Git init
[external/pango1.0.git] / pango / pangocairo-atsuifont.c
1 /* Pango
2  * pangocairo-atsuifont.c
3  *
4  * Copyright (C) 2000-2005 Red Hat Software
5  * Copyright (C) 2005-2007 Imendio AB
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 #import <Cocoa/Cocoa.h>
26
27 #include "pango-impl-utils.h"
28 #include "pangoatsui-private.h"
29 #include "pangocairo.h"
30 #include "pangocairo-private.h"
31 #include "pangocairo-atsui.h"
32 #include "pangocairo-atsuifont.h"
33
34 struct _PangoCairoATSUIFont
35 {
36   PangoATSUIFont font;
37   PangoCairoFontPrivate cf_priv;
38
39   double size;
40   int absolute_size;
41 };
42
43 struct _PangoCairoATSUIFontClass
44 {
45   PangoATSUIFontClass parent_class;
46 };
47
48
49
50 static cairo_font_face_t *pango_cairo_atsui_font_create_font_face           (PangoCairoFont *font);
51 static PangoFontMetrics  *pango_cairo_atsui_font_create_metrics_for_context (PangoCairoFont *font,
52                                                                             PangoContext    *context);
53
54 static void
55 cairo_font_iface_init (PangoCairoFontIface *iface)
56 {
57   iface->create_font_face = pango_cairo_atsui_font_create_font_face;
58   iface->create_metrics_for_context = pango_cairo_atsui_font_create_metrics_for_context;
59   iface->cf_priv_offset = G_STRUCT_OFFSET (PangoCairoATSUIFont, cf_priv);
60 }
61
62 G_DEFINE_TYPE_WITH_CODE (PangoCairoATSUIFont, pango_cairo_atsui_font, PANGO_TYPE_ATSUI_FONT,
63     { G_IMPLEMENT_INTERFACE (PANGO_TYPE_CAIRO_FONT, cairo_font_iface_init) });
64
65 /* we want get_glyph_extents extremely fast, so we use a small wrapper here
66  * to avoid having to lookup the interface data like we do for get_metrics
67  * in _pango_cairo_font_get_metrics(). */
68 static void
69 pango_cairo_atsui_font_get_glyph_extents (PangoFont      *font,
70                                           PangoGlyph      glyph,
71                                           PangoRectangle *ink_rect,
72                                           PangoRectangle *logical_rect)
73 {
74   PangoCairoATSUIFont *cafont = (PangoCairoATSUIFont *) (font);
75
76   _pango_cairo_font_private_get_glyph_extents (&cafont->cf_priv,
77                                                glyph,
78                                                ink_rect,
79                                                logical_rect);
80 }
81
82 static cairo_font_face_t *
83 pango_cairo_atsui_font_create_font_face (PangoCairoFont *font)
84 {
85   PangoATSUIFont *afont = (PangoATSUIFont *) (font);
86   CGFontRef font_id;
87
88   font_id = pango_atsui_font_get_cgfont (afont);
89   return cairo_quartz_font_face_create_for_cgfont (font_id);
90 }
91
92 static int
93 max_glyph_width (PangoLayout *layout)
94 {
95   int max_width = 0;
96   GSList *l, *r;
97
98   for (l = pango_layout_get_lines_readonly (layout); l; l = l->next)
99     {
100       PangoLayoutLine *line = l->data;
101
102       for (r = line->runs; r; r = r->next)
103         {
104           PangoGlyphString *glyphs = ((PangoGlyphItem *)r->data)->glyphs;
105           int i;
106
107           for (i = 0; i < glyphs->num_glyphs; i++)
108             if (glyphs->glyphs[i].geometry.width > max_width)
109               max_width = glyphs->glyphs[i].geometry.width;
110         }
111     }
112
113   return max_width;
114 }
115
116 static PangoFontMetrics *
117 pango_cairo_atsui_font_create_metrics_for_context (PangoCairoFont *font,
118                                                    PangoContext   *context)
119 {
120   PangoCairoATSUIFont *cafont = (PangoCairoATSUIFont *) font;
121   PangoATSUIFont *afont = (PangoATSUIFont *) font;
122   CGFontRef cg_font;
123   CTFontRef ct_font;
124   PangoFontMetrics *metrics;
125   PangoFontDescription *font_desc;
126   PangoLayout *layout;
127   PangoRectangle extents;
128   PangoLanguage *language = pango_context_get_language (context);
129   const char *sample_str = pango_language_get_sample_string (language);
130
131   cg_font = pango_atsui_font_get_cgfont (afont);
132   ct_font = CTFontCreateWithGraphicsFont(cg_font, cafont->size, NULL, NULL);
133
134   metrics = pango_font_metrics_new ();
135
136   metrics->ascent = CTFontGetAscent(ct_font) * PANGO_SCALE;
137   metrics->descent = -CTFontGetDescent(ct_font) * PANGO_SCALE;
138
139   metrics->underline_position = CTFontGetUnderlinePosition(ct_font) * PANGO_SCALE;
140   metrics->underline_thickness = CTFontGetUnderlineThickness(ct_font) * PANGO_SCALE;
141
142   metrics->strikethrough_position = metrics->ascent / 3;
143   metrics->strikethrough_thickness = metrics->underline_thickness * PANGO_SCALE;
144
145   layout = pango_layout_new (context);
146   font_desc = pango_font_describe_with_absolute_size ((PangoFont *) font);
147   pango_layout_set_font_description (layout, font_desc);
148   pango_layout_set_text (layout, sample_str, -1);
149   pango_layout_get_extents (layout, NULL, &extents);
150
151   metrics->approximate_char_width = extents.width / pango_utf8_strwidth (sample_str);
152
153   pango_layout_set_text (layout, "0123456789", -1);
154   metrics->approximate_digit_width = max_glyph_width (layout);
155
156   pango_font_description_free (font_desc);
157   g_object_unref (layout);
158   
159   
160
161   return metrics;
162 }
163
164 static PangoFontDescription *
165 pango_cairo_atsui_font_describe_absolute (PangoFont *font)
166 {
167   PangoFontDescription *desc;
168   PangoCairoATSUIFont *cafont = (PangoCairoATSUIFont *) font;
169
170   desc = pango_font_describe (font);
171   pango_font_description_set_absolute_size (desc, cafont->absolute_size);
172
173   return desc;
174 }
175
176 static void
177 pango_cairo_atsui_font_finalize (GObject *object)
178 {
179   PangoCairoATSUIFont *cafont = (PangoCairoATSUIFont *) object;
180
181   _pango_cairo_font_private_finalize (&cafont->cf_priv);
182
183   G_OBJECT_CLASS (pango_cairo_atsui_font_parent_class)->finalize (object);
184 }
185
186 static void
187 pango_cairo_atsui_font_class_init (PangoCairoATSUIFontClass *class)
188 {
189   GObjectClass *object_class = G_OBJECT_CLASS (class);
190   PangoFontClass *font_class = PANGO_FONT_CLASS (class);
191
192   object_class->finalize = pango_cairo_atsui_font_finalize;
193
194   font_class->get_glyph_extents = pango_cairo_atsui_font_get_glyph_extents;
195   font_class->get_metrics = _pango_cairo_font_get_metrics;
196   font_class->describe_absolute = pango_cairo_atsui_font_describe_absolute;
197 }
198
199 static void
200 pango_cairo_atsui_font_init (PangoCairoATSUIFont *cafont G_GNUC_UNUSED)
201 {
202 }
203
204 PangoATSUIFont *
205 _pango_cairo_atsui_font_new (PangoCairoATSUIFontMap     *cafontmap,
206                              PangoContext               *context,
207                              PangoATSUIFace             *face,
208                              const PangoFontDescription *desc)
209 {
210   const char *postscript_name;
211   gboolean synthesize_italic = FALSE;
212   PangoCairoATSUIFont *cafont;
213   PangoATSUIFont *afont;
214   CFStringRef cfstr;
215   ATSFontRef font_ref;
216   CGFontRef font_id;
217   double size;
218   double dpi;
219   double m;
220   cairo_matrix_t font_matrix;
221
222   postscript_name = _pango_atsui_face_get_postscript_name (face);
223   
224   cfstr = CFStringCreateWithCString (NULL, postscript_name,
225                                      kCFStringEncodingUTF8);
226   font_ref = ATSFontFindFromPostScriptName (cfstr, kATSOptionFlagsDefault);
227   CFRelease (cfstr);
228
229   /* We synthesize italic in two cases. The first is when
230    * NSFontManager has handed out a face that it claims has italic but
231    * it doesn't. The other is when an italic face is requested that
232    * doesn't have a real version.
233    */
234   if (font_ref == kATSFontRefUnspecified && 
235       pango_font_description_get_style (desc) != PANGO_STYLE_NORMAL)
236     {
237       NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
238       NSString *nsname;
239       NSFont *nsfont, *converted_font;
240
241       size = (double) pango_font_description_get_size (desc) / PANGO_SCALE;
242
243       nsname = [NSString stringWithUTF8String:postscript_name];
244       nsfont = [NSFont fontWithName:nsname size:size];
245
246       converted_font = [[NSFontManager sharedFontManager] convertFont:nsfont
247                         toHaveTrait:NSUnitalicFontMask];
248       font_ref = ATSFontFindFromPostScriptName ((CFStringRef) [converted_font fontName],
249                                                 kATSOptionFlagsDefault);
250
251       [pool release];
252
253       synthesize_italic = TRUE;
254     }
255   else if (_pango_atsui_face_get_synthetic_italic (face))
256     synthesize_italic = TRUE;
257
258   if (font_ref == kATSFontRefUnspecified)
259     return NULL;
260
261   font_id = CGFontCreateWithPlatformFont (&font_ref);
262   if (!font_id)
263     return NULL;
264
265   cafont = g_object_new (PANGO_TYPE_CAIRO_ATSUI_FONT, NULL);
266   afont = PANGO_ATSUI_FONT (cafont);
267
268   _pango_atsui_font_set_font_description (afont, desc);
269   _pango_atsui_font_set_face (afont, face);
270
271   size = (double) pango_font_description_get_size (desc) / PANGO_SCALE;
272   _pango_atsui_font_set_cgfont (afont, font_id);
273
274   if (context)
275     {
276       dpi = pango_cairo_context_get_resolution (context);
277
278       if (dpi <= 0)
279         dpi = cafontmap->dpi;
280     }
281   else
282     dpi = cafontmap->dpi;
283
284   cafont->absolute_size = pango_font_description_get_size (desc);
285
286   if (!pango_font_description_get_size_is_absolute (desc))
287     size *= dpi / 72.;
288
289   cafont->size = size;
290
291   /* When synthesizing italics, apply a shear matrix matching what Cocoa
292    * does. Cairo quartz had transformed text wrong before 1.5.13, stay
293    * backwards compatible until pango requires a new enough cairo.
294    */
295   if (cairo_version () >= CAIRO_VERSION_ENCODE(1,5,13))
296     m = -0.25;
297   else
298     m = 0.25;
299
300   if (synthesize_italic)
301     cairo_matrix_init (&font_matrix,
302                        1, 0, 
303                        m, 1,
304                        0, 0);
305   else
306     cairo_matrix_init_identity (&font_matrix);
307
308   cairo_matrix_scale (&font_matrix, size, size);
309
310   _pango_cairo_font_private_initialize (&cafont->cf_priv,
311                                         (PangoCairoFont *) cafont,
312                                         pango_font_description_get_gravity (desc),
313                                         _pango_cairo_context_get_merged_font_options (context),
314                                         pango_context_get_matrix (context),
315                                         &font_matrix);
316
317   return afont;
318 }