1 | /* Pango |
2 | * pangocairofc-font.c: Cairo font handling, fontconfig backend |
3 | * |
4 | * Copyright (C) 2000-2005 Red Hat Software |
5 | * |
6 | * This library is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU Library General Public |
8 | * License as published by the Free Software Foundation; either |
9 | * version 2 of the License, or (at your option) any later version. |
10 | * |
11 | * This library is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | * Library General Public License for more details. |
15 | * |
16 | * You should have received a copy of the GNU Library General Public |
17 | * License along with this library; if not, write to the |
18 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
19 | * Boston, MA 02111-1307, USA. |
20 | */ |
21 | |
22 | #include "config.h" |
23 | |
24 | /* Freetype has undefined macros in its header */ |
25 | #pragma GCC diagnostic push |
26 | #pragma GCC diagnostic ignored "-Wundef" |
27 | #include <cairo-ft.h> |
28 | #pragma GCC diagnostic pop |
29 | |
30 | #include "pangofc-fontmap-private.h" |
31 | #include "pangocairo-private.h" |
32 | #include "pangocairo-fc-private.h" |
33 | #include "pangofc-private.h" |
34 | #include "pango-impl-utils.h" |
35 | |
36 | #include <hb-ot.h> |
37 | #include <freetype/ftmm.h> |
38 | |
39 | #define PANGO_TYPE_CAIRO_FC_FONT (pango_cairo_fc_font_get_type ()) |
40 | #define PANGO_CAIRO_FC_FONT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_TYPE_CAIRO_FC_FONT, PangoCairoFcFont)) |
41 | #define PANGO_CAIRO_FC_FONT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PANGO_TYPE_CAIRO_FC_FONT, PangoCairoFcFontClass)) |
42 | #define PANGO_CAIRO_IS_FONT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PANGO_TYPE_CAIRO_FC_FONT)) |
43 | #define PANGO_CAIRO_FC_FONT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PANGO_TYPE_CAIRO_FC_FONT, PangoCairoFcFontClass)) |
44 | |
45 | typedef struct _PangoCairoFcFont PangoCairoFcFont; |
46 | typedef struct _PangoCairoFcFontClass PangoCairoFcFontClass; |
47 | |
48 | struct _PangoCairoFcFont |
49 | { |
50 | PangoFcFont font; |
51 | PangoCairoFontPrivate cf_priv; |
52 | }; |
53 | |
54 | struct _PangoCairoFcFontClass |
55 | { |
56 | PangoFcFontClass parent_class; |
57 | }; |
58 | |
59 | _PANGO_EXTERN |
60 | GType pango_cairo_fc_font_get_type (void); |
61 | |
62 | /******************************** |
63 | * Method implementations * |
64 | ********************************/ |
65 | |
66 | static cairo_font_face_t * |
67 | pango_cairo_fc_font_create_font_face (PangoCairoFont *cfont) |
68 | { |
69 | PangoFcFont *fcfont = (PangoFcFont *) (cfont); |
70 | |
71 | return cairo_ft_font_face_create_for_pattern (pattern: fcfont->font_pattern); |
72 | } |
73 | |
74 | static PangoFontMetrics * |
75 | pango_cairo_fc_font_create_base_metrics_for_context (PangoCairoFont *cfont, |
76 | PangoContext *context) |
77 | { |
78 | PangoCairoFcFont *cffont = (PangoCairoFcFont *) cfont; |
79 | PangoFcFont *fcfont = (PangoFcFont *) cfont; |
80 | PangoFontMetrics *metrics; |
81 | |
82 | metrics = pango_fc_font_create_base_metrics_for_context (font: fcfont, context); |
83 | |
84 | if (_pango_cairo_font_private_is_metrics_hinted (cf_priv: &cffont->cf_priv)) |
85 | { |
86 | metrics->ascent = PANGO_PIXELS_CEIL (metrics->ascent) * PANGO_SCALE; |
87 | metrics->descent = PANGO_PIXELS_CEIL (metrics->descent) * PANGO_SCALE; |
88 | metrics->height = PANGO_PIXELS_CEIL (metrics->height) * PANGO_SCALE; |
89 | } |
90 | |
91 | return metrics; |
92 | } |
93 | |
94 | static void |
95 | cairo_font_iface_init (PangoCairoFontIface *iface) |
96 | { |
97 | iface->create_font_face = pango_cairo_fc_font_create_font_face; |
98 | iface->create_base_metrics_for_context = pango_cairo_fc_font_create_base_metrics_for_context; |
99 | iface->cf_priv_offset = G_STRUCT_OFFSET (PangoCairoFcFont, cf_priv); |
100 | } |
101 | |
102 | G_DEFINE_TYPE_WITH_CODE (PangoCairoFcFont, pango_cairo_fc_font, PANGO_TYPE_FC_FONT, |
103 | { G_IMPLEMENT_INTERFACE (PANGO_TYPE_CAIRO_FONT, cairo_font_iface_init) }) |
104 | |
105 | static void |
106 | pango_cairo_fc_font_finalize (GObject *object) |
107 | { |
108 | PangoCairoFcFont *cffont = (PangoCairoFcFont *) object; |
109 | |
110 | _pango_cairo_font_private_finalize (cf_priv: &cffont->cf_priv); |
111 | |
112 | G_OBJECT_CLASS (pango_cairo_fc_font_parent_class)->finalize (object); |
113 | } |
114 | |
115 | /* we want get_glyph_extents extremely fast, so we use a small wrapper here |
116 | * to avoid having to lookup the interface data like we do for get_metrics |
117 | * in _pango_cairo_font_get_metrics(). */ |
118 | static void |
119 | pango_cairo_fc_font_get_glyph_extents (PangoFont *font, |
120 | PangoGlyph glyph, |
121 | PangoRectangle *ink_rect, |
122 | PangoRectangle *logical_rect) |
123 | { |
124 | PangoCairoFcFont *cffont = (PangoCairoFcFont *) (font); |
125 | |
126 | _pango_cairo_font_private_get_glyph_extents (cf_priv: &cffont->cf_priv, |
127 | glyph, |
128 | ink_rect, |
129 | logical_rect); |
130 | } |
131 | |
132 | static FT_Face |
133 | pango_cairo_fc_font_lock_face (PangoFcFont *font) |
134 | { |
135 | PangoCairoFcFont *cffont = (PangoCairoFcFont *) (font); |
136 | cairo_scaled_font_t *scaled_font = _pango_cairo_font_private_get_scaled_font (cf_priv: &cffont->cf_priv); |
137 | |
138 | if (G_UNLIKELY (!scaled_font)) |
139 | return NULL; |
140 | |
141 | return cairo_ft_scaled_font_lock_face (scaled_font); |
142 | } |
143 | |
144 | static void |
145 | pango_cairo_fc_font_unlock_face (PangoFcFont *font) |
146 | { |
147 | PangoCairoFcFont *cffont = (PangoCairoFcFont *) (font); |
148 | cairo_scaled_font_t *scaled_font = _pango_cairo_font_private_get_scaled_font (cf_priv: &cffont->cf_priv); |
149 | |
150 | if (G_UNLIKELY (!scaled_font)) |
151 | return; |
152 | |
153 | cairo_ft_scaled_font_unlock_face (scaled_font); |
154 | } |
155 | |
156 | static void |
157 | pango_cairo_fc_font_class_init (PangoCairoFcFontClass *class) |
158 | { |
159 | GObjectClass *object_class = G_OBJECT_CLASS (class); |
160 | PangoFontClass *font_class = PANGO_FONT_CLASS (class); |
161 | PangoFcFontClass *fc_font_class = PANGO_FC_FONT_CLASS (class); |
162 | |
163 | object_class->finalize = pango_cairo_fc_font_finalize; |
164 | |
165 | font_class->get_glyph_extents = pango_cairo_fc_font_get_glyph_extents; |
166 | font_class->get_metrics = _pango_cairo_font_get_metrics; |
167 | |
168 | fc_font_class->lock_face = pango_cairo_fc_font_lock_face; |
169 | fc_font_class->unlock_face = pango_cairo_fc_font_unlock_face; |
170 | } |
171 | |
172 | static void |
173 | pango_cairo_fc_font_init (PangoCairoFcFont *cffont G_GNUC_UNUSED) |
174 | { |
175 | } |
176 | |
177 | /******************** |
178 | * Private API * |
179 | ********************/ |
180 | |
181 | static double |
182 | get_font_size (const FcPattern *pattern) |
183 | { |
184 | double size; |
185 | double dpi; |
186 | |
187 | if (FcPatternGetDouble (p: pattern, FC_PIXEL_SIZE, n: 0, d: &size) == FcResultMatch) |
188 | return size; |
189 | |
190 | /* Just in case FC_PIXEL_SIZE got unset between pango_fc_make_pattern() |
191 | * and here. That would be very weird. |
192 | */ |
193 | |
194 | if (FcPatternGetDouble (p: pattern, FC_DPI, n: 0, d: &dpi) != FcResultMatch) |
195 | dpi = 72; |
196 | |
197 | if (FcPatternGetDouble (p: pattern, FC_SIZE, n: 0, d: &size) == FcResultMatch) |
198 | return size * dpi / 72.; |
199 | |
200 | /* Whatever */ |
201 | return 18.; |
202 | } |
203 | |
204 | static gpointer |
205 | get_gravity_class (void) |
206 | { |
207 | static GEnumClass *class = NULL; /* MT-safe */ |
208 | |
209 | if (g_once_init_enter (&class)) |
210 | g_once_init_leave(&class, (gpointer)g_type_class_ref (PANGO_TYPE_GRAVITY)); |
211 | |
212 | return class; |
213 | } |
214 | |
215 | static PangoGravity |
216 | get_gravity (const FcPattern *pattern) |
217 | { |
218 | char *s; |
219 | |
220 | if (FcPatternGetString (p: pattern, PANGO_FC_GRAVITY, n: 0, s: (FcChar8 **)(void *)&s) == FcResultMatch) |
221 | { |
222 | GEnumValue *value = g_enum_get_value_by_nick (enum_class: get_gravity_class (), nick: s); |
223 | return value->value; |
224 | } |
225 | |
226 | return PANGO_GRAVITY_SOUTH; |
227 | } |
228 | |
229 | PangoFcFont * |
230 | _pango_cairo_fc_font_new (PangoCairoFcFontMap *cffontmap, |
231 | PangoFcFontKey *key) |
232 | { |
233 | PangoCairoFcFont *cffont; |
234 | const FcPattern *pattern = pango_fc_font_key_get_pattern (key); |
235 | cairo_matrix_t font_matrix; |
236 | FcMatrix fc_matrix, *fc_matrix_val; |
237 | double size; |
238 | int i; |
239 | cairo_font_options_t *options; |
240 | |
241 | g_return_val_if_fail (PANGO_IS_CAIRO_FC_FONT_MAP (cffontmap), NULL); |
242 | g_return_val_if_fail (pattern != NULL, NULL); |
243 | |
244 | cffont = g_object_new (PANGO_TYPE_CAIRO_FC_FONT, |
245 | first_property_name: "pattern" , pattern, |
246 | "fontmap" , cffontmap, |
247 | NULL); |
248 | |
249 | size = get_font_size (pattern) / |
250 | pango_matrix_get_font_scale_factor (matrix: pango_fc_font_key_get_matrix (key)); |
251 | |
252 | FcMatrixInit (&fc_matrix); |
253 | for (i = 0; FcPatternGetMatrix (p: pattern, FC_MATRIX, n: i, s: &fc_matrix_val) == FcResultMatch; i++) |
254 | FcMatrixMultiply (result: &fc_matrix, a: &fc_matrix, b: fc_matrix_val); |
255 | |
256 | cairo_matrix_init (matrix: &font_matrix, |
257 | xx: fc_matrix.xx, |
258 | yx: - fc_matrix.yx, |
259 | xy: - fc_matrix.xy, |
260 | yy: fc_matrix.yy, |
261 | x0: 0., y0: 0.); |
262 | |
263 | cairo_matrix_scale (matrix: &font_matrix, sx: size, sy: size); |
264 | |
265 | options = pango_fc_font_key_get_context_key (key); |
266 | |
267 | _pango_cairo_font_private_initialize (cf_priv: &cffont->cf_priv, |
268 | font: (PangoCairoFont *) cffont, |
269 | gravity: get_gravity (pattern), |
270 | font_options: options, |
271 | pango_ctm: pango_fc_font_key_get_matrix (key), |
272 | font_matrix: &font_matrix); |
273 | |
274 | ((PangoFcFont *)(cffont))->is_hinted = _pango_cairo_font_private_is_metrics_hinted (cf_priv: &cffont->cf_priv); |
275 | |
276 | return (PangoFcFont *) cffont; |
277 | } |
278 | |