Git init
[external/pango1.0.git] / pango / pangofc-font.c
1 /* Pango
2  * pangofc-font.c: Shared interfaces for fontconfig-based backends
3  *
4  * Copyright (C) 2003 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 #include "pangofc-font.h"
25 #include "pangofc-fontmap.h"
26 #include "pangofc-private.h"
27 #include "pango-layout.h"
28 #include "pango-modules.h"
29 #include "pango-impl-utils.h"
30
31 #include <fontconfig/fcfreetype.h>
32
33 #include FT_TRUETYPE_TABLES_H
34
35 enum {
36   PROP_0,
37   PROP_PATTERN,
38   PROP_FONTMAP
39 };
40
41 typedef struct _PangoFcFontPrivate PangoFcFontPrivate;
42
43 struct _PangoFcFontPrivate
44 {
45   PangoFcDecoder *decoder;
46   PangoFcFontKey *key;
47   PangoFcCmapCache *cmap_cache;
48   gboolean has_weak_pointer; /* have set a weak_pointer from fontmap to us */
49 };
50
51 static gboolean pango_fc_font_real_has_char  (PangoFcFont *font,
52                                               gunichar     wc);
53 static guint    pango_fc_font_real_get_glyph (PangoFcFont *font,
54                                               gunichar     wc);
55
56 static void                  pango_fc_font_finalize     (GObject          *object);
57 static void                  pango_fc_font_set_property (GObject          *object,
58                                                          guint             prop_id,
59                                                          const GValue     *value,
60                                                          GParamSpec       *pspec);
61 static void                  pango_fc_font_get_property (GObject          *object,
62                                                          guint             prop_id,
63                                                          GValue           *value,
64                                                          GParamSpec       *pspec);
65 static PangoEngineShape *    pango_fc_font_find_shaper  (PangoFont        *font,
66                                                          PangoLanguage    *language,
67                                                          guint32           ch);
68 static PangoCoverage *       pango_fc_font_get_coverage (PangoFont        *font,
69                                                          PangoLanguage    *language);
70 static PangoFontMetrics *    pango_fc_font_get_metrics  (PangoFont        *font,
71                                                          PangoLanguage    *language);
72 static PangoFontMap *        pango_fc_font_get_font_map (PangoFont        *font);
73 static PangoFontDescription *pango_fc_font_describe     (PangoFont        *font);
74 static PangoFontDescription *pango_fc_font_describe_absolute (PangoFont        *font);
75
76
77 #define PANGO_FC_FONT_LOCK_FACE(font)   (PANGO_FC_FONT_GET_CLASS (font)->lock_face (font))
78 #define PANGO_FC_FONT_UNLOCK_FACE(font) (PANGO_FC_FONT_GET_CLASS (font)->unlock_face (font))
79
80 G_DEFINE_ABSTRACT_TYPE (PangoFcFont, pango_fc_font, PANGO_TYPE_FONT)
81
82 static void
83 pango_fc_font_class_init (PangoFcFontClass *class)
84 {
85   GObjectClass *object_class = G_OBJECT_CLASS (class);
86   PangoFontClass *font_class = PANGO_FONT_CLASS (class);
87
88   class->has_char = pango_fc_font_real_has_char;
89   class->get_glyph = pango_fc_font_real_get_glyph;
90   class->get_unknown_glyph = NULL;
91
92   object_class->finalize = pango_fc_font_finalize;
93   object_class->set_property = pango_fc_font_set_property;
94   object_class->get_property = pango_fc_font_get_property;
95   font_class->describe = pango_fc_font_describe;
96   font_class->describe_absolute = pango_fc_font_describe_absolute;
97   font_class->find_shaper = pango_fc_font_find_shaper;
98   font_class->get_coverage = pango_fc_font_get_coverage;
99   font_class->get_metrics = pango_fc_font_get_metrics;
100   font_class->get_font_map = pango_fc_font_get_font_map;
101
102   g_object_class_install_property (object_class, PROP_PATTERN,
103                                    g_param_spec_pointer ("pattern",
104                                                          "Pattern",
105                                                          "The fontconfig pattern for this font",
106                                                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
107                                                          G_PARAM_STATIC_STRINGS));
108   g_object_class_install_property (object_class, PROP_FONTMAP,
109                                    g_param_spec_object ("fontmap",
110                                                         "Font Map",
111                                                         "The PangoFc font map this font is associated with (Since: 1.26)",
112                                                         PANGO_TYPE_FC_FONT_MAP,
113                                                         G_PARAM_READWRITE |
114                                                         G_PARAM_STATIC_STRINGS));
115
116   g_type_class_add_private (object_class, sizeof (PangoFcFontPrivate));
117 }
118
119 static void
120 pango_fc_font_init (PangoFcFont *fcfont)
121 {
122   fcfont->priv = G_TYPE_INSTANCE_GET_PRIVATE (fcfont,
123                                               PANGO_TYPE_FC_FONT,
124                                               PangoFcFontPrivate);
125 }
126
127 static void
128 free_metrics_info (PangoFcMetricsInfo *info)
129 {
130   pango_font_metrics_unref (info->metrics);
131   g_slice_free (PangoFcMetricsInfo, info);
132 }
133
134 static void
135 pango_fc_font_finalize (GObject *object)
136 {
137   PangoFcFont *fcfont = PANGO_FC_FONT (object);
138   PangoFcFontPrivate *priv = fcfont->priv;
139
140   g_slist_foreach (fcfont->metrics_by_lang, (GFunc)free_metrics_info, NULL);
141   g_slist_free (fcfont->metrics_by_lang);
142
143   if (fcfont->fontmap)
144     {
145       _pango_fc_font_map_remove (PANGO_FC_FONT_MAP (fcfont->fontmap), fcfont);
146       if (priv->has_weak_pointer)
147         {
148           priv->has_weak_pointer = FALSE;
149           g_object_remove_weak_pointer (G_OBJECT (fcfont->fontmap), (gpointer *) (gpointer) &fcfont->fontmap);
150         }
151       fcfont->fontmap = NULL;
152     }
153
154   FcPatternDestroy (fcfont->font_pattern);
155   pango_font_description_free (fcfont->description);
156
157   if (priv->decoder)
158     _pango_fc_font_set_decoder (fcfont, NULL);
159
160   if (priv->cmap_cache)
161     _pango_fc_cmap_cache_unref (priv->cmap_cache);
162
163   G_OBJECT_CLASS (pango_fc_font_parent_class)->finalize (object);
164 }
165
166 static gboolean
167 pattern_is_hinted (FcPattern *pattern)
168 {
169   FcBool hinting;
170
171   if (FcPatternGetBool (pattern,
172                         FC_HINTING, 0, &hinting) != FcResultMatch)
173     hinting = FcTrue;
174
175   return hinting;
176 }
177
178 static gboolean
179 pattern_is_transformed (FcPattern *pattern)
180 {
181   FcMatrix *fc_matrix;
182
183   if (FcPatternGetMatrix (pattern, FC_MATRIX, 0, &fc_matrix) == FcResultMatch)
184     {
185       FT_Matrix ft_matrix;
186
187       ft_matrix.xx = 0x10000L * fc_matrix->xx;
188       ft_matrix.yy = 0x10000L * fc_matrix->yy;
189       ft_matrix.xy = 0x10000L * fc_matrix->xy;
190       ft_matrix.yx = 0x10000L * fc_matrix->yx;
191
192       return ((ft_matrix.xy | ft_matrix.yx) != 0 ||
193               ft_matrix.xx != 0x10000L ||
194               ft_matrix.yy != 0x10000L);
195     }
196   else
197     return FALSE;
198 }
199
200 static void
201 pango_fc_font_set_property (GObject       *object,
202                             guint          prop_id,
203                             const GValue  *value,
204                             GParamSpec    *pspec)
205 {
206   PangoFcFont *fcfont = PANGO_FC_FONT (object);
207
208   switch (prop_id)
209     {
210     case PROP_PATTERN:
211       {
212         FcPattern *pattern = g_value_get_pointer (value);
213
214         g_return_if_fail (pattern != NULL);
215         g_return_if_fail (fcfont->font_pattern == NULL);
216
217         FcPatternReference (pattern);
218         fcfont->font_pattern = pattern;
219         fcfont->description = pango_fc_font_description_from_pattern (pattern, TRUE);
220         fcfont->is_hinted = pattern_is_hinted (pattern);
221         fcfont->is_transformed = pattern_is_transformed (pattern);
222       }
223       goto set_decoder;
224
225     case PROP_FONTMAP:
226       {
227         PangoFcFontMap *fcfontmap = PANGO_FC_FONT_MAP (g_value_get_object (value));
228
229         g_return_if_fail (fcfont->fontmap == NULL);
230         fcfont->fontmap = (PangoFontMap *) fcfontmap;
231         if (fcfont->fontmap)
232           {
233             PangoFcFontPrivate *priv = fcfont->priv;
234             priv->has_weak_pointer = TRUE;
235             g_object_add_weak_pointer (G_OBJECT (fcfont->fontmap), (gpointer *) (gpointer) &fcfont->fontmap);
236           }
237       }
238       goto set_decoder;
239
240     default:
241       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
242       return;
243     }
244
245 set_decoder:
246   /* set decoder if both pattern and fontmap are set now */
247   if (fcfont->font_pattern && fcfont->fontmap)
248     _pango_fc_font_set_decoder (fcfont,
249                                 pango_fc_font_map_find_decoder  ((PangoFcFontMap *) fcfont->fontmap,
250                                                                  fcfont->font_pattern));
251 }
252
253 static void
254 pango_fc_font_get_property (GObject       *object,
255                             guint          prop_id,
256                             GValue        *value,
257                             GParamSpec    *pspec)
258 {
259   switch (prop_id)
260     {
261     case PROP_PATTERN:
262       {
263         PangoFcFont *fcfont = PANGO_FC_FONT (object);
264         g_value_set_pointer (value, fcfont->font_pattern);
265       }
266       break;
267     case PROP_FONTMAP:
268       {
269         PangoFcFont *fcfont = PANGO_FC_FONT (object);
270         g_value_set_object (value, fcfont->fontmap);
271       }
272       break;
273     default:
274       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
275       break;
276     }
277 }
278
279 static PangoFontDescription *
280 pango_fc_font_describe (PangoFont *font)
281 {
282   PangoFcFont *fcfont = (PangoFcFont *)font;
283
284   return pango_font_description_copy (fcfont->description);
285 }
286
287 static PangoFontDescription *
288 pango_fc_font_describe_absolute (PangoFont *font)
289 {
290   PangoFcFont *fcfont = (PangoFcFont *)font;
291   PangoFontDescription *desc = pango_font_description_copy (fcfont->description);
292   double size;
293
294   if (FcPatternGetDouble (fcfont->font_pattern, FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
295     pango_font_description_set_absolute_size (desc, size * PANGO_SCALE);
296
297   return desc;
298 }
299
300 static PangoMap *
301 pango_fc_get_shaper_map (PangoLanguage *language)
302 {
303   static guint engine_type_id = 0;
304   static guint render_type_id = 0;
305
306   if (engine_type_id == 0)
307     {
308       engine_type_id = g_quark_from_static_string (PANGO_ENGINE_TYPE_SHAPE);
309       render_type_id = g_quark_from_static_string (PANGO_RENDER_TYPE_FC);
310     }
311
312   return pango_find_map (language, engine_type_id, render_type_id);
313 }
314
315 static PangoEngineShape *
316 pango_fc_font_find_shaper (PangoFont     *font G_GNUC_UNUSED,
317                            PangoLanguage *language,
318                            guint32        ch)
319 {
320   PangoMap *shaper_map = NULL;
321   PangoScript script;
322
323   shaper_map = pango_fc_get_shaper_map (language);
324   script = pango_script_for_unichar (ch);
325   return (PangoEngineShape *)pango_map_get_engine (shaper_map, script);
326 }
327
328 static PangoCoverage *
329 pango_fc_font_get_coverage (PangoFont     *font,
330                             PangoLanguage *language G_GNUC_UNUSED)
331 {
332   PangoFcFont *fcfont = (PangoFcFont *)font;
333   PangoFcFontPrivate *priv = fcfont->priv;
334   FcCharSet *charset;
335
336   if (priv->decoder)
337     {
338       charset = pango_fc_decoder_get_charset (priv->decoder, fcfont);
339       return _pango_fc_font_map_fc_to_coverage (charset);
340     }
341
342   if (!fcfont->fontmap)
343     return pango_coverage_new ();
344
345   return _pango_fc_font_map_get_coverage (PANGO_FC_FONT_MAP (fcfont->fontmap),
346                                           fcfont);
347 }
348
349 /* For Xft, it would be slightly more efficient to simply to
350  * call Xft, and also more robust against changes in Xft.
351  * But for now, we simply use the same code for all backends.
352  *
353  * The code in this function is partly based on code from Xft,
354  * Copyright 2000 Keith Packard
355  */
356 static void
357 get_face_metrics (PangoFcFont      *fcfont,
358                   PangoFontMetrics *metrics)
359 {
360   FT_Face face = PANGO_FC_FONT_LOCK_FACE (fcfont);
361   FcMatrix *fc_matrix;
362   FT_Matrix ft_matrix;
363   TT_OS2 *os2;
364   gboolean have_transform = FALSE;
365
366   if (G_UNLIKELY (!face))
367     {
368       metrics->descent = 0;
369       metrics->ascent = PANGO_SCALE * PANGO_UNKNOWN_GLYPH_HEIGHT;
370       metrics->underline_thickness = PANGO_SCALE;
371       metrics->underline_position = - PANGO_SCALE;
372       metrics->strikethrough_thickness = PANGO_SCALE;
373       metrics->strikethrough_position = PANGO_SCALE * (PANGO_UNKNOWN_GLYPH_HEIGHT/2);
374       return;
375     }
376
377   if  (FcPatternGetMatrix (fcfont->font_pattern,
378                            FC_MATRIX, 0, &fc_matrix) == FcResultMatch)
379     {
380       ft_matrix.xx = 0x10000L * fc_matrix->xx;
381       ft_matrix.yy = 0x10000L * fc_matrix->yy;
382       ft_matrix.xy = 0x10000L * fc_matrix->xy;
383       ft_matrix.yx = 0x10000L * fc_matrix->yx;
384
385       have_transform = (ft_matrix.xx != 0x10000 || ft_matrix.xy != 0 ||
386                         ft_matrix.yx != 0 || ft_matrix.yy != 0x10000);
387     }
388
389   if (have_transform)
390     {
391       FT_Vector vector;
392
393       vector.x = 0;
394       vector.y = face->size->metrics.descender;
395       FT_Vector_Transform (&vector, &ft_matrix);
396       metrics->descent = - PANGO_UNITS_26_6 (vector.y);
397
398       vector.x = 0;
399       vector.y = face->size->metrics.ascender;
400       FT_Vector_Transform (&vector, &ft_matrix);
401       metrics->ascent = PANGO_UNITS_26_6 (vector.y);
402     }
403   else if (fcfont->is_hinted ||
404            (face->face_flags & FT_FACE_FLAG_SCALABLE) == 0)
405     {
406       metrics->descent = - PANGO_UNITS_26_6 (face->size->metrics.descender);
407       metrics->ascent = PANGO_UNITS_26_6 (face->size->metrics.ascender);
408     }
409   else
410     {
411       FT_Fixed ascender, descender;
412
413       descender = FT_MulFix (face->descender, face->size->metrics.y_scale);
414       metrics->descent = - PANGO_UNITS_26_6 (descender);
415
416       ascender = FT_MulFix (face->ascender, face->size->metrics.y_scale);
417       metrics->ascent = PANGO_UNITS_26_6 (ascender);
418     }
419
420
421   metrics->underline_thickness = 0;
422   metrics->underline_position = 0;
423
424   {
425     FT_Fixed ft_thickness, ft_position;
426
427     ft_thickness = FT_MulFix (face->underline_thickness, face->size->metrics.y_scale);
428     metrics->underline_thickness = PANGO_UNITS_26_6 (ft_thickness);
429
430     ft_position = FT_MulFix (face->underline_position, face->size->metrics.y_scale);
431     metrics->underline_position = PANGO_UNITS_26_6 (ft_position);
432   }
433
434   if (metrics->underline_thickness == 0 || metrics->underline_position == 0)
435     {
436       metrics->underline_thickness = (PANGO_SCALE * face->size->metrics.y_ppem) / 14;
437       metrics->underline_position = - metrics->underline_thickness;
438     }
439
440
441   metrics->strikethrough_thickness = 0;
442   metrics->strikethrough_position = 0;
443
444   os2 = FT_Get_Sfnt_Table (face, ft_sfnt_os2);
445   if (os2 && os2->version != 0xFFFF)
446     {
447       FT_Fixed ft_thickness, ft_position;
448
449       ft_thickness = FT_MulFix (os2->yStrikeoutSize, face->size->metrics.y_scale);
450       metrics->strikethrough_thickness = PANGO_UNITS_26_6 (ft_thickness);
451
452       ft_position = FT_MulFix (os2->yStrikeoutPosition, face->size->metrics.y_scale);
453       metrics->strikethrough_position = PANGO_UNITS_26_6 (ft_position);
454     }
455
456   if (metrics->strikethrough_thickness == 0 || metrics->strikethrough_position == 0)
457     {
458       metrics->strikethrough_thickness = metrics->underline_thickness;
459       metrics->strikethrough_position = (PANGO_SCALE * face->size->metrics.y_ppem) / 4;
460     }
461
462
463   /* If hinting is on for this font, quantize the underline and strikethrough position
464    * to integer values.
465    */
466   if (fcfont->is_hinted)
467     {
468       pango_quantize_line_geometry (&metrics->underline_thickness,
469                                     &metrics->underline_position);
470       pango_quantize_line_geometry (&metrics->strikethrough_thickness,
471                                     &metrics->strikethrough_position);
472
473       /* Quantizing may have pushed underline_position to 0.  Not good */
474       if (metrics->underline_position == 0)
475         metrics->underline_position = - metrics->underline_thickness;
476     }
477
478
479   PANGO_FC_FONT_UNLOCK_FACE (fcfont);
480 }
481
482 static int
483 max_glyph_width (PangoLayout *layout)
484 {
485   int max_width = 0;
486   GSList *l, *r;
487
488   for (l = pango_layout_get_lines_readonly (layout); l; l = l->next)
489     {
490       PangoLayoutLine *line = l->data;
491
492       for (r = line->runs; r; r = r->next)
493         {
494           PangoGlyphString *glyphs = ((PangoGlyphItem *)r->data)->glyphs;
495           int i;
496
497           for (i = 0; i < glyphs->num_glyphs; i++)
498             if (glyphs->glyphs[i].geometry.width > max_width)
499               max_width = glyphs->glyphs[i].geometry.width;
500         }
501     }
502
503   return max_width;
504 }
505
506 PangoFontMetrics *
507 pango_fc_font_create_metrics_for_context (PangoFcFont   *fcfont,
508                                           PangoContext  *context)
509 {
510   PangoFontMetrics *metrics;
511   PangoLayout *layout;
512   PangoRectangle extents;
513   PangoLanguage *language = pango_context_get_language (context);
514   const char *sample_str = pango_language_get_sample_string (language);
515   PangoFontDescription *desc = pango_font_describe_with_absolute_size (PANGO_FONT (fcfont));
516
517   metrics = pango_font_metrics_new ();
518
519   get_face_metrics (fcfont, metrics);
520
521   layout = pango_layout_new (context);
522   pango_layout_set_font_description (layout, desc);
523   pango_font_description_free (desc);
524
525   pango_layout_set_text (layout, sample_str, -1);
526   pango_layout_get_extents (layout, NULL, &extents);
527
528   metrics->approximate_char_width =
529     extents.width / pango_utf8_strwidth (sample_str);
530
531   pango_layout_set_text (layout, "0123456789", -1);
532   metrics->approximate_digit_width = max_glyph_width (layout);
533
534   g_object_unref (layout);
535
536   return metrics;
537 }
538
539 /* This function is cut-and-pasted into pangocairo-fcfont.c - it might be
540  * better to add a virtual fcfont->create_context (font).
541  */
542 static PangoFontMetrics *
543 pango_fc_font_get_metrics (PangoFont     *font,
544                            PangoLanguage *language)
545 {
546   PangoFcFont *fcfont = PANGO_FC_FONT (font);
547   PangoFcMetricsInfo *info = NULL; /* Quiet gcc */
548   GSList *tmp_list;
549
550   const char *sample_str = pango_language_get_sample_string (language);
551
552   tmp_list = fcfont->metrics_by_lang;
553   while (tmp_list)
554     {
555       info = tmp_list->data;
556
557       if (info->sample_str == sample_str)    /* We _don't_ need strcmp */
558         break;
559
560       tmp_list = tmp_list->next;
561     }
562
563   if (!tmp_list)
564     {
565       PangoFontMap *fontmap;
566       PangoContext *context;
567
568       /* XXX this is racy.  because weakref's are racy... */
569       fontmap = fcfont->fontmap;
570       if (!fontmap)
571         return pango_font_metrics_new ();
572       fontmap = g_object_ref (fontmap);
573
574       info = g_slice_new0 (PangoFcMetricsInfo);
575
576       fcfont->metrics_by_lang = g_slist_prepend (fcfont->metrics_by_lang,
577                                                  info);
578
579       info->sample_str = sample_str;
580
581       context = pango_font_map_create_context (fontmap);
582       pango_context_set_language (context, language);
583
584       info->metrics = pango_fc_font_create_metrics_for_context (fcfont, context);
585
586       g_object_unref (context);
587       g_object_unref (fontmap);
588     }
589
590   return pango_font_metrics_ref (info->metrics);
591 }
592
593 static PangoFontMap *
594 pango_fc_font_get_font_map (PangoFont *font)
595 {
596   PangoFcFont *fcfont = PANGO_FC_FONT (font);
597
598   return fcfont->fontmap;
599 }
600
601 static gboolean
602 pango_fc_font_real_has_char (PangoFcFont *font,
603                              gunichar     wc)
604 {
605   FcCharSet *charset;
606
607   if (FcPatternGetCharSet (font->font_pattern,
608                            FC_CHARSET, 0, &charset) != FcResultMatch)
609     return FALSE;
610
611   return FcCharSetHasChar (charset, wc);
612 }
613
614 static guint
615 pango_fc_font_real_get_glyph (PangoFcFont *font,
616                               gunichar     wc)
617 {
618   PangoFcFontPrivate *priv = font->priv;
619   FT_Face face;
620   FT_UInt index;
621
622   guint idx;
623   PangoFcCmapCacheEntry *entry;
624
625
626   if (G_UNLIKELY (priv->cmap_cache == NULL))
627     {
628       priv->cmap_cache = _pango_fc_font_map_get_cmap_cache ((PangoFcFontMap *) font->fontmap,
629                                                             font);
630
631       if (G_UNLIKELY (!priv->cmap_cache))
632         return 0;
633     }
634
635   idx = wc & CMAP_CACHE_MASK;
636   entry = priv->cmap_cache->entries + idx;
637
638   if (entry->ch != wc)
639     {
640       face = PANGO_FC_FONT_LOCK_FACE (font);
641       if (G_LIKELY (face))
642         {
643           index = FcFreeTypeCharIndex (face, wc);
644           if (index > (FT_UInt)face->num_glyphs)
645             index = 0;
646
647           PANGO_FC_FONT_UNLOCK_FACE (font);
648         }
649       else
650         index = 0;
651
652       entry->ch = wc;
653       entry->glyph = index;
654     }
655
656   return entry->glyph;
657 }
658
659 /**
660  * pango_fc_font_lock_face:
661  * @font: a #PangoFcFont.
662  *
663  * Gets the FreeType <type>FT_Face</type> associated with a font,
664  * This face will be kept around until you call
665  * pango_fc_font_unlock_face().
666  *
667  * Return value: the FreeType <type>FT_Face</type> associated with @font.
668  *
669  * Since: 1.4
670  **/
671 FT_Face
672 pango_fc_font_lock_face (PangoFcFont *font)
673 {
674   g_return_val_if_fail (PANGO_IS_FC_FONT (font), NULL);
675
676   return PANGO_FC_FONT_LOCK_FACE (font);
677 }
678
679 /**
680  * pango_fc_font_unlock_face:
681  * @font: a #PangoFcFont.
682  *
683  * Releases a font previously obtained with
684  * pango_fc_font_lock_face().
685  *
686  * Since: 1.4
687  **/
688 void
689 pango_fc_font_unlock_face (PangoFcFont *font)
690 {
691   g_return_if_fail (PANGO_IS_FC_FONT (font));
692
693   PANGO_FC_FONT_UNLOCK_FACE (font);
694 }
695
696 /**
697  * pango_fc_font_has_char:
698  * @font: a #PangoFcFont
699  * @wc: Unicode codepoint to look up
700  *
701  * Determines whether @font has a glyph for the codepoint @wc.
702  *
703  * Return value: %TRUE if @font has the requested codepoint.
704  *
705  * Since: 1.4
706  **/
707 gboolean
708 pango_fc_font_has_char (PangoFcFont *font,
709                         gunichar     wc)
710 {
711   PangoFcFontPrivate *priv = font->priv;
712   FcCharSet *charset;
713
714   g_return_val_if_fail (PANGO_IS_FC_FONT (font), FALSE);
715
716   if (priv->decoder)
717     {
718       charset = pango_fc_decoder_get_charset (priv->decoder, font);
719       return FcCharSetHasChar (charset, wc);
720     }
721
722   return PANGO_FC_FONT_GET_CLASS (font)->has_char (font, wc);
723 }
724
725 /**
726  * pango_fc_font_get_glyph:
727  * @font: a #PangoFcFont
728  * @wc: Unicode character to look up
729  *
730  * Gets the glyph index for a given Unicode character
731  * for @font. If you only want to determine
732  * whether the font has the glyph, use pango_fc_font_has_char().
733  *
734  * Return value: the glyph index, or 0, if the Unicode
735  *   character doesn't exist in the font.
736  *
737  * Since: 1.4
738  **/
739 PangoGlyph
740 pango_fc_font_get_glyph (PangoFcFont *font,
741                          gunichar     wc)
742 {
743   PangoFcFontPrivate *priv = font->priv;
744
745   /* Replace NBSP with a normal space; it should be invariant that
746    * they shape the same other than breaking properties.
747    */
748   if (wc == 0xA0)
749           wc = 0x20;
750
751   if (priv->decoder)
752     return pango_fc_decoder_get_glyph (priv->decoder, font, wc);
753
754   return PANGO_FC_FONT_GET_CLASS (font)->get_glyph (font, wc);
755 }
756
757
758 /**
759  * pango_fc_font_get_unknown_glyph:
760  * @font: a #PangoFcFont
761  * @wc: the Unicode character for which a glyph is needed.
762  *
763  * Returns the index of a glyph suitable for drawing @wc as an
764  * unknown character.
765  *
766  * Use PANGO_GET_UNKNOWN_GLYPH() instead.
767  *
768  * Return value: a glyph index into @font.
769  *
770  * Since: 1.4
771  **/
772 PangoGlyph
773 pango_fc_font_get_unknown_glyph (PangoFcFont *font,
774                                  gunichar     wc)
775 {
776   if (font && PANGO_FC_FONT_GET_CLASS (font)->get_unknown_glyph)
777     return PANGO_FC_FONT_GET_CLASS (font)->get_unknown_glyph (font, wc);
778
779   return PANGO_GET_UNKNOWN_GLYPH (wc);
780 }
781
782 void
783 _pango_fc_font_shutdown (PangoFcFont *font)
784 {
785   g_return_if_fail (PANGO_IS_FC_FONT (font));
786
787   if (PANGO_FC_FONT_GET_CLASS (font)->shutdown)
788     PANGO_FC_FONT_GET_CLASS (font)->shutdown (font);
789 }
790
791 /**
792  * pango_fc_font_kern_glyphs
793  * @font: a #PangoFcFont
794  * @glyphs: a #PangoGlyphString
795  *
796  * Adjust each adjacent pair of glyphs in @glyphs according to
797  * kerning information in @font.
798  *
799  * Since: 1.4
800  **/
801 void
802 pango_fc_font_kern_glyphs (PangoFcFont      *font,
803                            PangoGlyphString *glyphs)
804 {
805   FT_Face face;
806   FT_Error error;
807   FT_Vector kerning;
808   int i;
809   gboolean hinting = font->is_hinted;
810   gboolean scale = FALSE;
811   double xscale = 1;
812   PangoFcFontKey *key;
813
814   g_return_if_fail (PANGO_IS_FC_FONT (font));
815   g_return_if_fail (glyphs != NULL);
816
817   face = PANGO_FC_FONT_LOCK_FACE (font);
818   if (G_UNLIKELY (!face))
819     return;
820
821   if (!FT_HAS_KERNING (face))
822     {
823       PANGO_FC_FONT_UNLOCK_FACE (font);
824       return;
825     }
826
827   /* This is a kludge, and dupped in pango_ot_buffer_output().
828    * Should move the scale factor to PangoFcFont layer. */
829   key = _pango_fc_font_get_font_key (font);
830   if (key) {
831     const PangoMatrix *matrix = pango_fc_font_key_get_matrix (key);
832     PangoMatrix identity = PANGO_MATRIX_INIT;
833     if (G_UNLIKELY (matrix && 0 != memcmp (&identity, matrix, 2 * sizeof (double))))
834       {
835         scale = TRUE;
836         pango_matrix_get_font_scale_factors (matrix, &xscale, NULL);
837         if (xscale) xscale = 1 / xscale;
838       }
839   }
840
841   for (i = 1; i < glyphs->num_glyphs; ++i)
842     {
843       error = FT_Get_Kerning (face,
844                               glyphs->glyphs[i-1].glyph,
845                               glyphs->glyphs[i].glyph,
846                               ft_kerning_default,
847                               &kerning);
848
849       if (error == FT_Err_Ok) {
850         int adjustment = PANGO_UNITS_26_6 (kerning.x);
851
852         if (hinting)
853           adjustment = PANGO_UNITS_ROUND (adjustment);
854         if (G_UNLIKELY (scale))
855           adjustment *= xscale;
856
857         glyphs->glyphs[i-1].geometry.width += adjustment;
858       }
859     }
860
861   PANGO_FC_FONT_UNLOCK_FACE (font);
862 }
863
864 /**
865  * _pango_fc_font_get_decoder
866  * @font: a #PangoFcFont
867  *
868  * This will return any custom decoder set on this font.
869  *
870  * Return value: The custom decoder
871  *
872  * Since: 1.6
873  **/
874
875 PangoFcDecoder *
876 _pango_fc_font_get_decoder (PangoFcFont *font)
877 {
878   PangoFcFontPrivate *priv = font->priv;
879
880   return priv->decoder;
881 }
882
883 /**
884  * _pango_fc_font_set_decoder
885  * @font: a #PangoFcFont
886  * @decoder: a #PangoFcDecoder to set for this font
887  *
888  * This sets a custom decoder for this font.  Any previous decoder
889  * will be released before this one is set.
890  *
891  * Since: 1.6
892  **/
893
894 void
895 _pango_fc_font_set_decoder (PangoFcFont    *font,
896                             PangoFcDecoder *decoder)
897 {
898   PangoFcFontPrivate *priv = font->priv;
899
900   if (priv->decoder)
901     g_object_unref (priv->decoder);
902
903   priv->decoder = decoder;
904
905   if (priv->decoder)
906     g_object_ref (priv->decoder);
907 }
908
909 PangoFcFontKey *
910 _pango_fc_font_get_font_key (PangoFcFont *fcfont)
911 {
912   PangoFcFontPrivate *priv = fcfont->priv;
913
914   return priv->key;
915 }
916
917 void
918 _pango_fc_font_set_font_key (PangoFcFont    *fcfont,
919                              PangoFcFontKey *key)
920 {
921   PangoFcFontPrivate *priv = fcfont->priv;
922
923   priv->key = key;
924 }
925
926 static FT_Glyph_Metrics *
927 get_per_char (FT_Face      face,
928               FT_Int32     load_flags,
929               PangoGlyph   glyph)
930 {
931   FT_Error error;
932   FT_Glyph_Metrics *result;
933
934   error = FT_Load_Glyph (face, glyph, load_flags);
935   if (error == FT_Err_Ok)
936     result = &face->glyph->metrics;
937   else
938     result = NULL;
939
940   return result;
941 }
942
943 /**
944  * pango_fc_font_get_raw_extents:
945  * @fcfont: a #PangoFcFont
946  * @load_flags: flags to pass to FT_Load_Glyph()
947  * @glyph: the glyph index to load
948  * @ink_rect: location to store ink extents of the glyph, or %NULL
949  * @logical_rect: location to store logical extents of the glyph or %NULL
950  *
951  * Gets the extents of a single glyph from a font. The extents are in
952  * user space; that is, they are not transformed by any matrix in effect
953  * for the font.
954  *
955  * Long term, this functionality probably belongs in the default
956  * implementation of the get_glyph_extents() virtual function.
957  * The other possibility would be to to make it public in something
958  * like it's current form, and also expose glyph information
959  * caching functionality similar to pango_ft2_font_set_glyph_info().
960  *
961  * Since: 1.6
962  **/
963 void
964 pango_fc_font_get_raw_extents (PangoFcFont    *fcfont,
965                                FT_Int32        load_flags,
966                                PangoGlyph      glyph,
967                                PangoRectangle *ink_rect,
968                                PangoRectangle *logical_rect)
969 {
970   FT_Glyph_Metrics *gm;
971   FT_Face face;
972
973   g_return_if_fail (PANGO_IS_FC_FONT (fcfont));
974
975   face = PANGO_FC_FONT_LOCK_FACE (fcfont);
976   if (G_UNLIKELY (!face))
977     {
978       /* Get generic unknown-glyph extents. */
979       pango_font_get_glyph_extents (NULL, glyph, ink_rect, logical_rect);
980       return;
981     }
982
983   if (glyph == PANGO_GLYPH_EMPTY)
984     gm = NULL;
985   else
986     gm = get_per_char (face, load_flags, glyph);
987
988   if (gm)
989     {
990       if (ink_rect)
991         {
992           ink_rect->x = PANGO_UNITS_26_6 (gm->horiBearingX);
993           ink_rect->width = PANGO_UNITS_26_6 (gm->width);
994           ink_rect->y = -PANGO_UNITS_26_6 (gm->horiBearingY);
995           ink_rect->height = PANGO_UNITS_26_6 (gm->height);
996         }
997
998       if (logical_rect)
999         {
1000           logical_rect->x = 0;
1001           logical_rect->width = PANGO_UNITS_26_6 (gm->horiAdvance);
1002           if (fcfont->is_hinted ||
1003               (face->face_flags & FT_FACE_FLAG_SCALABLE) == 0)
1004             {
1005               logical_rect->y = - PANGO_UNITS_26_6 (face->size->metrics.ascender);
1006               logical_rect->height = PANGO_UNITS_26_6 (face->size->metrics.ascender - face->size->metrics.descender);
1007             }
1008           else
1009             {
1010               FT_Fixed ascender, descender;
1011
1012               ascender = FT_MulFix (face->ascender, face->size->metrics.y_scale);
1013               descender = FT_MulFix (face->descender, face->size->metrics.y_scale);
1014
1015               logical_rect->y = - PANGO_UNITS_26_6 (ascender);
1016               logical_rect->height = PANGO_UNITS_26_6 (ascender - descender);
1017             }
1018         }
1019     }
1020   else
1021     {
1022       if (ink_rect)
1023         {
1024           ink_rect->x = 0;
1025           ink_rect->width = 0;
1026           ink_rect->y = 0;
1027           ink_rect->height = 0;
1028         }
1029
1030       if (logical_rect)
1031         {
1032           logical_rect->x = 0;
1033           logical_rect->width = 0;
1034           logical_rect->y = 0;
1035           logical_rect->height = 0;
1036         }
1037     }
1038
1039   PANGO_FC_FONT_UNLOCK_FACE (fcfont);
1040 }
1041