PangoFontMetrics * _pango_cairo_font_get_metrics (PangoFont *font, PangoLanguage *language) { PangoCairoFont *cfont = (PangoCairoFont *) font; PangoCairoFontPrivate *cf_priv = PANGO_CAIRO_FONT_PRIVATE (font); PangoCairoFontMetricsInfo *info = NULL; /* Quiet gcc */ GSList *tmp_list; const char *sample_str = pango_language_get_sample_string (language); tmp_list = cf_priv->metrics_by_lang; while (tmp_list) { info = tmp_list->data; if (info->sample_str == sample_str) /* We _don't_ need strcmp */ break; tmp_list = tmp_list->next; } if (!tmp_list) { PangoFontMap *fontmap; PangoContext *context; cairo_font_options_t *font_options; int height, shift; /* XXX this is racy. need a ref'ing getter... */ fontmap = pango_font_get_font_map (font); if (!fontmap) return pango_font_metrics_new (); fontmap = g_object_ref (fontmap); info = g_slice_new0 (PangoCairoFontMetricsInfo); cf_priv->metrics_by_lang = g_slist_prepend (cf_priv->metrics_by_lang, info); info->sample_str = sample_str; context = pango_font_map_create_context (fontmap); pango_context_set_language (context, language); font_options = cairo_font_options_create (); cairo_scaled_font_get_font_options (_pango_cairo_font_private_get_scaled_font (cf_priv), font_options); pango_cairo_context_set_font_options (context, font_options); cairo_font_options_destroy (font_options); info->metrics = (* PANGO_CAIRO_FONT_GET_IFACE (font)->create_metrics_for_context) (cfont, context); /* We may actually reuse ascent/descent we got from cairo here. that's * in cf_priv->font_extents. */ height = info->metrics->ascent + info->metrics->descent; switch (cf_priv->gravity) { default: case PANGO_GRAVITY_AUTO: case PANGO_GRAVITY_SOUTH: break; case PANGO_GRAVITY_NORTH: info->metrics->ascent = info->metrics->descent; break; case PANGO_GRAVITY_EAST: case PANGO_GRAVITY_WEST: { int ascent = height / 2; if (cf_priv->is_hinted) ascent = PANGO_UNITS_ROUND (ascent); info->metrics->ascent = ascent; } } shift = (height - info->metrics->ascent) - info->metrics->descent; info->metrics->descent += shift; info->metrics->underline_position -= shift; info->metrics->strikethrough_position -= shift; info->metrics->ascent = height - info->metrics->descent; g_object_unref (context); g_object_unref (fontmap); } return pango_font_metrics_ref (info->metrics); }
cairo_scaled_font_t * _pango_cairo_font_private_get_scaled_font (PangoCairoFontPrivate *cf_priv) { cairo_font_face_t *font_face; if (G_LIKELY (cf_priv->scaled_font)) return cf_priv->scaled_font; /* need to create it */ if (G_UNLIKELY (cf_priv->data == NULL)) { /* we have tried to create and failed before */ return NULL; } font_face = (* PANGO_CAIRO_FONT_GET_IFACE (cf_priv->cfont)->create_font_face) (cf_priv->cfont); if (G_UNLIKELY (font_face == NULL)) goto done; cf_priv->scaled_font = cairo_scaled_font_create (font_face, &cf_priv->data->font_matrix, &cf_priv->data->ctm, cf_priv->data->options); cairo_font_face_destroy (font_face); done: if (G_UNLIKELY (cf_priv->scaled_font == NULL || cairo_scaled_font_status (cf_priv->scaled_font) != CAIRO_STATUS_SUCCESS)) { cairo_scaled_font_t *scaled_font = cf_priv->scaled_font; PangoFont *font = PANGO_FONT (cf_priv->cfont); static GQuark warned_quark = 0; if (!warned_quark) warned_quark = g_quark_from_static_string ("pangocairo-scaledfont-warned"); if (!g_object_get_qdata (G_OBJECT (font), warned_quark)) { PangoFontDescription *desc; char *s; desc = pango_font_describe (font); s = pango_font_description_to_string (desc); pango_font_description_free (desc); g_warning ("failed to create cairo %s, expect ugly output. the offending font is '%s'", font_face ? "scaled font" : "font face", s); if (!font_face) g_warning ("font_face is NULL"); else g_warning ("font_face status is: %s", cairo_status_to_string (cairo_font_face_status (font_face))); if (!scaled_font) g_warning ("scaled_font is NULL"); else g_warning ("scaled_font status is: %s", cairo_status_to_string (cairo_scaled_font_status (scaled_font))); g_free (s); g_object_set_qdata_full (G_OBJECT (font), warned_quark, GINT_TO_POINTER (1), NULL); } } _pango_cairo_font_private_scaled_font_data_destroy (cf_priv->data); cf_priv->data = NULL; return cf_priv->scaled_font; }
PangoFontMetrics * _pango_cairo_font_get_metrics (PangoFont *font, PangoLanguage *language) { PangoCairoFont *cfont = (PangoCairoFont *) font; PangoCairoFontPrivate *cf_priv = PANGO_CAIRO_FONT_PRIVATE (font); PangoCairoFontMetricsInfo *info = NULL; /* Quiet gcc */ GSList *tmp_list; const char *sample_str = pango_language_get_sample_string (language); tmp_list = cf_priv->metrics_by_lang; while (tmp_list) { info = tmp_list->data; if (info->sample_str == sample_str) /* We _don't_ need strcmp */ break; tmp_list = tmp_list->next; } if (!tmp_list) { PangoFontMap *fontmap; PangoContext *context; cairo_font_options_t *font_options; PangoLayout *layout; PangoRectangle extents; PangoFontDescription *desc; cairo_scaled_font_t *scaled_font; cairo_matrix_t cairo_matrix; PangoMatrix pango_matrix; PangoMatrix identity = PANGO_MATRIX_INIT; int height, shift; /* XXX this is racy. need a ref'ing getter... */ fontmap = pango_font_get_font_map (font); if (!fontmap) return pango_font_metrics_new (); fontmap = g_object_ref (fontmap); info = g_slice_new0 (PangoCairoFontMetricsInfo); cf_priv->metrics_by_lang = g_slist_prepend (cf_priv->metrics_by_lang, info); info->sample_str = sample_str; scaled_font = _pango_cairo_font_private_get_scaled_font (cf_priv); context = pango_font_map_create_context (fontmap); pango_context_set_language (context, language); font_options = cairo_font_options_create (); cairo_scaled_font_get_font_options (scaled_font, font_options); pango_cairo_context_set_font_options (context, font_options); cairo_font_options_destroy (font_options); info->metrics = (* PANGO_CAIRO_FONT_GET_IFACE (font)->create_base_metrics_for_context) (cfont, context); /* We now need to adjust the base metrics for ctm */ cairo_scaled_font_get_ctm (scaled_font, &cairo_matrix); pango_matrix.xx = cairo_matrix.xx; pango_matrix.yx = cairo_matrix.yx; pango_matrix.xy = cairo_matrix.xy; pango_matrix.yy = cairo_matrix.yy; pango_matrix.x0 = 0; pango_matrix.y0 = 0; if (G_UNLIKELY (0 != memcmp (&identity, &pango_matrix, 4 * sizeof (double)))) { double xscale = pango_matrix_get_font_scale_factor (&pango_matrix); if (xscale) xscale = 1 / xscale; info->metrics->ascent *= xscale; info->metrics->descent *= xscale; info->metrics->underline_position *= xscale; info->metrics->underline_thickness *= xscale; info->metrics->strikethrough_position *= xscale; info->metrics->strikethrough_thickness *= xscale; } /* Set the matrix on the context so we don't have to adjust the derived * metrics. */ pango_context_set_matrix (context, &pango_matrix); /* Update approximate_*_width now */ layout = pango_layout_new (context); desc = pango_font_describe_with_absolute_size (font); pango_layout_set_font_description (layout, desc); pango_font_description_free (desc); pango_layout_set_text (layout, sample_str, -1); pango_layout_get_extents (layout, NULL, &extents); info->metrics->approximate_char_width = extents.width / pango_utf8_strwidth (sample_str); pango_layout_set_text (layout, "0123456789", -1); info->metrics->approximate_digit_width = max_glyph_width (layout); g_object_unref (layout); /* We may actually reuse ascent/descent we got from cairo here. that's * in cf_priv->font_extents. */ height = info->metrics->ascent + info->metrics->descent; switch (cf_priv->gravity) { default: case PANGO_GRAVITY_AUTO: case PANGO_GRAVITY_SOUTH: break; case PANGO_GRAVITY_NORTH: info->metrics->ascent = info->metrics->descent; break; case PANGO_GRAVITY_EAST: case PANGO_GRAVITY_WEST: { int ascent = height / 2; if (cf_priv->is_hinted) ascent = PANGO_UNITS_ROUND (ascent); info->metrics->ascent = ascent; } } shift = (height - info->metrics->ascent) - info->metrics->descent; info->metrics->descent += shift; info->metrics->underline_position -= shift; info->metrics->strikethrough_position -= shift; info->metrics->ascent = height - info->metrics->descent; g_object_unref (context); g_object_unref (fontmap); } return pango_font_metrics_ref (info->metrics); }