/* cairo_dwrite_scaled_glyph_init helper function bodies */ cairo_int_status_t _cairo_dwrite_scaled_font_init_glyph_metrics(cairo_dwrite_scaled_font_t *scaled_font, cairo_scaled_glyph_t *scaled_glyph) { UINT16 charIndex = (UINT16)_cairo_scaled_glyph_index (scaled_glyph); cairo_dwrite_font_face_t *font_face = (cairo_dwrite_font_face_t*)scaled_font->base.font_face; cairo_text_extents_t extents; DWRITE_GLYPH_METRICS metrics; DWRITE_FONT_METRICS fontMetrics; font_face->dwriteface->GetMetrics(&fontMetrics); HRESULT hr = font_face->dwriteface->GetDesignGlyphMetrics(&charIndex, 1, &metrics); if (FAILED(hr)) { return CAIRO_INT_STATUS_UNSUPPORTED; } // TODO: Treat swap_xy. extents.width = (FLOAT)(metrics.advanceWidth - metrics.leftSideBearing - metrics.rightSideBearing) / fontMetrics.designUnitsPerEm; extents.height = (FLOAT)(metrics.advanceHeight - metrics.topSideBearing - metrics.bottomSideBearing) / fontMetrics.designUnitsPerEm; extents.x_advance = (FLOAT)metrics.advanceWidth / fontMetrics.designUnitsPerEm; extents.x_bearing = (FLOAT)metrics.leftSideBearing / fontMetrics.designUnitsPerEm; extents.y_advance = 0.0; extents.y_bearing = (FLOAT)(metrics.topSideBearing - metrics.verticalOriginY) / fontMetrics.designUnitsPerEm; // We pad the extents here because GetDesignGlyphMetrics returns "ideal" metrics // for the glyph outline, without accounting for hinting/gridfitting/antialiasing, // and therefore it does not always cover all pixels that will actually be touched. if (scaled_font->base.options.antialias != CAIRO_ANTIALIAS_NONE && extents.width > 0 && extents.height > 0) { extents.width += scaled_font->mat_inverse.xx * 2; extents.x_bearing -= scaled_font->mat_inverse.xx; } _cairo_scaled_glyph_set_metrics (scaled_glyph, &scaled_font->base, &extents); return CAIRO_INT_STATUS_SUCCESS; }
static cairo_int_status_t _cairo_user_scaled_glyph_init (void *abstract_font, cairo_scaled_glyph_t *scaled_glyph, cairo_scaled_glyph_info_t info) { cairo_int_status_t status = CAIRO_STATUS_SUCCESS; cairo_user_scaled_font_t *scaled_font = abstract_font; cairo_surface_t *meta_surface = scaled_glyph->meta_surface; if (!scaled_glyph->meta_surface) { cairo_user_font_face_t *face = (cairo_user_font_face_t *) scaled_font->base.font_face; cairo_text_extents_t extents = scaled_font->default_glyph_extents; cairo_t *cr; cr = _cairo_user_scaled_font_create_meta_context (scaled_font); if (face->scaled_font_methods.render_glyph) status = face->scaled_font_methods.render_glyph ((cairo_scaled_font_t *)scaled_font, _cairo_scaled_glyph_index(scaled_glyph), cr, &extents); else status = CAIRO_STATUS_USER_FONT_ERROR; if (status == CAIRO_STATUS_SUCCESS) status = cairo_status (cr); meta_surface = cairo_surface_reference (cairo_get_target (cr)); cairo_destroy (cr); if (status) { cairo_surface_destroy (meta_surface); return status; } _cairo_scaled_glyph_set_meta_surface (scaled_glyph, &scaled_font->base, meta_surface); /* set metrics */ if (extents.width == 0.) { /* Compute extents.x/y/width/height from meta_surface, in font space */ cairo_box_t bbox; double x1, y1, x2, y2; double x_scale, y_scale; cairo_surface_t *null_surface; cairo_surface_t *analysis_surface; null_surface = _cairo_null_surface_create (cairo_surface_get_content (meta_surface)); analysis_surface = _cairo_analysis_surface_create (null_surface, -1, -1); cairo_surface_destroy (null_surface); _cairo_analysis_surface_set_ctm (analysis_surface, &scaled_font->extent_scale); status = _cairo_meta_surface_replay (meta_surface, analysis_surface); _cairo_analysis_surface_get_bounding_box (analysis_surface, &bbox); cairo_surface_destroy (analysis_surface); if (status) return status; _cairo_box_to_doubles (&bbox, &x1, &y1, &x2, &y2); x_scale = scaled_font->extent_x_scale; y_scale = scaled_font->extent_y_scale; extents.x_bearing = x1 * x_scale; extents.y_bearing = y1 * y_scale; extents.width = (x2 - x1) * x_scale; extents.height = (y2 - y1) * y_scale; } if (scaled_font->base.options.hint_metrics != CAIRO_HINT_METRICS_OFF) { extents.x_advance = _cairo_lround (extents.x_advance / scaled_font->snap_x_scale) * scaled_font->snap_x_scale; extents.y_advance = _cairo_lround (extents.y_advance / scaled_font->snap_y_scale) * scaled_font->snap_y_scale; } _cairo_scaled_glyph_set_metrics (scaled_glyph, &scaled_font->base, &extents); } if (info & CAIRO_SCALED_GLYPH_INFO_SURFACE) { cairo_surface_t *surface; cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_format_t format; int width, height; /* TODO * extend the glyph cache to support argb glyphs. * need to figure out the semantics and interaction with subpixel * rendering first. */ width = _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.x) - _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x); height = _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.y) - _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y); switch (scaled_font->base.options.antialias) { default: case CAIRO_ANTIALIAS_DEFAULT: case CAIRO_ANTIALIAS_GRAY: format = CAIRO_FORMAT_A8; break; case CAIRO_ANTIALIAS_NONE: format = CAIRO_FORMAT_A1; break; case CAIRO_ANTIALIAS_SUBPIXEL: format = CAIRO_FORMAT_ARGB32; break; } surface = cairo_image_surface_create (format, width, height); cairo_surface_set_device_offset (surface, - _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x), - _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y)); status = _cairo_meta_surface_replay (meta_surface, surface); if (status) { cairo_surface_destroy(surface); return status; } _cairo_scaled_glyph_set_surface (scaled_glyph, &scaled_font->base, (cairo_image_surface_t *) surface); } if (info & CAIRO_SCALED_GLYPH_INFO_PATH) { cairo_path_fixed_t *path = _cairo_path_fixed_create (); if (!path) return _cairo_error (CAIRO_STATUS_NO_MEMORY); status = _cairo_meta_surface_get_path (meta_surface, path); if (status) { _cairo_path_fixed_destroy (path); return status; } _cairo_scaled_glyph_set_path (scaled_glyph, &scaled_font->base, path); } 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_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; }