static cairo_int_status_t _cairo_quartz_init_glyph_surface (cairo_quartz_scaled_font_t *font, cairo_scaled_glyph_t *scaled_glyph) { cairo_int_status_t status = CAIRO_STATUS_SUCCESS; cairo_quartz_font_face_t *font_face = _cairo_quartz_scaled_to_face(font); cairo_image_surface_t *surface = NULL; CGGlyph glyph = _cairo_quartz_scaled_glyph_index (scaled_glyph); int advance; CGRect bbox; double width, height; double emscale = CGFontGetUnitsPerEmPtr (font_face->cgFont); CGContextRef cgContext = NULL; CGAffineTransform textMatrix; CGRect glyphRect, glyphRectInt; CGPoint glyphOrigin; //fprintf (stderr, "scaled_glyph: %p surface: %p\n", scaled_glyph, scaled_glyph->surface); /* Create blank 2x2 image if we don't have this character. * Maybe we should draw a better missing-glyph slug or something, * but this is ok for now. */ if (glyph == INVALID_GLYPH) { surface = (cairo_image_surface_t*) cairo_image_surface_create (CAIRO_FORMAT_A8, 2, 2); status = cairo_surface_status ((cairo_surface_t *) surface); if (status) return status; _cairo_scaled_glyph_set_surface (scaled_glyph, &font->base, surface); return CAIRO_STATUS_SUCCESS; } if (!CGFontGetGlyphAdvancesPtr (font_face->cgFont, &glyph, 1, &advance) || !CGFontGetGlyphBBoxesPtr (font_face->cgFont, &glyph, 1, &bbox)) { return CAIRO_INT_STATUS_UNSUPPORTED; } /* scale(1,-1) * font->base.scale * scale(1,-1) */ textMatrix = CGAffineTransformMake (font->base.scale.xx, -font->base.scale.yx, -font->base.scale.xy, font->base.scale.yy, 0, -0); glyphRect = CGRectMake (bbox.origin.x / emscale, bbox.origin.y / emscale, bbox.size.width / emscale, bbox.size.height / emscale); glyphRect = CGRectApplyAffineTransform (glyphRect, textMatrix); /* Round the rectangle outwards, so that we don't have to deal * with non-integer-pixel origins or dimensions. */ glyphRectInt = CGRectIntegral (glyphRect); #if 0 fprintf (stderr, "glyphRect[o]: %f %f %f %f\n", glyphRect.origin.x, glyphRect.origin.y, glyphRect.size.width, glyphRect.size.height); fprintf (stderr, "glyphRectInt: %f %f %f %f\n", glyphRectInt.origin.x, glyphRectInt.origin.y, glyphRectInt.size.width, glyphRectInt.size.height); #endif glyphOrigin = glyphRectInt.origin; //textMatrix = CGAffineTransformConcat (textMatrix, CGAffineTransformInvert (ctm)); width = glyphRectInt.size.width; height = glyphRectInt.size.height; //fprintf (stderr, "glyphRect[n]: %f %f %f %f\n", glyphRect.origin.x, glyphRect.origin.y, glyphRect.size.width, glyphRect.size.height); surface = (cairo_image_surface_t*) cairo_image_surface_create (CAIRO_FORMAT_A8, width, height); if (surface->base.status) return surface->base.status; if (surface->width != 0 && surface->height != 0) { cgContext = CGBitmapContextCreate (surface->data, surface->width, surface->height, 8, surface->stride, NULL, kCGImageAlphaOnly); if (cgContext == NULL) { cairo_surface_destroy (&surface->base); return _cairo_error (CAIRO_STATUS_NO_MEMORY); } CGContextSetFont (cgContext, font_face->cgFont); CGContextSetFontSize (cgContext, 1.0); CGContextSetTextMatrix (cgContext, textMatrix); switch (font->base.options.antialias) { case CAIRO_ANTIALIAS_SUBPIXEL: case CAIRO_ANTIALIAS_BEST: CGContextSetShouldAntialias (cgContext, TRUE); CGContextSetShouldSmoothFonts (cgContext, TRUE); if (CGContextSetAllowsFontSmoothingPtr && !CGContextGetAllowsFontSmoothingPtr (cgContext)) CGContextSetAllowsFontSmoothingPtr (cgContext, TRUE); break; case CAIRO_ANTIALIAS_NONE: CGContextSetShouldAntialias (cgContext, FALSE); break; case CAIRO_ANTIALIAS_GRAY: case CAIRO_ANTIALIAS_GOOD: case CAIRO_ANTIALIAS_FAST: CGContextSetShouldAntialias (cgContext, TRUE); CGContextSetShouldSmoothFonts (cgContext, FALSE); break; case CAIRO_ANTIALIAS_DEFAULT: default: /* Don't do anything */ break; } CGContextSetAlpha (cgContext, 1.0); CGContextShowGlyphsAtPoint (cgContext, - glyphOrigin.x, - glyphOrigin.y, &glyph, 1); CGContextRelease (cgContext); } cairo_surface_set_device_offset (&surface->base, - glyphOrigin.x, height + glyphOrigin.y); _cairo_scaled_glyph_set_surface (scaled_glyph, &font->base, surface); return status; }
static cairo_int_status_t _cairo_quartz_init_glyph_metrics (cairo_quartz_scaled_font_t *font, cairo_scaled_glyph_t *scaled_glyph) { cairo_int_status_t status = CAIRO_STATUS_SUCCESS; cairo_quartz_font_face_t *font_face = _cairo_quartz_scaled_to_face(font); cairo_text_extents_t extents = {0, 0, 0, 0, 0, 0}; CGGlyph glyph = _cairo_quartz_scaled_glyph_index (scaled_glyph); int advance; CGRect bbox; double emscale = CGFontGetUnitsPerEmPtr (font_face->cgFont); double xmin, ymin, xmax, ymax; if (glyph == INVALID_GLYPH) goto FAIL; if (!CGFontGetGlyphAdvancesPtr (font_face->cgFont, &glyph, 1, &advance) || !CGFontGetGlyphBBoxesPtr (font_face->cgFont, &glyph, 1, &bbox)) goto FAIL; /* broken fonts like Al Bayan return incorrect bounds for some null characters, see https://bugzilla.mozilla.org/show_bug.cgi?id=534260 */ if (unlikely (bbox.origin.x == -32767 && bbox.origin.y == -32767 && bbox.size.width == 65534 && bbox.size.height == 65534)) { bbox.origin.x = bbox.origin.y = 0; bbox.size.width = bbox.size.height = 0; } bbox = CGRectMake (bbox.origin.x / emscale, bbox.origin.y / emscale, bbox.size.width / emscale, bbox.size.height / emscale); /* Should we want to always integer-align glyph extents, we can do so in this way */ #if 0 { CGAffineTransform textMatrix; textMatrix = CGAffineTransformMake (font->base.scale.xx, -font->base.scale.yx, -font->base.scale.xy, font->base.scale.yy, 0.0f, 0.0f); bbox = CGRectApplyAffineTransform (bbox, textMatrix); bbox = CGRectIntegral (bbox); bbox = CGRectApplyAffineTransform (bbox, CGAffineTransformInvert (textMatrix)); } #endif #if 0 fprintf (stderr, "[0x%04x] bbox: %f %f %f %f\n", glyph, bbox.origin.x / emscale, bbox.origin.y / emscale, bbox.size.width / emscale, bbox.size.height / emscale); #endif xmin = CGRectGetMinX(bbox); ymin = CGRectGetMinY(bbox); xmax = CGRectGetMaxX(bbox); ymax = CGRectGetMaxY(bbox); extents.x_bearing = xmin; extents.y_bearing = - ymax; extents.width = xmax - xmin; extents.height = ymax - ymin; extents.x_advance = (double) advance / emscale; extents.y_advance = 0.0; #if 0 fprintf (stderr, "[0x%04x] extents: bearings: %f %f dim: %f %f adv: %f\n\n", glyph, extents.x_bearing, extents.y_bearing, extents.width, extents.height, extents.x_advance); #endif FAIL: _cairo_scaled_glyph_set_metrics (scaled_glyph, &font->base, &extents); return status; }
static cairo_int_status_t _cairo_quartz_init_glyph_surface (cairo_quartz_scaled_font_t *font, cairo_scaled_glyph_t *scaled_glyph) { cairo_int_status_t status = CAIRO_STATUS_SUCCESS; cairo_quartz_font_face_t *font_face = _cairo_quartz_scaled_to_face(font); cairo_image_surface_t *surface = NULL; CGGlyph glyph = _cairo_quartz_scaled_glyph_index (scaled_glyph); int advance; CGRect bbox; double width, height; double xscale, yscale; double emscale = CGFontGetUnitsPerEmPtr (font_face->cgFont); CGColorSpaceRef gray; CGContextRef cgContext = NULL; CGAffineTransform textMatrix; CGRect glyphRect, glyphRectInt; CGPoint glyphOrigin; //fprintf (stderr, "scaled_glyph: %p surface: %p\n", scaled_glyph, scaled_glyph->surface); /* Create blank 2x2 image if we don't have this character. * Maybe we should draw a better missing-glyph slug or something, * but this is ok for now. */ if (glyph == INVALID_GLYPH) { surface = (cairo_image_surface_t*) cairo_image_surface_create (CAIRO_FORMAT_A8, 2, 2); status = cairo_surface_status ((cairo_surface_t *) surface); if (status) return status; _cairo_scaled_glyph_set_surface (scaled_glyph, &font->base, surface); return CAIRO_STATUS_SUCCESS; } if (!CGFontGetGlyphAdvancesPtr (font_face->cgFont, &glyph, 1, &advance) || !CGFontGetGlyphBBoxesPtr (font_face->cgFont, &glyph, 1, &bbox)) { return CAIRO_INT_STATUS_UNSUPPORTED; } status = _cairo_matrix_compute_basis_scale_factors (&font->base.scale, &xscale, &yscale, 1); if (status) return status; textMatrix = CGAffineTransformMake (font->base.scale.xx, -font->base.scale.yx, -font->base.scale.xy, font->base.scale.yy, 0.0f, 0.0f); glyphRect = CGRectMake (bbox.origin.x / emscale, bbox.origin.y / emscale, bbox.size.width / emscale, bbox.size.height / emscale); glyphRect = CGRectApplyAffineTransform (glyphRect, textMatrix); /* Round the rectangle outwards, so that we don't have to deal * with non-integer-pixel origins or dimensions. */ glyphRectInt = CGRectIntegral (glyphRect); #if 0 fprintf (stderr, "glyphRect[o]: %f %f %f %f\n", glyphRect.origin.x, glyphRect.origin.y, glyphRect.size.width, glyphRect.size.height); fprintf (stderr, "glyphRectInt: %f %f %f %f\n", glyphRectInt.origin.x, glyphRectInt.origin.y, glyphRectInt.size.width, glyphRectInt.size.height); #endif glyphOrigin = glyphRectInt.origin; //textMatrix = CGAffineTransformConcat (textMatrix, CGAffineTransformInvert (ctm)); width = glyphRectInt.size.width; height = glyphRectInt.size.height; //fprintf (stderr, "glyphRect[n]: %f %f %f %f\n", glyphRect.origin.x, glyphRect.origin.y, glyphRect.size.width, glyphRect.size.height); surface = (cairo_image_surface_t*) cairo_image_surface_create (CAIRO_FORMAT_A8, width, height); if (surface->base.status) return surface->base.status; gray = CGColorSpaceCreateDeviceGray (); cgContext = CGBitmapContextCreate (surface->data, surface->width, surface->height, 8, surface->stride, gray, kCGImageAlphaNone); CGColorSpaceRelease (gray); CGContextSetFont (cgContext, font_face->cgFont); CGContextSetFontSize (cgContext, 1.0); CGContextSetTextMatrix (cgContext, textMatrix); CGContextClearRect (cgContext, CGRectMake (0.0f, 0.0f, width, height)); if (font->base.options.antialias == CAIRO_ANTIALIAS_NONE) CGContextSetShouldAntialias (cgContext, false); CGContextSetRGBFillColor (cgContext, 1.0, 1.0, 1.0, 1.0); CGContextShowGlyphsAtPoint (cgContext, - glyphOrigin.x, - glyphOrigin.y, &glyph, 1); CGContextRelease (cgContext); cairo_surface_set_device_offset (&surface->base, - glyphOrigin.x, height + glyphOrigin.y); _cairo_scaled_glyph_set_surface (scaled_glyph, &font->base, surface); return status; }
static cairo_status_t _cairo_quartz_font_face_scaled_font_create (void *abstract_face, const cairo_matrix_t *font_matrix, const cairo_matrix_t *ctm, const cairo_font_options_t *options, cairo_scaled_font_t **font_out) { cairo_quartz_font_face_t *font_face = abstract_face; cairo_quartz_scaled_font_t *font = NULL; cairo_status_t status; cairo_font_extents_t fs_metrics; double ems; CGRect bbox; quartz_font_ensure_symbols(); if (!_cairo_quartz_font_symbols_present) return _cairo_error (CAIRO_STATUS_NO_MEMORY); font = malloc(sizeof(cairo_quartz_scaled_font_t)); if (font == NULL) return _cairo_error (CAIRO_STATUS_NO_MEMORY); memset (font, 0, sizeof(cairo_quartz_scaled_font_t)); status = _cairo_scaled_font_init (&font->base, &font_face->base, font_matrix, ctm, options, &_cairo_quartz_scaled_font_backend); if (status) goto FINISH; ems = CGFontGetUnitsPerEmPtr (font_face->cgFont); /* initialize metrics */ if (CGFontGetFontBBoxPtr && CGFontGetAscentPtr) { fs_metrics.ascent = (CGFontGetAscentPtr (font_face->cgFont) / ems); fs_metrics.descent = - (CGFontGetDescentPtr (font_face->cgFont) / ems); fs_metrics.height = fs_metrics.ascent + fs_metrics.descent + (CGFontGetLeadingPtr (font_face->cgFont) / ems); bbox = CGFontGetFontBBoxPtr (font_face->cgFont); fs_metrics.max_x_advance = CGRectGetMaxX(bbox) / ems; fs_metrics.max_y_advance = 0.0; } else { CGGlyph wGlyph; UniChar u; quartz_CGFontMetrics *m; m = CGFontGetHMetricsPtr (font_face->cgFont); /* On OX 10.4, GetHMetricsPtr sometimes returns NULL for unknown reasons */ if (!m) { status = _cairo_error(CAIRO_STATUS_NULL_POINTER); goto FINISH; } fs_metrics.ascent = (m->ascent / ems); fs_metrics.descent = - (m->descent / ems); fs_metrics.height = fs_metrics.ascent + fs_metrics.descent + (m->leading / ems); /* We kind of have to guess here; W's big, right? */ u = (UniChar) 'W'; CGFontGetGlyphsForUnicharsPtr (font_face->cgFont, &u, &wGlyph, 1); if (wGlyph && CGFontGetGlyphBBoxesPtr (font_face->cgFont, &wGlyph, 1, &bbox)) { fs_metrics.max_x_advance = CGRectGetMaxX(bbox) / ems; fs_metrics.max_y_advance = 0.0; } else { fs_metrics.max_x_advance = 0.0; fs_metrics.max_y_advance = 0.0; } } status = _cairo_scaled_font_set_metrics (&font->base, &fs_metrics); FINISH: if (status != CAIRO_STATUS_SUCCESS) { free (font); } else { *font_out = (cairo_scaled_font_t*) font; } return status; }
static cairo_int_status_t _cairo_quartz_init_glyph_metrics (cairo_quartz_scaled_font_t *font, cairo_scaled_glyph_t *scaled_glyph) { cairo_int_status_t status = CAIRO_STATUS_SUCCESS; cairo_quartz_font_face_t *font_face = _cairo_quartz_scaled_to_face(font); cairo_text_extents_t extents = {0, 0, 0, 0, 0, 0}; CGAffineTransform textMatrix; CGGlyph glyph = _cairo_quartz_scaled_glyph_index (scaled_glyph); int advance; CGRect bbox; double emscale = CGFontGetUnitsPerEmPtr (font_face->cgFont); double xscale, yscale; double xmin, ymin, xmax, ymax; if (glyph == INVALID_GLYPH) goto FAIL; if (!CGFontGetGlyphAdvancesPtr (font_face->cgFont, &glyph, 1, &advance) || !CGFontGetGlyphBBoxesPtr (font_face->cgFont, &glyph, 1, &bbox)) goto FAIL; status = _cairo_matrix_compute_basis_scale_factors (&font->base.scale, &xscale, &yscale, 1); if (status) goto FAIL; bbox = CGRectMake (bbox.origin.x / emscale, bbox.origin.y / emscale, bbox.size.width / emscale, bbox.size.height / emscale); /* Should we want to always integer-align glyph extents, we can do so in this way */ #if 0 { CGAffineTransform textMatrix; textMatrix = CGAffineTransformMake (font->base.scale.xx, -font->base.scale.yx, -font->base.scale.xy, font->base.scale.yy, 0.0f, 0.0f); bbox = CGRectApplyAffineTransform (bbox, textMatrix); bbox = CGRectIntegral (bbox); bbox = CGRectApplyAffineTransform (bbox, CGAffineTransformInvert (textMatrix)); } #endif #if 0 fprintf (stderr, "[0x%04x] bbox: %f %f %f %f\n", glyph, bbox.origin.x / emscale, bbox.origin.y / emscale, bbox.size.width / emscale, bbox.size.height / emscale); #endif xmin = CGRectGetMinX(bbox); ymin = CGRectGetMinY(bbox); xmax = CGRectGetMaxX(bbox); ymax = CGRectGetMaxY(bbox); extents.x_bearing = xmin; extents.y_bearing = - ymax; extents.width = xmax - xmin; extents.height = ymax - ymin; extents.x_advance = (double) advance / emscale; extents.y_advance = 0.0; #if 0 fprintf (stderr, "[0x%04x] extents: bearings: %f %f dim: %f %f adv: %f\n\n", glyph, extents.x_bearing, extents.y_bearing, extents.width, extents.height, extents.x_advance); #endif FAIL: _cairo_scaled_glyph_set_metrics (scaled_glyph, &font->base, &extents); return status; }