📄 pangofc-font.c
字号:
/* 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. */#include <config.h>#include "pangofc-font.h"#include "pangofc-fontmap.h"#include "pangofc-private.h"#include "pango-layout.h"#include "pango-modules.h"#include "pango-impl-utils.h"#include <fontconfig/fcfreetype.h>#include FT_TRUETYPE_TABLES_Henum { PROP_0, PROP_PATTERN};typedef struct _GUnicharToGlyphCacheEntry GUnicharToGlyphCacheEntry;/* An entry in the fixed-size cache for the gunichar -> glyph mapping. * The cache is indexed by the lower N bits of the gunichar (see * GLYPH_CACHE_NUM_ENTRIES). For scripts with few code points, * this should provide pretty much instant lookups. * * The "ch" field is zero if that cache entry is invalid. */struct _GUnicharToGlyphCacheEntry{ gunichar ch; PangoGlyph glyph;};typedef struct _PangoFcFontPrivate PangoFcFontPrivate;struct _PangoFcFontPrivate{ PangoFcDecoder *decoder; gpointer context_key; GUnicharToGlyphCacheEntry *char_to_glyph_cache;};#define GLYPH_CACHE_NUM_ENTRIES 256 /* should be power of two */#define GLYPH_CACHE_MASK (GLYPH_CACHE_NUM_ENTRIES - 1)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 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);#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_TYPE (PangoFcFont, pango_fc_font, PANGO_TYPE_FONT)static voidpango_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; 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; g_object_class_install_property (object_class, PROP_PATTERN, g_param_spec_pointer ("pattern", "Pattern", "The fontconfig pattern for this font", G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); g_type_class_add_private (object_class, sizeof (PangoFcFontPrivate));}static voidpango_fc_font_init (PangoFcFont *fcfont){ fcfont->priv = G_TYPE_INSTANCE_GET_PRIVATE (fcfont, PANGO_TYPE_FC_FONT, PangoFcFontPrivate);}static voidfree_metrics_info (PangoFcMetricsInfo *info){ pango_font_metrics_unref (info->metrics); g_slice_free (PangoFcMetricsInfo, info);}static voidpango_fc_font_finalize (GObject *object){ PangoFcFont *fcfont = PANGO_FC_FONT (object); PangoFcFontPrivate *priv = fcfont->priv; g_slist_foreach (fcfont->metrics_by_lang, (GFunc)free_metrics_info, NULL); g_slist_free (fcfont->metrics_by_lang); if (fcfont->fontmap) _pango_fc_font_map_remove (PANGO_FC_FONT_MAP (fcfont->fontmap), fcfont); FcPatternDestroy (fcfont->font_pattern); pango_font_description_free (fcfont->description); if (priv->decoder) _pango_fc_font_set_decoder (fcfont, NULL); g_free (priv->char_to_glyph_cache); G_OBJECT_CLASS (pango_fc_font_parent_class)->finalize (object);}static gbooleanpattern_is_hinted (FcPattern *pattern){ FcBool hinting; if (FcPatternGetBool (pattern, FC_HINTING, 0, &hinting) != FcResultMatch) hinting = FcTrue; return hinting;}static gbooleanpattern_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 voidpango_fc_font_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec){ switch (prop_id) { case PROP_PATTERN: { PangoFcFont *fcfont = PANGO_FC_FONT (object); 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); } 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;}static PangoMap *pango_fc_get_shaper_map (PangoLanguage *language){ static guint engine_type_id = 0; static guint render_type_id = 0; if (engine_type_id == 0) { engine_type_id = g_quark_from_static_string (PANGO_ENGINE_TYPE_SHAPE); render_type_id = g_quark_from_static_string (PANGO_RENDER_TYPE_FC); } return pango_find_map (language, engine_type_id, render_type_id);}static PangoEngineShape *pango_fc_font_find_shaper (PangoFont *font, PangoLanguage *language, guint32 ch){ PangoMap *shaper_map = NULL; PangoScript script; shaper_map = pango_fc_get_shaper_map (language); script = pango_script_for_unichar (ch); return (PangoEngineShape *)pango_map_get_engine (shaper_map, script);}static PangoCoverage *pango_fc_font_get_coverage (PangoFont *font, PangoLanguage *language){ PangoFcFont *fcfont = (PangoFcFont *)font; PangoFcFontPrivate *priv = fcfont->priv; FcCharSet *charset; if (priv->decoder) { charset = pango_fc_decoder_get_charset (priv->decoder, fcfont); return _pango_fc_font_map_fc_to_coverage (charset); } return _pango_fc_font_map_get_coverage (PANGO_FC_FONT_MAP (fcfont->fontmap), fcfont);}/* 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 voidget_face_metrics (PangoFcFont *fcfont, PangoFontMetrics *metrics){ FT_Face face = PANGO_FC_FONT_LOCK_FACE (fcfont); FcMatrix *fc_matrix; FT_Matrix ft_matrix; TT_OS2 *os2; gboolean have_transform = FALSE; if (!face) { metrics->descent = 0; metrics->ascent = PANGO_SCALE * PANGO_UNKNOWN_GLYPH_HEIGHT; metrics->underline_thickness = PANGO_SCALE; metrics->underline_position = - PANGO_SCALE; metrics->strikethrough_thickness = PANGO_SCALE; metrics->strikethrough_position = PANGO_SCALE * (PANGO_UNKNOWN_GLYPH_HEIGHT/2); return; } if (FcPatternGetMatrix (fcfont->font_pattern, FC_MATRIX, 0, &fc_matrix) == FcResultMatch) { 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; have_transform = (ft_matrix.xx != 0x10000 || ft_matrix.xy != 0 || ft_matrix.yx != 0 || ft_matrix.yy != 0x10000); } if (have_transform) { FT_Vector vector; vector.x = 0; vector.y = face->size->metrics.descender; FT_Vector_Transform (&vector, &ft_matrix); metrics->descent = - PANGO_UNITS_26_6 (vector.y); vector.x = 0; vector.y = face->size->metrics.ascender; FT_Vector_Transform (&vector, &ft_matrix); metrics->ascent = PANGO_UNITS_26_6 (vector.y); } else if (fcfont->is_hinted || (face->face_flags & FT_FACE_FLAG_SCALABLE) == 0) { metrics->descent = - PANGO_UNITS_26_6 (face->size->metrics.descender); metrics->ascent = PANGO_UNITS_26_6 (face->size->metrics.ascender); } else { FT_Fixed ascender, descender; descender = FT_MulFix (face->descender, face->size->metrics.y_scale); metrics->descent = - PANGO_UNITS_26_6 (descender); ascender = FT_MulFix (face->ascender, face->size->metrics.y_scale); metrics->ascent = PANGO_UNITS_26_6 (ascender); } /* Versions of FreeType < 2.1.8 get underline thickness wrong * for Postscript fonts (always zero), so we need a fallback */ if (face->underline_thickness == 0) { metrics->underline_thickness = (PANGO_SCALE * face->size->metrics.y_ppem) / 14; metrics->underline_position = - metrics->underline_thickness; } else { FT_Fixed ft_thickness, ft_position; ft_thickness = FT_MulFix (face->underline_thickness, face->size->metrics.y_scale); metrics->underline_thickness = PANGO_UNITS_26_6 (ft_thickness); ft_position = FT_MulFix (face->underline_position, face->size->metrics.y_scale); metrics->underline_position = PANGO_UNITS_26_6 (ft_position); } os2 = FT_Get_Sfnt_Table (face, ft_sfnt_os2); if (os2 && os2->version != 0xFFFF && os2->yStrikeoutSize != 0) { FT_Fixed ft_thickness, ft_position; ft_thickness = FT_MulFix (os2->yStrikeoutSize, face->size->metrics.y_scale); metrics->strikethrough_thickness = PANGO_UNITS_26_6 (ft_thickness); ft_position = FT_MulFix (os2->yStrikeoutPosition, face->size->metrics.y_scale); metrics->strikethrough_position = PANGO_UNITS_26_6 (ft_position); } else { metrics->strikethrough_thickness = metrics->underline_thickness; metrics->strikethrough_position = (PANGO_SCALE * face->size->metrics.y_ppem) / 4; } /* If hinting is on for this font, quantize the underline and strikethrough position * to integer values. */ if (fcfont->is_hinted) { pango_quantize_line_geometry (&metrics->underline_thickness, &metrics->underline_position); pango_quantize_line_geometry (&metrics->strikethrough_thickness, &metrics->strikethrough_position); } PANGO_FC_FONT_UNLOCK_FACE (fcfont);}static intmax_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;}PangoFontMetrics *pango_fc_font_create_metrics_for_context (PangoFcFont *fcfont, PangoContext *context){ PangoFontMetrics *metrics; PangoLayout *layout; PangoRectangle extents; PangoLanguage *language = pango_context_get_language (context); const char *sample_str = pango_language_get_sample_string (language); PangoFontDescription *desc = pango_font_describe_with_absolute_size (fcfont); metrics = pango_font_metrics_new (); get_face_metrics (fcfont, metrics); 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); metrics->approximate_char_width = extents.width / g_utf8_strlen (sample_str, -1); pango_layout_set_text (layout, "0123456789", -1); metrics->approximate_digit_width = max_glyph_width (layout); g_object_unref (layout);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -