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 *
pango_cairo_fc_font_create_font_face(PangoCairoFont * cfont)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 (fcfont->font_pattern);
72 }
73 
74 static PangoFontMetrics *
pango_cairo_fc_font_create_base_metrics_for_context(PangoCairoFont * cfont,PangoContext * context)75 pango_cairo_fc_font_create_base_metrics_for_context (PangoCairoFont *cfont,
76 						     PangoContext   *context)
77 {
78   PangoFcFont *fcfont = (PangoFcFont *) (cfont);
79 
80   return pango_fc_font_create_base_metrics_for_context (fcfont, context);
81 }
82 
83 static void
cairo_font_iface_init(PangoCairoFontIface * iface)84 cairo_font_iface_init (PangoCairoFontIface *iface)
85 {
86   iface->create_font_face = pango_cairo_fc_font_create_font_face;
87   iface->create_base_metrics_for_context = pango_cairo_fc_font_create_base_metrics_for_context;
88   iface->cf_priv_offset = G_STRUCT_OFFSET (PangoCairoFcFont, cf_priv);
89 }
90 
91 G_DEFINE_TYPE_WITH_CODE (PangoCairoFcFont, pango_cairo_fc_font, PANGO_TYPE_FC_FONT,
92     { G_IMPLEMENT_INTERFACE (PANGO_TYPE_CAIRO_FONT, cairo_font_iface_init) })
93 
94 static void
pango_cairo_fc_font_finalize(GObject * object)95 pango_cairo_fc_font_finalize (GObject *object)
96 {
97   PangoCairoFcFont *cffont = (PangoCairoFcFont *) object;
98 
99   _pango_cairo_font_private_finalize (&cffont->cf_priv);
100 
101   G_OBJECT_CLASS (pango_cairo_fc_font_parent_class)->finalize (object);
102 }
103 
104 /* we want get_glyph_extents extremely fast, so we use a small wrapper here
105  * to avoid having to lookup the interface data like we do for get_metrics
106  * in _pango_cairo_font_get_metrics(). */
107 static void
pango_cairo_fc_font_get_glyph_extents(PangoFont * font,PangoGlyph glyph,PangoRectangle * ink_rect,PangoRectangle * logical_rect)108 pango_cairo_fc_font_get_glyph_extents (PangoFont      *font,
109 				       PangoGlyph      glyph,
110 				       PangoRectangle *ink_rect,
111 				       PangoRectangle *logical_rect)
112 {
113   PangoCairoFcFont *cffont = (PangoCairoFcFont *) (font);
114 
115   _pango_cairo_font_private_get_glyph_extents (&cffont->cf_priv,
116 					       glyph,
117 					       ink_rect,
118 					       logical_rect);
119 }
120 
121 static FT_Face
pango_cairo_fc_font_lock_face(PangoFcFont * font)122 pango_cairo_fc_font_lock_face (PangoFcFont *font)
123 {
124   PangoCairoFcFont *cffont = (PangoCairoFcFont *) (font);
125   cairo_scaled_font_t *scaled_font = _pango_cairo_font_private_get_scaled_font (&cffont->cf_priv);
126 
127   if (G_UNLIKELY (!scaled_font))
128     return NULL;
129 
130   return cairo_ft_scaled_font_lock_face (scaled_font);
131 }
132 
133 static void
pango_cairo_fc_font_unlock_face(PangoFcFont * font)134 pango_cairo_fc_font_unlock_face (PangoFcFont *font)
135 {
136   PangoCairoFcFont *cffont = (PangoCairoFcFont *) (font);
137   cairo_scaled_font_t *scaled_font = _pango_cairo_font_private_get_scaled_font (&cffont->cf_priv);
138 
139   if (G_UNLIKELY (!scaled_font))
140     return;
141 
142   cairo_ft_scaled_font_unlock_face (scaled_font);
143 }
144 
145 static void
pango_cairo_fc_font_class_init(PangoCairoFcFontClass * class)146 pango_cairo_fc_font_class_init (PangoCairoFcFontClass *class)
147 {
148   GObjectClass *object_class = G_OBJECT_CLASS (class);
149   PangoFontClass *font_class = PANGO_FONT_CLASS (class);
150   PangoFcFontClass *fc_font_class = PANGO_FC_FONT_CLASS (class);
151 
152   object_class->finalize = pango_cairo_fc_font_finalize;
153 
154   font_class->get_glyph_extents = pango_cairo_fc_font_get_glyph_extents;
155   font_class->get_metrics = _pango_cairo_font_get_metrics;
156 
157   fc_font_class->lock_face = pango_cairo_fc_font_lock_face;
158   fc_font_class->unlock_face = pango_cairo_fc_font_unlock_face;
159 }
160 
161 static void
pango_cairo_fc_font_init(PangoCairoFcFont * cffont G_GNUC_UNUSED)162 pango_cairo_fc_font_init (PangoCairoFcFont *cffont G_GNUC_UNUSED)
163 {
164 }
165 
166 /********************
167  *    Private API   *
168  ********************/
169 
170 static double
get_font_size(const FcPattern * pattern)171 get_font_size (const FcPattern *pattern)
172 {
173   double size;
174   double dpi;
175 
176   if (FcPatternGetDouble (pattern, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
177     return size;
178 
179   /* Just in case FC_PIXEL_SIZE got unset between pango_fc_make_pattern()
180    * and here.  That would be very weird.
181    */
182 
183   if (FcPatternGetDouble (pattern, FC_DPI, 0, &dpi) != FcResultMatch)
184     dpi = 72;
185 
186   if (FcPatternGetDouble (pattern, FC_SIZE, 0, &size) == FcResultMatch)
187     return size * dpi / 72.;
188 
189   /* Whatever */
190   return 18.;
191 }
192 
193 static gpointer
get_gravity_class(void)194 get_gravity_class (void)
195 {
196   static GEnumClass *class = NULL; /* MT-safe */
197 
198   if (g_once_init_enter (&class))
199     g_once_init_leave(&class, (gpointer)g_type_class_ref (PANGO_TYPE_GRAVITY));
200 
201   return class;
202 }
203 
204 static PangoGravity
get_gravity(const FcPattern * pattern)205 get_gravity (const FcPattern *pattern)
206 {
207   char *s;
208 
209   if (FcPatternGetString (pattern, PANGO_FC_GRAVITY, 0, (FcChar8 **)(void *)&s) == FcResultMatch)
210     {
211       GEnumValue *value = g_enum_get_value_by_nick (get_gravity_class (), s);
212       return value->value;
213     }
214 
215   return PANGO_GRAVITY_SOUTH;
216 }
217 
218 PangoFcFont *
_pango_cairo_fc_font_new(PangoCairoFcFontMap * cffontmap,PangoFcFontKey * key)219 _pango_cairo_fc_font_new (PangoCairoFcFontMap *cffontmap,
220 			  PangoFcFontKey      *key)
221 {
222   PangoCairoFcFont *cffont;
223   const FcPattern *pattern = pango_fc_font_key_get_pattern (key);
224   cairo_matrix_t font_matrix;
225   FcMatrix fc_matrix, *fc_matrix_val;
226   double size;
227   int i;
228   cairo_font_options_t *options;
229 
230   g_return_val_if_fail (PANGO_IS_CAIRO_FC_FONT_MAP (cffontmap), NULL);
231   g_return_val_if_fail (pattern != NULL, NULL);
232 
233   cffont = g_object_new (PANGO_TYPE_CAIRO_FC_FONT,
234 			 "pattern", pattern,
235 			 "fontmap", cffontmap,
236 			 NULL);
237 
238   size = get_font_size (pattern) /
239 	 pango_matrix_get_font_scale_factor (pango_fc_font_key_get_matrix (key));
240 
241   FcMatrixInit (&fc_matrix);
242   for (i = 0; FcPatternGetMatrix (pattern, FC_MATRIX, i, &fc_matrix_val) == FcResultMatch; i++)
243     FcMatrixMultiply (&fc_matrix, &fc_matrix, fc_matrix_val);
244 
245   cairo_matrix_init (&font_matrix,
246 		     fc_matrix.xx,
247 		     - fc_matrix.yx,
248 		     - fc_matrix.xy,
249 		     fc_matrix.yy,
250 		     0., 0.);
251 
252   cairo_matrix_scale (&font_matrix, size, size);
253 
254   options = pango_fc_font_key_get_context_key (key);
255 
256   _pango_cairo_font_private_initialize (&cffont->cf_priv,
257 					(PangoCairoFont *) cffont,
258 					get_gravity (pattern),
259 					options,
260 					pango_fc_font_key_get_matrix (key),
261 					&font_matrix);
262 
263   ((PangoFcFont *)(cffont))->is_hinted = _pango_cairo_font_private_is_metrics_hinted (&cffont->cf_priv);
264 
265   return (PangoFcFont *) cffont;
266 }
267