static PangoCairoFontHexBoxInfo * _pango_cairo_font_private_get_hex_box_info (PangoCairoFontPrivate *cf_priv) { static const char hexdigits[] = "0123456789ABCDEF"; char c[2] = {0, 0}; PangoFont *mini_font; PangoCairoFontHexBoxInfo *hbi; /* for metrics hinting */ double scale_x = 1., scale_x_inv = 1., scale_y = 1., scale_y_inv = 1.; gboolean is_hinted; int i; int rows; double pad; double width = 0; double height = 0; cairo_font_options_t *font_options; cairo_font_extents_t font_extents; double size, mini_size; PangoFontDescription *desc; cairo_scaled_font_t *scaled_font, *scaled_mini_font; PangoMatrix pango_ctm; cairo_matrix_t cairo_ctm; PangoGravity gravity; if (!cf_priv) return NULL; if (cf_priv->hbi) return cf_priv->hbi; scaled_font = _pango_cairo_font_private_get_scaled_font (cf_priv); if (G_UNLIKELY (scaled_font == NULL || cairo_scaled_font_status (scaled_font) != CAIRO_STATUS_SUCCESS)) return NULL; is_hinted = cf_priv->is_hinted; font_options = cairo_font_options_create (); desc = pango_font_describe_with_absolute_size ((PangoFont *)cf_priv->cfont); size = pango_font_description_get_size (desc) / (1.*PANGO_SCALE); gravity = pango_font_description_get_gravity (desc); cairo_scaled_font_get_ctm (scaled_font, &cairo_ctm); cairo_scaled_font_get_font_options (scaled_font, font_options); /* I started adding support for vertical hexboxes here, but it's too much * work. Easier to do with cairo user fonts and vertical writing mode * support in cairo. */ /*cairo_matrix_rotate (&cairo_ctm, pango_gravity_to_rotation (gravity));*/ pango_ctm.xx = cairo_ctm.xx; pango_ctm.yx = cairo_ctm.yx; pango_ctm.xy = cairo_ctm.xy; pango_ctm.yy = cairo_ctm.yy; pango_ctm.x0 = cairo_ctm.x0; pango_ctm.y0 = cairo_ctm.y0; if (is_hinted) { /* prepare for some hinting */ double x, y; x = 1.; y = 0.; cairo_matrix_transform_distance (&cairo_ctm, &x, &y); scale_x = sqrt (x*x + y*y); scale_x_inv = 1 / scale_x; x = 0.; y = 1.; cairo_matrix_transform_distance (&cairo_ctm, &x, &y); scale_y = sqrt (x*x + y*y); scale_y_inv = 1 / scale_y; } /* we hint to the nearest device units */ #define HINT(value, scale, scale_inv) (ceil ((value-1e-5) * scale) * scale_inv) #define HINT_X(value) HINT ((value), scale_x, scale_x_inv) #define HINT_Y(value) HINT ((value), scale_y, scale_y_inv) /* create mini_font description */ { PangoFontMap *fontmap; PangoContext *context; /* XXX this is racy. need a ref'ing getter... */ fontmap = pango_font_get_font_map ((PangoFont *)cf_priv->cfont); if (!fontmap) return NULL; fontmap = g_object_ref (fontmap); /* we inherit most font properties for the mini font. just * change family and size. means, you get bold hex digits * in the hexbox for a bold font. */ /* We should rotate the box, not glyphs */ pango_font_description_unset_fields (desc, PANGO_FONT_MASK_GRAVITY); pango_font_description_set_family_static (desc, "monospace"); rows = 2; mini_size = size / 2.2; if (is_hinted) { mini_size = HINT_Y (mini_size); if (mini_size < 6.0) { rows = 1; mini_size = MIN (MAX (size - 1, 0), 6.0); } } pango_font_description_set_absolute_size (desc, pango_units_from_double (mini_size)); /* load mini_font */ context = pango_font_map_create_context (fontmap); pango_context_set_matrix (context, &pango_ctm); pango_context_set_language (context, pango_script_get_sample_language (PANGO_SCRIPT_LATIN)); pango_cairo_context_set_font_options (context, font_options); mini_font = pango_font_map_load_font (fontmap, context, desc); g_object_unref (context); g_object_unref (fontmap); } pango_font_description_free (desc); cairo_font_options_destroy (font_options); scaled_mini_font = pango_cairo_font_get_scaled_font ((PangoCairoFont *) mini_font); for (i = 0 ; i < 16 ; i++) { cairo_text_extents_t extents; c[0] = hexdigits[i]; cairo_scaled_font_text_extents (scaled_mini_font, c, &extents); width = MAX (width, extents.width); height = MAX (height, extents.height); } cairo_scaled_font_extents (scaled_font, &font_extents); if (font_extents.ascent + font_extents.descent <= 0) { font_extents.ascent = PANGO_UNKNOWN_GLYPH_HEIGHT; font_extents.descent = 0; } pad = (font_extents.ascent + font_extents.descent) / 43; pad = MIN (pad, mini_size); hbi = g_slice_new (PangoCairoFontHexBoxInfo); hbi->font = (PangoCairoFont *) mini_font; hbi->rows = rows; hbi->digit_width = width; hbi->digit_height = height; hbi->pad_x = pad; hbi->pad_y = pad; if (is_hinted) { hbi->digit_width = HINT_X (hbi->digit_width); hbi->digit_height = HINT_Y (hbi->digit_height); hbi->pad_x = HINT_X (hbi->pad_x); hbi->pad_y = HINT_Y (hbi->pad_y); } hbi->line_width = MIN (hbi->pad_x, hbi->pad_y); hbi->box_height = 3 * hbi->pad_y + rows * (hbi->pad_y + hbi->digit_height); if (rows == 1 || hbi->box_height <= font_extents.ascent) { hbi->box_descent = 2 * hbi->pad_y; } else if (hbi->box_height <= font_extents.ascent + font_extents.descent - 2 * hbi->pad_y) { hbi->box_descent = 2 * hbi->pad_y + hbi->box_height - font_extents.ascent; } else { hbi->box_descent = font_extents.descent * hbi->box_height / (font_extents.ascent + font_extents.descent); } if (is_hinted) { hbi->box_descent = HINT_Y (hbi->box_descent); } cf_priv->hbi = hbi; return hbi; }
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); }
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); }
static VALUE rg_font_map(VALUE self) { return GOBJ2RVAL(pango_font_get_font_map(_SELF(self))); }