Git init
[external/pango1.0.git] / pango / pangoft2.c
1 /* Pango
2  * pangoft2.c: Routines for handling FreeType2 fonts
3  *
4  * Copyright (C) 1999 Red Hat Software
5  * Copyright (C) 2000 Tor Lillqvist
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #include "config.h"
24
25 #include <string.h>
26 #include <stdlib.h>
27 #include <math.h>
28 #include <glib.h>
29 #include <glib/gprintf.h>
30
31 #include "pangoft2.h"
32 #include "pangoft2-private.h"
33 #include "pangofc-fontmap.h"
34 #include "pangofc-private.h"
35
36 /* for compatibility with older freetype versions */
37 #ifndef FT_LOAD_TARGET_MONO
38 #define FT_LOAD_TARGET_MONO  FT_LOAD_MONOCHROME
39 #endif
40
41 #define PANGO_FT2_FONT_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), PANGO_TYPE_FT2_FONT, PangoFT2FontClass))
42 #define PANGO_FT2_IS_FONT_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), PANGO_TYPE_FT2_FONT))
43 #define PANGO_FT2_FONT_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), PANGO_TYPE_FT2_FONT, PangoFT2FontClass))
44
45 typedef struct _PangoFT2FontClass   PangoFT2FontClass;
46
47 struct _PangoFT2FontClass
48 {
49   PangoFcFontClass parent_class;
50 };
51
52 static void     pango_ft2_font_finalize          (GObject        *object);
53
54 static void     pango_ft2_font_get_glyph_extents (PangoFont      *font,
55                                                   PangoGlyph      glyph,
56                                                   PangoRectangle *ink_rect,
57                                                   PangoRectangle *logical_rect);
58
59 static FT_Face  pango_ft2_font_real_lock_face    (PangoFcFont    *font);
60 static void     pango_ft2_font_real_unlock_face  (PangoFcFont    *font);
61
62
63 PangoFT2Font *
64 _pango_ft2_font_new (PangoFT2FontMap *ft2fontmap,
65                      FcPattern       *pattern)
66 {
67   PangoFontMap *fontmap = PANGO_FONT_MAP (ft2fontmap);
68   PangoFT2Font *ft2font;
69   double d;
70
71   g_return_val_if_fail (fontmap != NULL, NULL);
72   g_return_val_if_fail (pattern != NULL, NULL);
73
74   ft2font = (PangoFT2Font *)g_object_new (PANGO_TYPE_FT2_FONT,
75                                           "pattern", pattern,
76                                           "fontmap", fontmap,
77                                           NULL);
78
79   if (FcPatternGetDouble (pattern, FC_PIXEL_SIZE, 0, &d) == FcResultMatch)
80     ft2font->size = d*PANGO_SCALE;
81
82   return ft2font;
83 }
84
85 static void
86 load_fallback_face (PangoFT2Font *ft2font,
87                     const char   *original_file)
88 {
89   PangoFcFont *fcfont = PANGO_FC_FONT (ft2font);
90   FcPattern *sans;
91   FcPattern *matched;
92   FcResult result;
93   FT_Error error;
94   FcChar8 *filename2 = NULL;
95   gchar *name;
96   int id;
97
98   sans = FcPatternBuild (NULL,
99                          FC_FAMILY,     FcTypeString, "sans",
100                          FC_PIXEL_SIZE, FcTypeDouble, (double)ft2font->size / PANGO_SCALE,
101                          NULL);
102
103   _pango_ft2_font_map_default_substitute ((PangoFcFontMap *)fcfont->fontmap, sans);
104
105   matched = FcFontMatch (NULL, sans, &result);
106
107   if (FcPatternGetString (matched, FC_FILE, 0, &filename2) != FcResultMatch)
108     goto bail1;
109
110   if (FcPatternGetInteger (matched, FC_INDEX, 0, &id) != FcResultMatch)
111     goto bail1;
112
113   error = FT_New_Face (_pango_ft2_font_map_get_library (fcfont->fontmap),
114                        (char *) filename2, id, &ft2font->face);
115
116
117   if (error)
118     {
119     bail1:
120       name = pango_font_description_to_string (fcfont->description);
121       g_error ("Unable to open font file %s for font %s, exiting\n", filename2, name);
122     }
123   else
124     {
125       name = pango_font_description_to_string (fcfont->description);
126       g_warning ("Unable to open font file %s for font %s, falling back to %s\n", original_file, name, filename2);
127       g_free (name);
128     }
129
130   FcPatternDestroy (sans);
131   FcPatternDestroy (matched);
132 }
133
134 static void
135 set_transform (PangoFT2Font *ft2font)
136 {
137   PangoFcFont *fcfont = (PangoFcFont *)ft2font;
138   FcMatrix *fc_matrix;
139
140   if (FcPatternGetMatrix (fcfont->font_pattern, FC_MATRIX, 0, &fc_matrix) == FcResultMatch)
141     {
142       FT_Matrix ft_matrix;
143
144       ft_matrix.xx = 0x10000L * fc_matrix->xx;
145       ft_matrix.yy = 0x10000L * fc_matrix->yy;
146       ft_matrix.xy = 0x10000L * fc_matrix->xy;
147       ft_matrix.yx = 0x10000L * fc_matrix->yx;
148
149       FT_Set_Transform (ft2font->face, &ft_matrix, NULL);
150     }
151 }
152
153 /**
154  * pango_ft2_font_get_face:
155  * @font: a #PangoFont
156  *
157  * Returns the native FreeType2 <type>FT_Face</type> structure used for this #PangoFont.
158  * This may be useful if you want to use FreeType2 functions directly.
159  *
160  * Use pango_fc_font_lock_face() instead; when you are done with a
161  * face from pango_fc_font_lock_face() you must call
162  * pango_fc_font_unlock_face().
163  *
164  * Return value: a pointer to a <type>FT_Face</type> structure, with the size set correctly,
165  *               or %NULL if @font is %NULL.
166  **/
167 FT_Face
168 pango_ft2_font_get_face (PangoFont *font)
169 {
170   PangoFT2Font *ft2font = (PangoFT2Font *)font;
171   PangoFcFont *fcfont = (PangoFcFont *)font;
172   FT_Error error;
173   FcPattern *pattern;
174   FcChar8 *filename;
175   FcBool antialias, hinting, autohint;
176   int hintstyle;
177   int id;
178
179   if (G_UNLIKELY (!font))
180     return NULL;
181
182   pattern = fcfont->font_pattern;
183
184   if (!ft2font->face)
185     {
186       ft2font->load_flags = 0;
187
188       /* disable antialiasing if requested */
189       if (FcPatternGetBool (pattern,
190                             FC_ANTIALIAS, 0, &antialias) != FcResultMatch)
191         antialias = FcTrue;
192
193       if (antialias)
194         ft2font->load_flags |= FT_LOAD_NO_BITMAP;
195       else
196         ft2font->load_flags |= FT_LOAD_TARGET_MONO;
197
198       /* disable hinting if requested */
199       if (FcPatternGetBool (pattern,
200                             FC_HINTING, 0, &hinting) != FcResultMatch)
201         hinting = FcTrue;
202
203 #ifdef FC_HINT_STYLE
204       if (FcPatternGetInteger (pattern, FC_HINT_STYLE, 0, &hintstyle) != FcResultMatch)
205         hintstyle = FC_HINT_FULL;
206
207       if (!hinting || hintstyle == FC_HINT_NONE)
208           ft2font->load_flags |= FT_LOAD_NO_HINTING;
209       
210       switch (hintstyle) {
211       case FC_HINT_SLIGHT:
212       case FC_HINT_MEDIUM:
213         ft2font->load_flags |= FT_LOAD_TARGET_LIGHT;
214         break;
215       default:
216         ft2font->load_flags |= FT_LOAD_TARGET_NORMAL;
217         break;
218       }
219 #else
220       if (!hinting)
221           ft2font->load_flags |= FT_LOAD_NO_HINTING;
222 #endif
223
224       /* force autohinting if requested */
225       if (FcPatternGetBool (pattern,
226                             FC_AUTOHINT, 0, &autohint) != FcResultMatch)
227         autohint = FcFalse;
228
229       if (autohint)
230         ft2font->load_flags |= FT_LOAD_FORCE_AUTOHINT;
231
232       if (FcPatternGetString (pattern, FC_FILE, 0, &filename) != FcResultMatch)
233               goto bail0;
234
235       if (FcPatternGetInteger (pattern, FC_INDEX, 0, &id) != FcResultMatch)
236               goto bail0;
237
238       error = FT_New_Face (_pango_ft2_font_map_get_library (fcfont->fontmap),
239                            (char *) filename, id, &ft2font->face);
240       if (error != FT_Err_Ok)
241         {
242         bail0:
243           load_fallback_face (ft2font, (char *) filename);
244         }
245
246       g_assert (ft2font->face);
247
248       set_transform (ft2font);
249
250       error = FT_Set_Char_Size (ft2font->face,
251                                 PANGO_PIXELS_26_6 (ft2font->size),
252                                 PANGO_PIXELS_26_6 (ft2font->size),
253                                 0, 0);
254       if (error)
255         g_warning ("Error in FT_Set_Char_Size: %d", error);
256     }
257
258   return ft2font->face;
259 }
260
261 G_DEFINE_TYPE (PangoFT2Font, pango_ft2_font, PANGO_TYPE_FC_FONT)
262
263 static void
264 pango_ft2_font_init (PangoFT2Font *ft2font)
265 {
266   ft2font->face = NULL;
267
268   ft2font->size = 0;
269
270   ft2font->glyph_info = g_hash_table_new (NULL, NULL);
271 }
272
273 static void
274 pango_ft2_font_class_init (PangoFT2FontClass *class)
275 {
276   GObjectClass *object_class = G_OBJECT_CLASS (class);
277   PangoFontClass *font_class = PANGO_FONT_CLASS (class);
278   PangoFcFontClass *fc_font_class = PANGO_FC_FONT_CLASS (class);
279
280   object_class->finalize = pango_ft2_font_finalize;
281
282   font_class->get_glyph_extents = pango_ft2_font_get_glyph_extents;
283
284   fc_font_class->lock_face = pango_ft2_font_real_lock_face;
285   fc_font_class->unlock_face = pango_ft2_font_real_unlock_face;
286 }
287
288 static PangoFT2GlyphInfo *
289 pango_ft2_font_get_glyph_info (PangoFont   *font,
290                                PangoGlyph   glyph,
291                                gboolean     create)
292 {
293   PangoFT2Font *ft2font = (PangoFT2Font *)font;
294   PangoFcFont *fcfont = (PangoFcFont *)font;
295   PangoFT2GlyphInfo *info;
296
297   info = g_hash_table_lookup (ft2font->glyph_info, GUINT_TO_POINTER (glyph));
298
299   if ((info == NULL) && create)
300     {
301       info = g_slice_new0 (PangoFT2GlyphInfo);
302
303       pango_fc_font_get_raw_extents (fcfont, ft2font->load_flags,
304                                      glyph,
305                                      &info->ink_rect,
306                                      &info->logical_rect);
307
308       g_hash_table_insert (ft2font->glyph_info, GUINT_TO_POINTER(glyph), info);
309     }
310
311   return info;
312 }
313
314 static void
315 pango_ft2_font_get_glyph_extents (PangoFont      *font,
316                                   PangoGlyph      glyph,
317                                   PangoRectangle *ink_rect,
318                                   PangoRectangle *logical_rect)
319 {
320   PangoFT2GlyphInfo *info;
321   gboolean empty = FALSE;
322
323   if (glyph == PANGO_GLYPH_EMPTY)
324     {
325       glyph = pango_fc_font_get_glyph ((PangoFcFont *) font, ' ');
326       empty = TRUE;
327     }
328
329   if (glyph & PANGO_GLYPH_UNKNOWN_FLAG)
330     {
331       PangoFontMetrics *metrics = pango_font_get_metrics (font, NULL);
332
333       if (metrics)
334         {
335           if (ink_rect)
336             {
337               ink_rect->x = PANGO_SCALE;
338               ink_rect->width = metrics->approximate_char_width - 2 * PANGO_SCALE;
339               ink_rect->y = - (metrics->ascent - PANGO_SCALE);
340               ink_rect->height = metrics->ascent + metrics->descent - 2 * PANGO_SCALE;
341             }
342           if (logical_rect)
343             {
344               logical_rect->x = 0;
345               logical_rect->width = metrics->approximate_char_width;
346               logical_rect->y = -metrics->ascent;
347               logical_rect->height = metrics->ascent + metrics->descent;
348             }
349
350           pango_font_metrics_unref (metrics);
351         }
352       else
353         {
354           if (ink_rect)
355             ink_rect->x = ink_rect->y = ink_rect->height = ink_rect->width = 0;
356           if (logical_rect)
357             logical_rect->x = logical_rect->y = logical_rect->height = logical_rect->width = 0;
358         }
359       return;
360     }
361
362   info = pango_ft2_font_get_glyph_info (font, glyph, TRUE);
363
364   if (ink_rect)
365     *ink_rect = info->ink_rect;
366   if (logical_rect)
367     *logical_rect = info->logical_rect;
368
369   if (empty)
370     {
371       if (ink_rect)
372         ink_rect->x = ink_rect->y = ink_rect->height = ink_rect->width = 0;
373       if (logical_rect)
374         logical_rect->x = logical_rect->width = 0;
375       return;
376     }
377 }
378
379 /**
380  * pango_ft2_font_get_kerning:
381  * @font: a #PangoFont
382  * @left: the left #PangoGlyph
383  * @right: the right #PangoGlyph
384  *
385  * Retrieves kerning information for a combination of two glyphs.
386  *
387  * Use pango_fc_font_kern_glyphs() instead.
388  *
389  * Return value: The amount of kerning (in Pango units) to apply for
390  * the given combination of glyphs.
391  **/
392 int
393 pango_ft2_font_get_kerning (PangoFont *font,
394                             PangoGlyph left,
395                             PangoGlyph right)
396 {
397   PangoFcFont *fc_font = PANGO_FC_FONT (font);
398
399   FT_Face face;
400   FT_Error error;
401   FT_Vector kerning;
402
403   face = pango_fc_font_lock_face (fc_font);
404   if (!face)
405     return 0;
406
407   if (!FT_HAS_KERNING (face))
408     {
409       pango_fc_font_unlock_face (fc_font);
410       return 0;
411     }
412
413   error = FT_Get_Kerning (face, left, right, ft_kerning_default, &kerning);
414   if (error != FT_Err_Ok)
415     {
416       pango_fc_font_unlock_face (fc_font);
417       return 0;
418     }
419
420   pango_fc_font_unlock_face (fc_font);
421   return PANGO_UNITS_26_6 (kerning.x);
422 }
423
424 static FT_Face
425 pango_ft2_font_real_lock_face (PangoFcFont *font)
426 {
427   return pango_ft2_font_get_face ((PangoFont *)font);
428 }
429
430 static void
431 pango_ft2_font_real_unlock_face (PangoFcFont *font G_GNUC_UNUSED)
432 {
433 }
434
435 static gboolean
436 pango_ft2_free_glyph_info_callback (gpointer key G_GNUC_UNUSED,
437                                     gpointer value,
438                                     gpointer data)
439 {
440   PangoFT2Font *font = PANGO_FT2_FONT (data);
441   PangoFT2GlyphInfo *info = value;
442
443   if (font->glyph_cache_destroy && info->cached_glyph)
444     (*font->glyph_cache_destroy) (info->cached_glyph);
445
446   g_slice_free (PangoFT2GlyphInfo, info);
447   return TRUE;
448 }
449
450 static void
451 pango_ft2_font_finalize (GObject *object)
452 {
453   PangoFT2Font *ft2font = (PangoFT2Font *)object;
454
455   if (ft2font->face)
456     {
457       FT_Done_Face (ft2font->face);
458       ft2font->face = NULL;
459     }
460
461   g_hash_table_foreach_remove (ft2font->glyph_info,
462                                pango_ft2_free_glyph_info_callback, object);
463   g_hash_table_destroy (ft2font->glyph_info);
464
465   G_OBJECT_CLASS (pango_ft2_font_parent_class)->finalize (object);
466 }
467
468 /**
469  * pango_ft2_font_get_coverage:
470  * @font: a #PangoFT2Font.
471  * @language: a language tag.
472  * @returns: a #PangoCoverage.
473  *
474  * Gets the #PangoCoverage for a #PangoFT2Font. Use
475  * pango_font_get_coverage() instead.
476  **/
477 PangoCoverage *
478 pango_ft2_font_get_coverage (PangoFont     *font,
479                              PangoLanguage *language)
480 {
481   return pango_font_get_coverage (font, language);
482 }
483
484 /* Utility functions */
485
486 /**
487  * pango_ft2_get_unknown_glyph:
488  * @font: a #PangoFont
489  *
490  * Return the index of a glyph suitable for drawing unknown characters with
491  * @font, or %PANGO_GLYPH_EMPTY if no suitable glyph found.
492  *
493  * If you want to draw an unknown-box for a character that is not covered
494  * by the font,
495  * use PANGO_GET_UNKNOWN_GLYPH() instead.
496  *
497  * Return value: a glyph index into @font, or %PANGO_GLYPH_EMPTY
498  **/
499 PangoGlyph
500 pango_ft2_get_unknown_glyph (PangoFont *font)
501 {
502   FT_Face face = pango_ft2_font_get_face (font);
503   if (face && FT_IS_SFNT (face))
504     /* TrueType fonts have an 'unknown glyph' box on glyph index 0 */
505     return 0;
506   else
507     return PANGO_GLYPH_EMPTY;
508 }
509
510 typedef struct
511 {
512   FT_Error     code;
513   const char   msg[40];
514 } ft_error_description;
515
516 static int
517 ft_error_compare (const void *pkey,
518                   const void *pbase)
519 {
520   return ((ft_error_description *) pkey)->code - ((ft_error_description *) pbase)->code;
521 }
522
523 G_CONST_RETURN char *
524 _pango_ft2_ft_strerror (FT_Error error)
525 {
526 #undef __FTERRORS_H__
527 #define FT_ERRORDEF( e, v, s )  { e, s },
528 #define FT_ERROR_START_LIST  {
529 #define FT_ERROR_END_LIST    };
530
531   static const ft_error_description ft_errors[] =
532 #include FT_ERRORS_H
533
534 #undef FT_ERRORDEF
535 #undef FT_ERROR_START_LIST
536 #undef FT_ERROR_END_LIST
537
538   ft_error_description *found =
539     bsearch (&error, ft_errors, G_N_ELEMENTS (ft_errors),
540              sizeof (ft_errors[0]), ft_error_compare);
541   if (found != NULL)
542     return found->msg;
543   else
544     {
545       static char *default_msg = NULL;
546
547       if (!default_msg)
548         default_msg = g_malloc (60);
549
550       g_sprintf (default_msg, "Unknown FreeType2 error %#x", error);
551       return default_msg;
552     }
553 }
554
555 void *
556 _pango_ft2_font_get_cache_glyph_data (PangoFont *font,
557                                      int        glyph_index)
558 {
559   PangoFT2GlyphInfo *info;
560
561   if (!PANGO_FT2_IS_FONT (font))
562     return NULL;
563
564   info = pango_ft2_font_get_glyph_info (font, glyph_index, FALSE);
565
566   if (info == NULL)
567     return NULL;
568
569   return info->cached_glyph;
570 }
571
572 void
573 _pango_ft2_font_set_cache_glyph_data (PangoFont     *font,
574                                      int            glyph_index,
575                                      void          *cached_glyph)
576 {
577   PangoFT2GlyphInfo *info;
578
579   if (!PANGO_FT2_IS_FONT (font))
580     return;
581
582   info = pango_ft2_font_get_glyph_info (font, glyph_index, TRUE);
583
584   info->cached_glyph = cached_glyph;
585
586   /* TODO: Implement limiting of the number of cached glyphs */
587 }
588
589 void
590 _pango_ft2_font_set_glyph_cache_destroy (PangoFont      *font,
591                                          GDestroyNotify  destroy_notify)
592 {
593   if (!PANGO_FT2_IS_FONT (font))
594     return;
595
596   PANGO_FT2_FONT (font)->glyph_cache_destroy = destroy_notify;
597 }