/* Pango * pangofc-font.c: Shared interfaces for fontconfig-based backends * * Copyright (C) 2003 Red Hat Software * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ /** * SECTION:pangofc-font * @short_description:Base font class for Fontconfig-based backends * @title:PangoFcFont * @see_also: * #PangoFcFontMap The base class for font maps; creating a new * Fontconfig-based backend involves deriving from both * #PangoFcFontMap and #PangoFcFont. * * #PangoFcFont is a base class for font implementation using the * Fontconfig and FreeType libraries. It is used in the * Xft and * FreeType * backends shipped with Pango, but can also be used when creating * new backends. Any backend deriving from this base class will * take advantage of the wide range of shapers implemented using * FreeType that come with Pango. */ #include "config.h" #include "pangofc-font-private.h" #include "pangofc-fontmap.h" #include "pangofc-private.h" #include "pango-engine.h" #include "pango-layout.h" #include "pango-impl-utils.h" #include enum { PROP_0, PROP_PATTERN, PROP_FONTMAP }; typedef struct _PangoFcFontPrivate PangoFcFontPrivate; struct _PangoFcFontPrivate { PangoFcDecoder *decoder; PangoFcFontKey *key; }; static gboolean pango_fc_font_real_has_char (PangoFcFont *font, gunichar wc); static guint pango_fc_font_real_get_glyph (PangoFcFont *font, gunichar wc); static void pango_fc_font_finalize (GObject *object); static void pango_fc_font_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); static void pango_fc_font_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); static PangoEngineShape * pango_fc_font_find_shaper (PangoFont *font, PangoLanguage *language, guint32 ch); static PangoCoverage * pango_fc_font_get_coverage (PangoFont *font, PangoLanguage *language); static PangoFontMetrics * pango_fc_font_get_metrics (PangoFont *font, PangoLanguage *language); static PangoFontMap * pango_fc_font_get_font_map (PangoFont *font); static PangoFontDescription *pango_fc_font_describe (PangoFont *font); static PangoFontDescription *pango_fc_font_describe_absolute (PangoFont *font); static void pango_fc_font_get_features (PangoFont *font, hb_feature_t *features, guint len, guint *num_features); static hb_font_t * pango_fc_font_create_hb_font (PangoFont *font); #define PANGO_FC_FONT_LOCK_FACE(font) (PANGO_FC_FONT_GET_CLASS (font)->lock_face (font)) #define PANGO_FC_FONT_UNLOCK_FACE(font) (PANGO_FC_FONT_GET_CLASS (font)->unlock_face (font)) G_DEFINE_ABSTRACT_TYPE_WITH_CODE (PangoFcFont, pango_fc_font, PANGO_TYPE_FONT, G_ADD_PRIVATE (PangoFcFont)) static void pango_fc_font_class_init (PangoFcFontClass *class) { GObjectClass *object_class = G_OBJECT_CLASS (class); PangoFontClass *font_class = PANGO_FONT_CLASS (class); class->has_char = pango_fc_font_real_has_char; class->get_glyph = pango_fc_font_real_get_glyph; class->get_unknown_glyph = NULL; object_class->finalize = pango_fc_font_finalize; object_class->set_property = pango_fc_font_set_property; object_class->get_property = pango_fc_font_get_property; font_class->describe = pango_fc_font_describe; font_class->describe_absolute = pango_fc_font_describe_absolute; font_class->find_shaper = pango_fc_font_find_shaper; font_class->get_coverage = pango_fc_font_get_coverage; font_class->get_metrics = pango_fc_font_get_metrics; font_class->get_font_map = pango_fc_font_get_font_map; font_class->get_features = pango_fc_font_get_features; font_class->create_hb_font = pango_fc_font_create_hb_font; font_class->get_features = pango_fc_font_get_features; g_object_class_install_property (object_class, PROP_PATTERN, g_param_spec_pointer ("pattern", "Pattern", "The fontconfig pattern for this font", G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_FONTMAP, g_param_spec_object ("fontmap", "Font Map", "The PangoFc font map this font is associated with (Since: 1.26)", PANGO_TYPE_FC_FONT_MAP, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); } static void pango_fc_font_init (PangoFcFont *fcfont) { fcfont->priv = pango_fc_font_get_instance_private (fcfont); } static void free_metrics_info (PangoFcMetricsInfo *info) { pango_font_metrics_unref (info->metrics); g_slice_free (PangoFcMetricsInfo, info); } static void pango_fc_font_finalize (GObject *object) { PangoFcFont *fcfont = PANGO_FC_FONT (object); PangoFcFontPrivate *priv = fcfont->priv; PangoFcFontMap *fontmap; g_slist_foreach (fcfont->metrics_by_lang, (GFunc)free_metrics_info, NULL); g_slist_free (fcfont->metrics_by_lang); fontmap = g_weak_ref_get ((GWeakRef *) &fcfont->fontmap); if (fontmap) { _pango_fc_font_map_remove (PANGO_FC_FONT_MAP (fcfont->fontmap), fcfont); g_weak_ref_clear ((GWeakRef *) &fcfont->fontmap); g_object_unref (fontmap); } FcPatternDestroy (fcfont->font_pattern); pango_font_description_free (fcfont->description); if (priv->decoder) _pango_fc_font_set_decoder (fcfont, NULL); G_OBJECT_CLASS (pango_fc_font_parent_class)->finalize (object); } static gboolean pattern_is_hinted (FcPattern *pattern) { FcBool hinting; if (FcPatternGetBool (pattern, FC_HINTING, 0, &hinting) != FcResultMatch) hinting = FcTrue; return hinting; } static gboolean pattern_is_transformed (FcPattern *pattern) { FcMatrix *fc_matrix; if (FcPatternGetMatrix (pattern, FC_MATRIX, 0, &fc_matrix) == FcResultMatch) { FT_Matrix ft_matrix; ft_matrix.xx = 0x10000L * fc_matrix->xx; ft_matrix.yy = 0x10000L * fc_matrix->yy; ft_matrix.xy = 0x10000L * fc_matrix->xy; ft_matrix.yx = 0x10000L * fc_matrix->yx; return ((ft_matrix.xy | ft_matrix.yx) != 0 || ft_matrix.xx != 0x10000L || ft_matrix.yy != 0x10000L); } else return FALSE; } static void pango_fc_font_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { PangoFcFont *fcfont = PANGO_FC_FONT (object); switch (prop_id) { case PROP_PATTERN: { FcPattern *pattern = g_value_get_pointer (value); g_return_if_fail (pattern != NULL); g_return_if_fail (fcfont->font_pattern == NULL); FcPatternReference (pattern); fcfont->font_pattern = pattern; fcfont->description = pango_fc_font_description_from_pattern (pattern, TRUE); fcfont->is_hinted = pattern_is_hinted (pattern); fcfont->is_transformed = pattern_is_transformed (pattern); } goto set_decoder; case PROP_FONTMAP: { PangoFcFontMap *fcfontmap = PANGO_FC_FONT_MAP (g_value_get_object (value)); g_return_if_fail (fcfont->fontmap == NULL); g_weak_ref_set ((GWeakRef *) &fcfont->fontmap, fcfontmap); } goto set_decoder; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); return; } set_decoder: /* set decoder if both pattern and fontmap are set now */ if (fcfont->font_pattern && fcfont->fontmap) _pango_fc_font_set_decoder (fcfont, pango_fc_font_map_find_decoder ((PangoFcFontMap *) fcfont->fontmap, fcfont->font_pattern)); } static void pango_fc_font_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { switch (prop_id) { case PROP_PATTERN: { PangoFcFont *fcfont = PANGO_FC_FONT (object); g_value_set_pointer (value, fcfont->font_pattern); } break; case PROP_FONTMAP: { PangoFcFont *fcfont = PANGO_FC_FONT (object); PangoFontMap *fontmap = g_weak_ref_get ((GWeakRef *) &fcfont->fontmap); g_value_take_object (value, fontmap); } break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static PangoFontDescription * pango_fc_font_describe (PangoFont *font) { PangoFcFont *fcfont = (PangoFcFont *)font; return pango_font_description_copy (fcfont->description); } static PangoFontDescription * pango_fc_font_describe_absolute (PangoFont *font) { PangoFcFont *fcfont = (PangoFcFont *)font; PangoFontDescription *desc = pango_font_description_copy (fcfont->description); double size; if (FcPatternGetDouble (fcfont->font_pattern, FC_PIXEL_SIZE, 0, &size) == FcResultMatch) pango_font_description_set_absolute_size (desc, size * PANGO_SCALE); return desc; } /* Wrap shaper in PangoEngineShape to pass it through old API, * from times when there were modules and engines. */ typedef PangoEngineShape PangoFcShapeEngine; typedef PangoEngineShapeClass PangoFcShapeEngineClass; static GType pango_fc_shape_engine_get_type (void) G_GNUC_CONST; G_DEFINE_TYPE (PangoFcShapeEngine, pango_fc_shape_engine, PANGO_TYPE_ENGINE_SHAPE); static void _pango_fc_shape_engine_shape (PangoEngineShape *engine G_GNUC_UNUSED, PangoFont *font, const char *item_text, unsigned int item_length, const PangoAnalysis *analysis, PangoGlyphString *glyphs, const char *paragraph_text, unsigned int paragraph_length) { _pango_fc_shape (font, item_text, item_length, analysis, glyphs, paragraph_text, paragraph_length); } static void pango_fc_shape_engine_class_init (PangoEngineShapeClass *class) { class->script_shape = _pango_fc_shape_engine_shape; } static void pango_fc_shape_engine_init (PangoEngineShape *object) { } static PangoEngineShape * pango_fc_font_find_shaper (PangoFont *font G_GNUC_UNUSED, PangoLanguage *language, guint32 ch) { static PangoEngineShape *shaper; if (g_once_init_enter (&shaper)) g_once_init_leave (&shaper, g_object_new (pango_fc_shape_engine_get_type(), NULL)); return shaper; } static PangoCoverage * pango_fc_font_get_coverage (PangoFont *font, PangoLanguage *language G_GNUC_UNUSED) { PangoFcFont *fcfont = (PangoFcFont *)font; PangoFcFontPrivate *priv = fcfont->priv; FcCharSet *charset; PangoFcFontMap *fontmap; PangoCoverage *coverage; if (priv->decoder) { charset = pango_fc_decoder_get_charset (priv->decoder, fcfont); return _pango_fc_font_map_fc_to_coverage (charset); } fontmap = g_weak_ref_get ((GWeakRef *) &fcfont->fontmap); if (!fontmap) return pango_coverage_new (); coverage = _pango_fc_font_map_get_coverage (fontmap, fcfont); g_object_unref (fontmap); return coverage; } /* For Xft, it would be slightly more efficient to simply to * call Xft, and also more robust against changes in Xft. * But for now, we simply use the same code for all backends. * * The code in this function is partly based on code from Xft, * Copyright 2000 Keith Packard */ static void get_face_metrics (PangoFcFont *fcfont, PangoFontMetrics *metrics) { hb_font_t *hb_font = pango_font_get_hb_font (PANGO_FONT (fcfont)); hb_font_extents_t extents; FcMatrix *fc_matrix; gboolean have_transform = FALSE; hb_font_get_extents_for_direction (hb_font, HB_DIRECTION_LTR, &extents); if (FcPatternGetMatrix (fcfont->font_pattern, FC_MATRIX, 0, &fc_matrix) == FcResultMatch) { have_transform = (fc_matrix->xx != 1 || fc_matrix->xy != 0 || fc_matrix->yx != 0 || fc_matrix->yy != 1); } if (have_transform) { metrics->descent = - extents.descender * fc_matrix->yy; metrics->ascent = extents.ascender * fc_matrix->yy; metrics->height = (extents.ascender - extents.descender + extents.line_gap) * fc_matrix->yy; } else { metrics->descent = - extents.descender; metrics->ascent = extents.ascender; metrics->height = extents.ascender - extents.descender + extents.line_gap; } metrics->underline_thickness = PANGO_SCALE; metrics->underline_position = - PANGO_SCALE; metrics->strikethrough_thickness = PANGO_SCALE; metrics->strikethrough_position = metrics->ascent / 2; /* FIXME: use the right hb version */ #if HB_VERSION_ATLEAST(2,5,4) hb_position_t position; if (hb_ot_metrics_get_position (hb_font, HB_OT_METRICS_UNDERLINE_SIZE, &position)) metrics->underline_thickness = position; if (hb_ot_metrics_get_position (hb_font, HB_OT_METRICS_UNDERLINE_OFFSET, &position)) metrics->underline_position = position; if (hb_ot_metrics_get_position (hb_font, HB_OT_METRICS_STRIKEOUT_SIZE, &position)) metrics->strikethrough_thickness = position; if (hb_ot_metrics_get_position (hb_font, HB_OT_METRICS_STRIKEOUT_OFFSET, &position)) metrics->strikethrough_position = position; #endif } PangoFontMetrics * pango_fc_font_create_base_metrics_for_context (PangoFcFont *fcfont, PangoContext *context) { PangoFontMetrics *metrics; metrics = pango_font_metrics_new (); get_face_metrics (fcfont, metrics); return metrics; } static int max_glyph_width (PangoLayout *layout) { int max_width = 0; GSList *l, *r; for (l = pango_layout_get_lines_readonly (layout); l; l = l->next) { PangoLayoutLine *line = l->data; for (r = line->runs; r; r = r->next) { PangoGlyphString *glyphs = ((PangoGlyphItem *)r->data)->glyphs; int i; for (i = 0; i < glyphs->num_glyphs; i++) if (glyphs->glyphs[i].geometry.width > max_width) max_width = glyphs->glyphs[i].geometry.width; } } return max_width; } static PangoFontMetrics * pango_fc_font_get_metrics (PangoFont *font, PangoLanguage *language) { PangoFcFont *fcfont = PANGO_FC_FONT (font); PangoFcMetricsInfo *info = NULL; /* Quiet gcc */ GSList *tmp_list; static int in_get_metrics; const char *sample_str = pango_language_get_sample_string (language); tmp_list = fcfont->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; fontmap = g_weak_ref_get ((GWeakRef *) &fcfont->fontmap); if (!fontmap) return pango_font_metrics_new (); info = g_slice_new0 (PangoFcMetricsInfo); /* Note: we need to add info to the list before calling * into PangoLayout below, to prevent recursion */ fcfont->metrics_by_lang = g_slist_prepend (fcfont->metrics_by_lang, info); info->sample_str = sample_str; context = pango_font_map_create_context (fontmap); pango_context_set_language (context, language); info->metrics = pango_fc_font_create_base_metrics_for_context (fcfont, context); if (!in_get_metrics) { in_get_metrics = 1; /* Compute derived metrics */ PangoLayout *layout; PangoRectangle extents; const char *sample_str = pango_language_get_sample_string (language); PangoFontDescription *desc = pango_font_describe_with_absolute_size (font); gulong sample_str_width; layout = pango_layout_new (context); 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); sample_str_width = pango_utf8_strwidth (sample_str); g_assert (sample_str_width > 0); info->metrics->approximate_char_width = extents.width / sample_str_width; pango_layout_set_text (layout, "0123456789", -1); info->metrics->approximate_digit_width = max_glyph_width (layout); g_object_unref (layout); in_get_metrics = 0; } g_object_unref (context); g_object_unref (fontmap); } return pango_font_metrics_ref (info->metrics); } static PangoFontMap * pango_fc_font_get_font_map (PangoFont *font) { PangoFcFont *fcfont = PANGO_FC_FONT (font); /* MT-unsafe. Oh well... The API is unsafe. */ return fcfont->fontmap; } static gboolean pango_fc_font_real_has_char (PangoFcFont *font, gunichar wc) { FcCharSet *charset; if (FcPatternGetCharSet (font->font_pattern, FC_CHARSET, 0, &charset) != FcResultMatch) return FALSE; return FcCharSetHasChar (charset, wc); } static guint pango_fc_font_real_get_glyph (PangoFcFont *font, gunichar wc) { hb_font_t *hb_font = pango_font_get_hb_font (PANGO_FONT (font)); hb_codepoint_t glyph = PANGO_GET_UNKNOWN_GLYPH (wc); hb_font_get_nominal_glyph (hb_font, wc, &glyph); return glyph; } /** * pango_fc_font_lock_face: * @font: a #PangoFcFont. * * Gets the FreeType FT_Face associated with a font, * This face will be kept around until you call * pango_fc_font_unlock_face(). * * Return value: the FreeType FT_Face associated with @font. * * Since: 1.4 * Deprecated: 1.44: Use pango_font_get_hb_font() instead **/ FT_Face pango_fc_font_lock_face (PangoFcFont *font) { g_return_val_if_fail (PANGO_IS_FC_FONT (font), NULL); return PANGO_FC_FONT_LOCK_FACE (font); } /** * pango_fc_font_unlock_face: * @font: a #PangoFcFont. * * Releases a font previously obtained with * pango_fc_font_lock_face(). * * Since: 1.4 * Deprecated: 1.44: Use pango_font_get_hb_font() instead **/ void pango_fc_font_unlock_face (PangoFcFont *font) { g_return_if_fail (PANGO_IS_FC_FONT (font)); PANGO_FC_FONT_UNLOCK_FACE (font); } /** * pango_fc_font_has_char: * @font: a #PangoFcFont * @wc: Unicode codepoint to look up * * Determines whether @font has a glyph for the codepoint @wc. * * Return value: %TRUE if @font has the requested codepoint. * * Since: 1.4 **/ gboolean pango_fc_font_has_char (PangoFcFont *font, gunichar wc) { PangoFcFontPrivate *priv = font->priv; FcCharSet *charset; g_return_val_if_fail (PANGO_IS_FC_FONT (font), FALSE); if (priv->decoder) { charset = pango_fc_decoder_get_charset (priv->decoder, font); return FcCharSetHasChar (charset, wc); } return PANGO_FC_FONT_GET_CLASS (font)->has_char (font, wc); } /** * pango_fc_font_get_glyph: * @font: a #PangoFcFont * @wc: Unicode character to look up * * Gets the glyph index for a given Unicode character * for @font. If you only want to determine * whether the font has the glyph, use pango_fc_font_has_char(). * * Return value: the glyph index, or 0, if the Unicode * character doesn't exist in the font. * * Since: 1.4 **/ PangoGlyph pango_fc_font_get_glyph (PangoFcFont *font, gunichar wc) { PangoFcFontPrivate *priv = font->priv; /* Replace NBSP with a normal space; it should be invariant that * they shape the same other than breaking properties. */ if (wc == 0xA0) wc = 0x20; if (priv->decoder) return pango_fc_decoder_get_glyph (priv->decoder, font, wc); return PANGO_FC_FONT_GET_CLASS (font)->get_glyph (font, wc); } /** * pango_fc_font_get_unknown_glyph: * @font: a #PangoFcFont * @wc: the Unicode character for which a glyph is needed. * * Returns the index of a glyph suitable for drawing @wc as an * unknown character. * * Use PANGO_GET_UNKNOWN_GLYPH() instead. * * Return value: a glyph index into @font. * * Since: 1.4 **/ PangoGlyph pango_fc_font_get_unknown_glyph (PangoFcFont *font, gunichar wc) { if (font && PANGO_FC_FONT_GET_CLASS (font)->get_unknown_glyph) return PANGO_FC_FONT_GET_CLASS (font)->get_unknown_glyph (font, wc); return PANGO_GET_UNKNOWN_GLYPH (wc); } void _pango_fc_font_shutdown (PangoFcFont *font) { g_return_if_fail (PANGO_IS_FC_FONT (font)); if (PANGO_FC_FONT_GET_CLASS (font)->shutdown) PANGO_FC_FONT_GET_CLASS (font)->shutdown (font); } /** * pango_fc_font_kern_glyphs: * @font: a #PangoFcFont * @glyphs: a #PangoGlyphString * * This function used to adjust each adjacent pair of glyphs * in @glyphs according to kerning information in @font. * * Since 1.44, it does nothing. * * * Since: 1.4 * Deprecated: 1.32 **/ void pango_fc_font_kern_glyphs (PangoFcFont *font, PangoGlyphString *glyphs) { } /** * _pango_fc_font_get_decoder: * @font: a #PangoFcFont * * This will return any custom decoder set on this font. * * Return value: The custom decoder * * Since: 1.6 **/ PangoFcDecoder * _pango_fc_font_get_decoder (PangoFcFont *font) { PangoFcFontPrivate *priv = font->priv; return priv->decoder; } /** * _pango_fc_font_set_decoder: * @font: a #PangoFcFont * @decoder: a #PangoFcDecoder to set for this font * * This sets a custom decoder for this font. Any previous decoder * will be released before this one is set. * * Since: 1.6 **/ void _pango_fc_font_set_decoder (PangoFcFont *font, PangoFcDecoder *decoder) { PangoFcFontPrivate *priv = font->priv; if (priv->decoder) g_object_unref (priv->decoder); priv->decoder = decoder; if (priv->decoder) g_object_ref (priv->decoder); } PangoFcFontKey * _pango_fc_font_get_font_key (PangoFcFont *fcfont) { PangoFcFontPrivate *priv = fcfont->priv; return priv->key; } void _pango_fc_font_set_font_key (PangoFcFont *fcfont, PangoFcFontKey *key) { PangoFcFontPrivate *priv = fcfont->priv; priv->key = key; } /** * pango_fc_font_get_raw_extents: * @fcfont: a #PangoFcFont * @load_flags: flags to pass to FT_Load_Glyph() * @glyph: the glyph index to load * @ink_rect: (out) (optional): location to store ink extents of the * glyph, or %NULL * @logical_rect: (out) (optional): location to store logical extents * of the glyph or %NULL * * Gets the extents of a single glyph from a font. The extents are in * user space; that is, they are not transformed by any matrix in effect * for the font. * * Long term, this functionality probably belongs in the default * implementation of the get_glyph_extents() virtual function. * The other possibility would be to to make it public in something * like it's current form, and also expose glyph information * caching functionality similar to pango_ft2_font_set_glyph_info(). * * Since: 1.6 **/ void pango_fc_font_get_raw_extents (PangoFcFont *fcfont, FT_Int32 load_flags, PangoGlyph glyph, PangoRectangle *ink_rect, PangoRectangle *logical_rect) { g_return_if_fail (PANGO_IS_FC_FONT (fcfont)); if (glyph == PANGO_GLYPH_EMPTY) { if (ink_rect) { ink_rect->x = 0; ink_rect->width = 0; ink_rect->y = 0; ink_rect->height = 0; } if (logical_rect) { logical_rect->x = 0; logical_rect->width = 0; logical_rect->y = 0; logical_rect->height = 0; } } else { hb_font_t *hb_font = pango_font_get_hb_font (PANGO_FONT (fcfont)); hb_glyph_extents_t extents; hb_font_extents_t font_extents; hb_font_get_glyph_extents (hb_font, glyph, &extents); hb_font_get_extents_for_direction (hb_font, HB_DIRECTION_LTR, &font_extents); if (ink_rect) { ink_rect->x = extents.x_bearing; ink_rect->width = extents.width; ink_rect->y = -extents.y_bearing; ink_rect->height = extents.height; } if (logical_rect) { hb_position_t x, y; hb_font_get_glyph_advance_for_direction (hb_font, glyph, HB_DIRECTION_LTR, &x, &y); logical_rect->x = 0; logical_rect->width = x; logical_rect->y = - font_extents.ascender; logical_rect->height = font_extents.ascender - font_extents.descender; } } } static void pango_fc_font_get_features (PangoFont *font, hb_feature_t *features, guint len, guint *num_features) { /* Setup features from fontconfig pattern. */ PangoFcFont *fc_font = PANGO_FC_FONT (font); if (fc_font->font_pattern) { char *s; while (*num_features < len && FcResultMatch == FcPatternGetString (fc_font->font_pattern, PANGO_FC_FONT_FEATURES, *num_features, (FcChar8 **) &s)) { gboolean ret = hb_feature_from_string (s, -1, &features[*num_features]); features[*num_features].start = 0; features[*num_features].end = (unsigned int) -1; if (ret) (*num_features)++; } } } extern gpointer get_gravity_class (void); static PangoGravity pango_fc_font_key_get_gravity (PangoFcFontKey *key) { FcPattern *pattern; PangoGravity gravity = PANGO_GRAVITY_SOUTH; FcChar8 *s; pattern = pango_fc_font_key_get_pattern (key); if (FcPatternGetString (pattern, PANGO_FC_GRAVITY, 0, (FcChar8 **)&s) == FcResultMatch) { GEnumValue *value = g_enum_get_value_by_nick (get_gravity_class (), (char *)s); gravity = value->value; } return gravity; } static double get_font_size (PangoFcFontKey *key) { FcPattern *pattern; double size; double dpi; pattern = pango_fc_font_key_get_pattern (key); if (FcPatternGetDouble (pattern, FC_PIXEL_SIZE, 0, &size) == FcResultMatch) return size; /* Just in case FC_PIXEL_SIZE got unset between pango_fc_make_pattern() * and here. That would be very weird. */ if (FcPatternGetDouble (pattern, FC_DPI, 0, &dpi) != FcResultMatch) dpi = 72; if (FcPatternGetDouble (pattern, FC_SIZE, 0, &size) == FcResultMatch) return size * dpi / 72.; /* Whatever */ return 18.; } static void parse_variations (const char *variations, hb_variation_t **hb_variations, guint *n_variations) { guint n; hb_variation_t *var; int i; const char *p; n = 1; for (i = 0; variations[i]; i++) { if (variations[i] == ',') n++; } var = g_new (hb_variation_t, n); p = variations; n = 0; while (p && *p) { char *end = strchr (p, ','); if (hb_variation_from_string (p, end ? end - p: -1, &var[n])) n++; p = end ? end + 1 : NULL; } *hb_variations = var; *n_variations = n; } static hb_font_t * pango_fc_font_create_hb_font (PangoFont *font) { PangoFcFont *fc_font = PANGO_FC_FONT (font); PangoFcFontKey *key; hb_face_t *hb_face; hb_font_t *hb_font; double x_scale_inv, y_scale_inv; double x_scale, y_scale; double size; PangoGravity gravity; x_scale_inv = y_scale_inv = 1.0; key = _pango_fc_font_get_font_key (fc_font); if (key) { const PangoMatrix *matrix = pango_fc_font_key_get_matrix (key); pango_matrix_get_font_scale_factors (matrix, &x_scale_inv, &y_scale_inv); } if (PANGO_GRAVITY_IS_IMPROPER (gravity)) { x_scale_inv = -x_scale_inv; y_scale_inv = -y_scale_inv; } x_scale = 1. / x_scale_inv; y_scale = 1. / y_scale_inv; size = get_font_size (key); gravity = pango_fc_font_key_get_gravity (key); hb_face = pango_fc_font_map_get_hb_face (PANGO_FC_FONT_MAP (fc_font->fontmap), fc_font); hb_font = hb_font_create (hb_face); hb_font_set_scale (hb_font, size * PANGO_SCALE * x_scale, size * PANGO_SCALE * y_scale); if (key) { const char *variations = pango_fc_font_key_get_variations (key); if (variations) { guint n_variations; hb_variation_t *hb_variations; parse_variations (variations, &hb_variations, &n_variations); hb_font_set_variations (hb_font, hb_variations, n_variations); g_free (hb_variations); } } return hb_font; }