Git init
[external/pango1.0.git] / pango / pangoxft-font.c
1 /* Pango
2  * pangoxft-font.c: Routines for handling X fonts
3  *
4  * Copyright (C) 2000 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 <stdlib.h>
25
26 #include "pangofc-fontmap.h"
27 #include "pangoxft-private.h"
28 #include "pangofc-private.h"
29
30 #define PANGO_XFT_FONT_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), PANGO_TYPE_XFT_FONT, PangoXftFontClass))
31 #define PANGO_XFT_IS_FONT_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), PANGO_TYPE_XFT_FONT))
32 #define PANGO_XFT_FONT_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), PANGO_TYPE_XFT_FONT, PangoXftFontClass))
33
34 typedef struct _PangoXftFontClass    PangoXftFontClass;
35
36 struct _PangoXftFontClass
37 {
38   PangoFcFontClass  parent_class;
39 };
40
41 static void pango_xft_font_finalize (GObject *object);
42
43 static void                  pango_xft_font_get_glyph_extents (PangoFont        *font,
44                                                                PangoGlyph        glyph,
45                                                                PangoRectangle   *ink_rect,
46                                                                PangoRectangle   *logical_rect);
47
48 static FT_Face    pango_xft_font_real_lock_face         (PangoFcFont      *font);
49 static void       pango_xft_font_real_unlock_face       (PangoFcFont      *font);
50 static gboolean   pango_xft_font_real_has_char          (PangoFcFont      *font,
51                                                          gunichar          wc);
52 static guint      pango_xft_font_real_get_glyph         (PangoFcFont      *font,
53                                                          gunichar          wc);
54 static void       pango_xft_font_real_shutdown          (PangoFcFont      *font);
55
56 static XftFont *xft_font_get_font (PangoFont *font);
57
58 G_DEFINE_TYPE (PangoXftFont, pango_xft_font, PANGO_TYPE_FC_FONT)
59
60 static void
61 pango_xft_font_class_init (PangoXftFontClass *class)
62 {
63   GObjectClass *object_class = G_OBJECT_CLASS (class);
64   PangoFontClass *font_class = PANGO_FONT_CLASS (class);
65   PangoFcFontClass *fc_font_class = PANGO_FC_FONT_CLASS (class);
66
67   object_class->finalize = pango_xft_font_finalize;
68
69   font_class->get_glyph_extents = pango_xft_font_get_glyph_extents;
70
71   fc_font_class->lock_face = pango_xft_font_real_lock_face;
72   fc_font_class->unlock_face = pango_xft_font_real_unlock_face;
73   fc_font_class->has_char = pango_xft_font_real_has_char;
74   fc_font_class->get_glyph = pango_xft_font_real_get_glyph;
75   fc_font_class->shutdown = pango_xft_font_real_shutdown;
76 }
77
78 static void
79 pango_xft_font_init (PangoXftFont *xftfont G_GNUC_UNUSED)
80 {
81 }
82
83 PangoXftFont *
84 _pango_xft_font_new (PangoXftFontMap *xftfontmap,
85                      FcPattern       *pattern)
86 {
87   PangoFontMap *fontmap = PANGO_FONT_MAP (xftfontmap);
88   PangoXftFont *xfont;
89
90   g_return_val_if_fail (fontmap != NULL, NULL);
91   g_return_val_if_fail (pattern != NULL, NULL);
92
93   xfont = (PangoXftFont *)g_object_new (PANGO_TYPE_XFT_FONT,
94                                         "pattern", pattern,
95                                         "fontmap", fontmap,
96                                         NULL);
97
98   /* Hack to force hinting of vertical metrics; hinting off for
99    * a Xft font just means to not hint outlines, but we still
100    * want integer line spacing, underline positions, etc
101    */
102   PANGO_FC_FONT (xfont)->is_hinted = TRUE;
103
104   xfont->xft_font = NULL;
105
106   return xfont;
107 }
108
109 /**
110  * _pango_xft_font_get_mini_font:
111  * @xfont: a #PangoXftFont
112  *
113  * Gets the font used for drawing the digits in the
114  * missing-character hex squares
115  *
116  * Return value: the #PangoFont used for the digits; this
117  *  value is associated with the main font and will be freed
118  *  along with the main font.
119  **/
120 PangoFont *
121 _pango_xft_font_get_mini_font (PangoXftFont *xfont)
122 {
123   PangoFcFont *fcfont = (PangoFcFont *)xfont;
124
125   if (!fcfont || !fcfont->fontmap)
126     return NULL;
127
128   if (!xfont->mini_font)
129     {
130       Display *display;
131       int screen;
132       PangoFontDescription *desc = pango_font_description_new ();
133       PangoContext *context;
134       int i;
135       int width = 0, height = 0;
136       XGlyphInfo extents;
137       XftFont *mini_xft;
138       int new_size;
139
140       _pango_xft_font_map_get_info (fcfont->fontmap, &display, &screen);
141
142       context = pango_font_map_create_context (pango_xft_get_font_map (display, screen));
143       pango_context_set_language (context, pango_language_from_string ("en"));
144
145       pango_font_description_set_family_static (desc, "monospace");
146
147       new_size = pango_font_description_get_size (fcfont->description) / 2;
148
149       if (pango_font_description_get_size_is_absolute (fcfont->description))
150         pango_font_description_set_absolute_size (desc, new_size);
151       else
152         pango_font_description_set_size (desc, new_size);
153
154       xfont->mini_font = pango_font_map_load_font (fcfont->fontmap, context, desc);
155       pango_font_description_free (desc);
156       g_object_unref (context);
157
158       if (!xfont->mini_font)
159         return NULL;
160
161       mini_xft = xft_font_get_font (xfont->mini_font);
162
163       for (i = 0 ; i < 16 ; i++)
164         {
165           char c = i < 10 ? '0' + i : 'A' + i - 10;
166           XftTextExtents8 (display, mini_xft, (FcChar8 *) &c, 1, &extents);
167           width = MAX (width, extents.width);
168           height = MAX (height, extents.height);
169         }
170
171       xfont->mini_width = PANGO_SCALE * width;
172       xfont->mini_height = PANGO_SCALE * height;
173       xfont->mini_pad = PANGO_SCALE * MIN (height / 2, MAX ((int)(2.2 * height + 27) / 28, 1));
174     }
175
176   return xfont->mini_font;
177 }
178
179 static void
180 pango_xft_font_finalize (GObject *object)
181 {
182   PangoXftFont *xfont = (PangoXftFont *)object;
183   PangoFcFont *fcfont = (PangoFcFont *)object;
184
185   if (xfont->mini_font)
186     g_object_unref (xfont->mini_font);
187
188   if (xfont->xft_font)
189     {
190       Display *display;
191
192       _pango_xft_font_map_get_info (fcfont->fontmap, &display, NULL);
193       XftFontClose (display, xfont->xft_font);
194     }
195
196   if (xfont->glyph_info)
197     g_hash_table_destroy (xfont->glyph_info);
198
199   G_OBJECT_CLASS (pango_xft_font_parent_class)->finalize (object);
200 }
201
202 static void
203 get_glyph_extents_missing (PangoXftFont    *xfont,
204                            PangoGlyph       glyph,
205                            PangoRectangle  *ink_rect,
206                            PangoRectangle  *logical_rect)
207
208 {
209   PangoFont *font = PANGO_FONT (xfont);
210   XftFont *xft_font = xft_font_get_font (font);
211   gunichar ch;
212   gint cols;
213   
214   ch = glyph & ~PANGO_GLYPH_UNKNOWN_FLAG;
215
216   if (G_UNLIKELY (glyph == PANGO_GLYPH_INVALID_INPUT || ch > 0x10FFFF))
217     cols = 1;
218   else
219     cols = ch > 0xffff ? 3 : 2;
220
221   _pango_xft_font_get_mini_font (xfont);
222
223   if (ink_rect)
224     {
225       ink_rect->x = 0;
226       ink_rect->y = - PANGO_SCALE * xft_font->ascent + PANGO_SCALE * (((xft_font->ascent + xft_font->descent) - (xfont->mini_height * 2 + xfont->mini_pad * 5 + PANGO_SCALE / 2) / PANGO_SCALE) / 2);
227       ink_rect->width = xfont->mini_width * cols + xfont->mini_pad * (2 * cols + 1);
228       ink_rect->height = xfont->mini_height * 2 + xfont->mini_pad * 5;
229     }
230
231   if (logical_rect)
232     {
233       logical_rect->x = 0;
234       logical_rect->y = - PANGO_SCALE * xft_font->ascent;
235       logical_rect->width = xfont->mini_width * cols + xfont->mini_pad * (2 * cols + 2);
236       logical_rect->height = (xft_font->ascent + xft_font->descent) * PANGO_SCALE;
237     }
238 }
239
240 static void
241 get_glyph_extents_xft (PangoFcFont      *fcfont,
242                        PangoGlyph        glyph,
243                        PangoRectangle   *ink_rect,
244                        PangoRectangle   *logical_rect)
245 {
246   XftFont *xft_font = xft_font_get_font ((PangoFont *)fcfont);
247   XGlyphInfo extents;
248   Display *display;
249   FT_UInt ft_glyph = glyph;
250
251   _pango_xft_font_map_get_info (fcfont->fontmap, &display, NULL);
252
253   XftGlyphExtents (display, xft_font, &ft_glyph, 1, &extents);
254
255   if (ink_rect)
256     {
257       ink_rect->x = - extents.x * PANGO_SCALE; /* Xft crack-rock sign choice */
258       ink_rect->y = - extents.y * PANGO_SCALE; /*             "              */
259       ink_rect->width = extents.width * PANGO_SCALE;
260       ink_rect->height = extents.height * PANGO_SCALE;
261     }
262
263   if (logical_rect)
264     {
265       logical_rect->x = 0;
266       logical_rect->y = - xft_font->ascent * PANGO_SCALE;
267       logical_rect->width = extents.xOff * PANGO_SCALE;
268       logical_rect->height = (xft_font->ascent + xft_font->descent) * PANGO_SCALE;
269     }
270 }
271
272 typedef struct
273 {
274   PangoRectangle ink_rect;
275   PangoRectangle logical_rect;
276 } Extents;
277
278 static void
279 extents_free (Extents *ext)
280 {
281   g_slice_free (Extents, ext);
282 }
283
284 static void
285 get_glyph_extents_raw (PangoXftFont     *xfont,
286                        PangoGlyph        glyph,
287                        PangoRectangle   *ink_rect,
288                        PangoRectangle   *logical_rect)
289 {
290   Extents *extents;
291
292   if (!xfont->glyph_info)
293     xfont->glyph_info = g_hash_table_new_full (NULL, NULL,
294                                                NULL, (GDestroyNotify)extents_free);
295
296   extents = g_hash_table_lookup (xfont->glyph_info,
297                                  GUINT_TO_POINTER (glyph));
298
299   if (!extents)
300     {
301       extents = g_slice_new (Extents);
302
303       pango_fc_font_get_raw_extents (PANGO_FC_FONT (xfont),
304                                      FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING,
305                                      glyph,
306                                      &extents->ink_rect,
307                                      &extents->logical_rect);
308
309       g_hash_table_insert (xfont->glyph_info,
310                            GUINT_TO_POINTER (glyph),
311                            extents);
312     }
313
314   if (ink_rect)
315     *ink_rect = extents->ink_rect;
316
317   if (logical_rect)
318     *logical_rect = extents->logical_rect;
319 }
320
321 static void
322 pango_xft_font_get_glyph_extents (PangoFont        *font,
323                                   PangoGlyph        glyph,
324                                   PangoRectangle   *ink_rect,
325                                   PangoRectangle   *logical_rect)
326 {
327   PangoXftFont *xfont = (PangoXftFont *)font;
328   PangoFcFont *fcfont = PANGO_FC_FONT (font);
329   gboolean empty = FALSE;
330
331   if (G_UNLIKELY (!fcfont->fontmap))    /* Display closed */
332     {
333       if (ink_rect)
334         ink_rect->x = ink_rect->width = ink_rect->y = ink_rect->height = 0;
335       if (logical_rect)
336         logical_rect->x = logical_rect->width = logical_rect->y = logical_rect->height = 0;
337       return;
338     }
339
340   if (glyph == PANGO_GLYPH_EMPTY)
341     {
342       glyph = pango_fc_font_get_glyph (fcfont, ' ');
343       empty = TRUE;
344     }
345
346   if (glyph & PANGO_GLYPH_UNKNOWN_FLAG)
347     {
348       get_glyph_extents_missing (xfont, glyph, ink_rect, logical_rect);
349     }
350   else
351     {
352       if (!fcfont->is_transformed)
353         get_glyph_extents_xft (fcfont, glyph, ink_rect, logical_rect);
354       else
355         get_glyph_extents_raw (xfont, glyph, ink_rect, logical_rect);
356     }
357
358   if (empty)
359     {
360       if (ink_rect)
361         ink_rect->x = ink_rect->y = ink_rect->height = ink_rect->width = 0;
362       if (logical_rect)
363         logical_rect->x = logical_rect->width = 0;
364       return;
365     }
366 }
367
368 static void
369 load_fallback_font (PangoXftFont *xfont)
370 {
371   PangoFcFont *fcfont = PANGO_FC_FONT (xfont);
372   Display *display;
373   int screen;
374   XftFont *xft_font;
375   gboolean size_is_absolute;
376   double size;
377
378   _pango_xft_font_map_get_info (fcfont->fontmap, &display, &screen);
379
380   size_is_absolute = pango_font_description_get_size_is_absolute (fcfont->description);
381   size = pango_font_description_get_size (fcfont->description) / PANGO_SCALE;
382
383   xft_font = XftFontOpen (display,  screen,
384                           FC_FAMILY, FcTypeString, "sans",
385                           size_is_absolute ? FC_PIXEL_SIZE : FC_SIZE, FcTypeDouble, size,
386                           NULL);
387
388   xfont->xft_font = xft_font;
389 }
390
391 static XftFont *
392 xft_font_get_font (PangoFont *font)
393 {
394   PangoXftFont *xfont;
395   PangoFcFont *fcfont;
396   Display *display;
397   int screen;
398
399   xfont = (PangoXftFont *)font;
400   fcfont = (PangoFcFont *)font;
401
402   if (G_UNLIKELY (xfont->xft_font == NULL))
403     {
404       FcPattern *pattern = FcPatternDuplicate (fcfont->font_pattern);
405       FcPatternDel (pattern, FC_SPACING);
406
407       _pango_xft_font_map_get_info (fcfont->fontmap, &display, &screen);
408
409       xfont->xft_font = XftFontOpenPattern (display, pattern);
410       if (!xfont->xft_font)
411         {
412           gchar *name = pango_font_description_to_string (fcfont->description);
413           g_warning ("Cannot open font file for font %s", name);
414           g_free (name);
415
416           load_fallback_font (xfont);
417         }
418     }
419
420   return xfont->xft_font;
421 }
422
423 static FT_Face
424 pango_xft_font_real_lock_face (PangoFcFont *font)
425 {
426   XftFont *xft_font = xft_font_get_font ((PangoFont *)font);
427
428   return XftLockFace (xft_font);
429 }
430
431 static void
432 pango_xft_font_real_unlock_face (PangoFcFont *font)
433 {
434   XftFont *xft_font = xft_font_get_font ((PangoFont *)font);
435
436   XftUnlockFace (xft_font);
437 }
438
439 static gboolean
440 pango_xft_font_real_has_char (PangoFcFont *font,
441                               gunichar     wc)
442 {
443   XftFont *xft_font = xft_font_get_font ((PangoFont *)font);
444
445   return XftCharExists (NULL, xft_font, wc);
446 }
447
448 static guint
449 pango_xft_font_real_get_glyph (PangoFcFont *font,
450                                gunichar     wc)
451 {
452   XftFont *xft_font = xft_font_get_font ((PangoFont *)font);
453
454   return XftCharIndex (NULL, xft_font, wc);
455 }
456
457 static void
458 pango_xft_font_real_shutdown (PangoFcFont *fcfont)
459 {
460   PangoXftFont *xfont = PANGO_XFT_FONT (fcfont);
461
462   if (xfont->xft_font)
463     {
464       Display *display;
465
466       _pango_xft_font_map_get_info (fcfont->fontmap, &display, NULL);
467       XftFontClose (display, xfont->xft_font);
468       xfont->xft_font = NULL;
469     }
470 }
471
472 /**
473  * pango_xft_font_get_font:
474  * @font: a #PangoFont.
475  *
476  * Returns the XftFont of a font.
477  *
478  * Return value: the XftFont associated to @font, or %NULL if @font is %NULL.
479  **/
480 XftFont *
481 pango_xft_font_get_font (PangoFont *font)
482 {
483   if (G_UNLIKELY (!font))
484     return NULL;
485
486   return xft_font_get_font (font);
487 }
488
489 /**
490  * pango_xft_font_get_display:
491  * @font: a #PangoFont.
492  *
493  * Returns the X display of the XftFont of a font.
494  *
495  * Return value: the X display of the XftFont associated to @font.
496  **/
497 Display *
498 pango_xft_font_get_display (PangoFont *font)
499 {
500   PangoFcFont *fcfont;
501   Display *display;
502
503   g_return_val_if_fail (PANGO_XFT_IS_FONT (font), NULL);
504
505   fcfont = PANGO_FC_FONT (font);
506   _pango_xft_font_map_get_info (fcfont->fontmap, &display, NULL);
507
508   return display;
509 }
510
511 /**
512  * pango_xft_font_get_unknown_glyph:
513  * @font: a #PangoFont.
514  * @wc: the Unicode character for which a glyph is needed.
515  *
516  * Returns the index of a glyph suitable for drawing @wc as an
517  * unknown character.
518  *
519  * Use PANGO_GET_UNKNOWN_GLYPH() instead.
520  *
521  * Return value: a glyph index into @font.
522  **/
523 PangoGlyph
524 pango_xft_font_get_unknown_glyph (PangoFont *font,
525                                   gunichar   wc)
526 {
527   g_return_val_if_fail (PANGO_XFT_IS_FONT (font), PANGO_GLYPH_EMPTY);
528
529   return pango_fc_font_get_unknown_glyph (PANGO_FC_FONT (font), wc);
530 }
531
532 /**
533  * pango_xft_font_lock_face:
534  * @font: a #PangoFont.
535  *
536  * Gets the FreeType <type>FT_Face</type> associated with a font,
537  * This face will be kept around until you call
538  * pango_xft_font_unlock_face().
539  *
540  * Use pango_fc_font_lock_face() instead.
541  *
542  * Return value: the FreeType <type>FT_Face</type> associated with @font.
543  *
544  * Since: 1.2
545  **/
546 FT_Face
547 pango_xft_font_lock_face (PangoFont *font)
548 {
549   g_return_val_if_fail (PANGO_XFT_IS_FONT (font), NULL);
550
551   return pango_fc_font_lock_face (PANGO_FC_FONT (font));
552 }
553
554 /**
555  * pango_xft_font_unlock_face:
556  * @font: a #PangoFont.
557  *
558  * Releases a font previously obtained with
559  * pango_xft_font_lock_face().
560  *
561  * Use pango_fc_font_unlock_face() instead.
562  *
563  * Since: 1.2
564  **/
565 void
566 pango_xft_font_unlock_face (PangoFont *font)
567 {
568   g_return_if_fail (PANGO_XFT_IS_FONT (font));
569
570   pango_fc_font_unlock_face (PANGO_FC_FONT (font));
571 }
572
573 /**
574  * pango_xft_font_get_glyph:
575  * @font: a #PangoFont for the Xft backend
576  * @wc: Unicode codepoint to look up
577  *
578  * Gets the glyph index for a given Unicode character
579  * for @font. If you only want to determine
580  * whether the font has the glyph, use pango_xft_font_has_char().
581  *
582  * Use pango_fc_font_get_glyph() instead.
583  *
584  * Return value: the glyph index, or 0, if the Unicode
585  *  character does not exist in the font.
586  *
587  * Since: 1.2
588  **/
589 guint
590 pango_xft_font_get_glyph (PangoFont *font,
591                           gunichar   wc)
592 {
593   g_return_val_if_fail (PANGO_XFT_IS_FONT (font), 0);
594
595   return pango_fc_font_get_glyph (PANGO_FC_FONT (font), wc);
596 }
597
598 /**
599  * pango_xft_font_has_char:
600  * @font: a #PangoFont for the Xft backend
601  * @wc: Unicode codepoint to look up
602  *
603  * Determines whether @font has a glyph for the codepoint @wc.
604  *
605  * Use pango_fc_font_has_char() instead.
606  *
607  * Return value: %TRUE if @font has the requested codepoint.
608  *
609  * Since: 1.2
610  **/
611 gboolean
612 pango_xft_font_has_char (PangoFont *font,
613                          gunichar   wc)
614 {
615   g_return_val_if_fail (PANGO_XFT_IS_FONT (font), 0);
616
617   return pango_fc_font_has_char (PANGO_FC_FONT (font), wc);
618 }