Upload Tizen2.0 source
[framework/graphics/cairo.git] / src / cairo-quartz-font.c
1 /* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
2 /* cairo - a vector graphics library with display and print output
3  *
4  * Copyright � 2008 Mozilla Corporation
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it either under the terms of the GNU Lesser General Public
8  * License version 2.1 as published by the Free Software Foundation
9  * (the "LGPL") or, at your option, under the terms of the Mozilla
10  * Public License Version 1.1 (the "MPL"). If you do not alter this
11  * notice, a recipient may use your version of this file under either
12  * the MPL or the LGPL.
13  *
14  * You should have received a copy of the LGPL along with this library
15  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
17  * You should have received a copy of the MPL along with this library
18  * in the file COPYING-MPL-1.1
19  *
20  * The contents of this file are subject to the Mozilla Public License
21  * Version 1.1 (the "License"); you may not use this file except in
22  * compliance with the License. You may obtain a copy of the License at
23  * http://www.mozilla.org/MPL/
24  *
25  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
26  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
27  * the specific language governing rights and limitations.
28  *
29  * The Original Code is the cairo graphics library.
30  *
31  * The Initial Developer of the Original Code is Mozilla Foundation.
32  *
33  * Contributor(s):
34  *      Vladimir Vukicevic <vladimir@mozilla.com>
35  */
36
37 #include "cairoint.h"
38
39 #include <dlfcn.h>
40
41 #include "cairo-image-surface-private.h"
42 #include "cairo-quartz.h"
43 #include "cairo-quartz-private.h"
44
45 #include "cairo-error-private.h"
46
47 /**
48  * SECTION:cairo-quartz-fonts
49  * @Title: Quartz (CGFont) Fonts
50  * @Short_Description: Font support via CGFont on OS X
51  * @See_Also: #cairo_font_face_t
52  *
53  * The Quartz font backend is primarily used to render text on Apple
54  * MacOS X systems.  The CGFont API is used for the internal
55  * implementation of the font backend methods.
56  **/
57
58 /**
59  * CAIRO_HAS_QUARTZ_FONT:
60  *
61  * Defined if the Quartz font backend is available.
62  * This macro can be used to conditionally compile backend-specific code.
63  *
64  * Since: 1.6
65  **/
66
67 static CFDataRef (*CGFontCopyTableForTagPtr) (CGFontRef font, uint32_t tag) = NULL;
68
69 /* CreateWithFontName exists in 10.5, but not in 10.4; CreateWithName isn't public in 10.4 */
70 static CGFontRef (*CGFontCreateWithFontNamePtr) (CFStringRef) = NULL;
71 static CGFontRef (*CGFontCreateWithNamePtr) (const char *) = NULL;
72
73 /* These aren't public before 10.5, and some have different names in 10.4 */
74 static int (*CGFontGetUnitsPerEmPtr) (CGFontRef) = NULL;
75 static bool (*CGFontGetGlyphAdvancesPtr) (CGFontRef, const CGGlyph[], size_t, int[]) = NULL;
76 static bool (*CGFontGetGlyphBBoxesPtr) (CGFontRef, const CGGlyph[], size_t, CGRect[]) = NULL;
77 static CGRect (*CGFontGetFontBBoxPtr) (CGFontRef) = NULL;
78
79 /* Not public, but present */
80 static void (*CGFontGetGlyphsForUnicharsPtr) (CGFontRef, const UniChar[], const CGGlyph[], size_t) = NULL;
81 static void (*CGContextSetAllowsFontSmoothingPtr) (CGContextRef, bool) = NULL;
82 static bool (*CGContextGetAllowsFontSmoothingPtr) (CGContextRef) = NULL;
83
84 /* Not public in the least bit */
85 static CGPathRef (*CGFontGetGlyphPathPtr) (CGFontRef fontRef, CGAffineTransform *textTransform, int unknown, CGGlyph glyph) = NULL;
86
87 /* CGFontGetHMetrics isn't public, but the other functions are public/present in 10.5 */
88 typedef struct {
89     int ascent;
90     int descent;
91     int leading;
92 } quartz_CGFontMetrics;
93 static quartz_CGFontMetrics* (*CGFontGetHMetricsPtr) (CGFontRef fontRef) = NULL;
94 static int (*CGFontGetAscentPtr) (CGFontRef fontRef) = NULL;
95 static int (*CGFontGetDescentPtr) (CGFontRef fontRef) = NULL;
96 static int (*CGFontGetLeadingPtr) (CGFontRef fontRef) = NULL;
97
98 /* Not public anymore in 64-bits nor in 10.7 */
99 static ATSFontRef (*FMGetATSFontRefFromFontPtr) (FMFont iFont) = NULL;
100
101 static cairo_bool_t _cairo_quartz_font_symbol_lookup_done = FALSE;
102 static cairo_bool_t _cairo_quartz_font_symbols_present = FALSE;
103
104 static void
105 quartz_font_ensure_symbols(void)
106 {
107     if (_cairo_quartz_font_symbol_lookup_done)
108         return;
109
110     CGFontCopyTableForTagPtr = dlsym(RTLD_DEFAULT, "CGFontCopyTableForTag");
111
112     /* Look for the 10.5 versions first */
113     CGFontGetGlyphBBoxesPtr = dlsym(RTLD_DEFAULT, "CGFontGetGlyphBBoxes");
114     if (!CGFontGetGlyphBBoxesPtr)
115         CGFontGetGlyphBBoxesPtr = dlsym(RTLD_DEFAULT, "CGFontGetGlyphBoundingBoxes");
116
117     CGFontGetGlyphsForUnicharsPtr = dlsym(RTLD_DEFAULT, "CGFontGetGlyphsForUnichars");
118     if (!CGFontGetGlyphsForUnicharsPtr)
119         CGFontGetGlyphsForUnicharsPtr = dlsym(RTLD_DEFAULT, "CGFontGetGlyphsForUnicodes");
120
121     CGFontGetFontBBoxPtr = dlsym(RTLD_DEFAULT, "CGFontGetFontBBox");
122
123     /* We just need one of these two */
124     CGFontCreateWithFontNamePtr = dlsym(RTLD_DEFAULT, "CGFontCreateWithFontName");
125     CGFontCreateWithNamePtr = dlsym(RTLD_DEFAULT, "CGFontCreateWithName");
126
127     /* These have the same name in 10.4 and 10.5 */
128     CGFontGetUnitsPerEmPtr = dlsym(RTLD_DEFAULT, "CGFontGetUnitsPerEm");
129     CGFontGetGlyphAdvancesPtr = dlsym(RTLD_DEFAULT, "CGFontGetGlyphAdvances");
130     CGFontGetGlyphPathPtr = dlsym(RTLD_DEFAULT, "CGFontGetGlyphPath");
131
132     CGFontGetHMetricsPtr = dlsym(RTLD_DEFAULT, "CGFontGetHMetrics");
133     CGFontGetAscentPtr = dlsym(RTLD_DEFAULT, "CGFontGetAscent");
134     CGFontGetDescentPtr = dlsym(RTLD_DEFAULT, "CGFontGetDescent");
135     CGFontGetLeadingPtr = dlsym(RTLD_DEFAULT, "CGFontGetLeading");
136
137     CGContextGetAllowsFontSmoothingPtr = dlsym(RTLD_DEFAULT, "CGContextGetAllowsFontSmoothing");
138     CGContextSetAllowsFontSmoothingPtr = dlsym(RTLD_DEFAULT, "CGContextSetAllowsFontSmoothing");
139
140     FMGetATSFontRefFromFontPtr = dlsym(RTLD_DEFAULT, "FMGetATSFontRefFromFont");
141
142     if ((CGFontCreateWithFontNamePtr || CGFontCreateWithNamePtr) &&
143         CGFontGetGlyphBBoxesPtr &&
144         CGFontGetGlyphsForUnicharsPtr &&
145         CGFontGetUnitsPerEmPtr &&
146         CGFontGetGlyphAdvancesPtr &&
147         CGFontGetGlyphPathPtr &&
148         (CGFontGetHMetricsPtr || (CGFontGetAscentPtr && CGFontGetDescentPtr && CGFontGetLeadingPtr)))
149         _cairo_quartz_font_symbols_present = TRUE;
150
151     _cairo_quartz_font_symbol_lookup_done = TRUE;
152 }
153
154 typedef struct _cairo_quartz_font_face cairo_quartz_font_face_t;
155 typedef struct _cairo_quartz_scaled_font cairo_quartz_scaled_font_t;
156
157 struct _cairo_quartz_scaled_font {
158     cairo_scaled_font_t base;
159 };
160
161 struct _cairo_quartz_font_face {
162     cairo_font_face_t base;
163
164     CGFontRef cgFont;
165 };
166
167 /*
168  * font face backend
169  */
170
171 static cairo_status_t
172 _cairo_quartz_font_face_create_for_toy (cairo_toy_font_face_t   *toy_face,
173                                         cairo_font_face_t      **font_face)
174 {
175     const char *family;
176     char *full_name;
177     CFStringRef cgFontName = NULL;
178     CGFontRef cgFont = NULL;
179     int loop;
180
181     quartz_font_ensure_symbols();
182     if (! _cairo_quartz_font_symbols_present)
183         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
184
185     family = toy_face->family;
186     full_name = malloc (strlen (family) + 64); // give us a bit of room to tack on Bold, Oblique, etc.
187     /* handle CSS-ish faces */
188     if (!strcmp(family, "serif") || !strcmp(family, "Times Roman"))
189         family = "Times";
190     else if (!strcmp(family, "sans-serif") || !strcmp(family, "sans"))
191         family = "Helvetica";
192     else if (!strcmp(family, "cursive"))
193         family = "Apple Chancery";
194     else if (!strcmp(family, "fantasy"))
195         family = "Papyrus";
196     else if (!strcmp(family, "monospace") || !strcmp(family, "mono"))
197         family = "Courier";
198
199     /* Try to build up the full name, e.g. "Helvetica Bold Oblique" first,
200      * then drop the bold, then drop the slant, then drop both.. finally
201      * just use "Helvetica".  And if Helvetica doesn't exist, give up.
202      */
203     for (loop = 0; loop < 5; loop++) {
204         if (loop == 4)
205             family = "Helvetica";
206
207         strcpy (full_name, family);
208
209         if (loop < 3 && (loop & 1) == 0) {
210             if (toy_face->weight == CAIRO_FONT_WEIGHT_BOLD)
211                 strcat (full_name, " Bold");
212         }
213
214         if (loop < 3 && (loop & 2) == 0) {
215             if (toy_face->slant == CAIRO_FONT_SLANT_ITALIC)
216                 strcat (full_name, " Italic");
217             else if (toy_face->slant == CAIRO_FONT_SLANT_OBLIQUE)
218                 strcat (full_name, " Oblique");
219         }
220
221         if (CGFontCreateWithFontNamePtr) {
222             cgFontName = CFStringCreateWithCString (NULL, full_name, kCFStringEncodingASCII);
223             cgFont = CGFontCreateWithFontNamePtr (cgFontName);
224             CFRelease (cgFontName);
225         } else {
226             cgFont = CGFontCreateWithNamePtr (full_name);
227         }
228
229         if (cgFont)
230             break;
231     }
232
233     if (!cgFont) {
234         /* Give up */
235         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
236     }
237
238     *font_face = cairo_quartz_font_face_create_for_cgfont (cgFont);
239     CGFontRelease (cgFont);
240
241     return CAIRO_STATUS_SUCCESS;
242 }
243
244 static void
245 _cairo_quartz_font_face_destroy (void *abstract_face)
246 {
247     cairo_quartz_font_face_t *font_face = (cairo_quartz_font_face_t*) abstract_face;
248
249     CGFontRelease (font_face->cgFont);
250 }
251
252 static const cairo_scaled_font_backend_t _cairo_quartz_scaled_font_backend;
253
254 static cairo_status_t
255 _cairo_quartz_font_face_scaled_font_create (void *abstract_face,
256                                             const cairo_matrix_t *font_matrix,
257                                             const cairo_matrix_t *ctm,
258                                             const cairo_font_options_t *options,
259                                             cairo_scaled_font_t **font_out)
260 {
261     cairo_quartz_font_face_t *font_face = abstract_face;
262     cairo_quartz_scaled_font_t *font = NULL;
263     cairo_status_t status;
264     cairo_font_extents_t fs_metrics;
265     double ems;
266     CGRect bbox;
267
268     quartz_font_ensure_symbols();
269     if (!_cairo_quartz_font_symbols_present)
270         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
271
272     font = malloc(sizeof(cairo_quartz_scaled_font_t));
273     if (font == NULL)
274         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
275
276     memset (font, 0, sizeof(cairo_quartz_scaled_font_t));
277
278     status = _cairo_scaled_font_init (&font->base,
279                                       &font_face->base, font_matrix, ctm, options,
280                                       &_cairo_quartz_scaled_font_backend);
281     if (status)
282         goto FINISH;
283
284     ems = CGFontGetUnitsPerEmPtr (font_face->cgFont);
285
286     /* initialize metrics */
287     if (CGFontGetFontBBoxPtr && CGFontGetAscentPtr) {
288         fs_metrics.ascent = (CGFontGetAscentPtr (font_face->cgFont) / ems);
289         fs_metrics.descent = - (CGFontGetDescentPtr (font_face->cgFont) / ems);
290         fs_metrics.height = fs_metrics.ascent + fs_metrics.descent +
291             (CGFontGetLeadingPtr (font_face->cgFont) / ems);
292
293         bbox = CGFontGetFontBBoxPtr (font_face->cgFont);
294         fs_metrics.max_x_advance = CGRectGetMaxX(bbox) / ems;
295         fs_metrics.max_y_advance = 0.0;
296     } else {
297         CGGlyph wGlyph;
298         UniChar u;
299
300         quartz_CGFontMetrics *m;
301         m = CGFontGetHMetricsPtr (font_face->cgFont);
302
303         /* On OX 10.4, GetHMetricsPtr sometimes returns NULL for unknown reasons */
304         if (!m) {
305             status = _cairo_error(CAIRO_STATUS_NULL_POINTER);
306             goto FINISH;
307         }
308
309         fs_metrics.ascent = (m->ascent / ems);
310         fs_metrics.descent = - (m->descent / ems);
311         fs_metrics.height = fs_metrics.ascent + fs_metrics.descent + (m->leading / ems);
312
313         /* We kind of have to guess here; W's big, right? */
314         u = (UniChar) 'W';
315         CGFontGetGlyphsForUnicharsPtr (font_face->cgFont, &u, &wGlyph, 1);
316         if (wGlyph && CGFontGetGlyphBBoxesPtr (font_face->cgFont, &wGlyph, 1, &bbox)) {
317             fs_metrics.max_x_advance = CGRectGetMaxX(bbox) / ems;
318             fs_metrics.max_y_advance = 0.0;
319         } else {
320             fs_metrics.max_x_advance = 0.0;
321             fs_metrics.max_y_advance = 0.0;
322         }
323     }
324
325     status = _cairo_scaled_font_set_metrics (&font->base, &fs_metrics);
326
327 FINISH:
328     if (status != CAIRO_STATUS_SUCCESS) {
329         free (font);
330     } else {
331         *font_out = (cairo_scaled_font_t*) font;
332     }
333
334     return status;
335 }
336
337 const cairo_font_face_backend_t _cairo_quartz_font_face_backend = {
338     CAIRO_FONT_TYPE_QUARTZ,
339     _cairo_quartz_font_face_create_for_toy,
340     _cairo_quartz_font_face_destroy,
341     _cairo_quartz_font_face_scaled_font_create
342 };
343
344 /**
345  * cairo_quartz_font_face_create_for_cgfont:
346  * @font: a #CGFontRef obtained through a method external to cairo.
347  *
348  * Creates a new font for the Quartz font backend based on a
349  * #CGFontRef.  This font can then be used with
350  * cairo_set_font_face() or cairo_scaled_font_create().
351  *
352  * Return value: a newly created #cairo_font_face_t. Free with
353  *  cairo_font_face_destroy() when you are done using it.
354  *
355  * Since: 1.6
356  **/
357 cairo_font_face_t *
358 cairo_quartz_font_face_create_for_cgfont (CGFontRef font)
359 {
360     cairo_quartz_font_face_t *font_face;
361
362     quartz_font_ensure_symbols();
363
364     font_face = malloc (sizeof (cairo_quartz_font_face_t));
365     if (!font_face) {
366         cairo_status_t ignore_status;
367         ignore_status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
368         return (cairo_font_face_t *)&_cairo_font_face_nil;
369     }
370
371     font_face->cgFont = CGFontRetain (font);
372
373     _cairo_font_face_init (&font_face->base, &_cairo_quartz_font_face_backend);
374
375     return &font_face->base;
376 }
377
378 /*
379  * scaled font backend
380  */
381
382 static cairo_quartz_font_face_t *
383 _cairo_quartz_scaled_to_face (void *abstract_font)
384 {
385     cairo_quartz_scaled_font_t *sfont = (cairo_quartz_scaled_font_t*) abstract_font;
386     cairo_font_face_t *font_face = sfont->base.font_face;
387     assert (font_face->backend->type == CAIRO_FONT_TYPE_QUARTZ);
388     return (cairo_quartz_font_face_t*) font_face;
389 }
390
391 static void
392 _cairo_quartz_scaled_font_fini(void *abstract_font)
393 {
394 }
395
396 #define INVALID_GLYPH 0x00
397
398 static inline CGGlyph
399 _cairo_quartz_scaled_glyph_index (cairo_scaled_glyph_t *scaled_glyph) {
400     unsigned long index = _cairo_scaled_glyph_index (scaled_glyph);
401     if (index > 0xffff)
402         return INVALID_GLYPH;
403     return (CGGlyph) index;
404 }
405
406 static cairo_int_status_t
407 _cairo_quartz_init_glyph_metrics (cairo_quartz_scaled_font_t *font,
408                                   cairo_scaled_glyph_t *scaled_glyph)
409 {
410     cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
411
412     cairo_quartz_font_face_t *font_face = _cairo_quartz_scaled_to_face(font);
413     cairo_text_extents_t extents = {0, 0, 0, 0, 0, 0};
414     CGGlyph glyph = _cairo_quartz_scaled_glyph_index (scaled_glyph);
415     int advance;
416     CGRect bbox;
417     double emscale = CGFontGetUnitsPerEmPtr (font_face->cgFont);
418     double xmin, ymin, xmax, ymax;
419
420     if (glyph == INVALID_GLYPH)
421         goto FAIL;
422
423     if (!CGFontGetGlyphAdvancesPtr (font_face->cgFont, &glyph, 1, &advance) ||
424         !CGFontGetGlyphBBoxesPtr (font_face->cgFont, &glyph, 1, &bbox))
425         goto FAIL;
426
427     /* broken fonts like Al Bayan return incorrect bounds for some null characters,
428        see https://bugzilla.mozilla.org/show_bug.cgi?id=534260 */
429     if (unlikely (bbox.origin.x == -32767 &&
430                   bbox.origin.y == -32767 &&
431                   bbox.size.width == 65534 &&
432                   bbox.size.height == 65534)) {
433         bbox.origin.x = bbox.origin.y = 0;
434         bbox.size.width = bbox.size.height = 0;
435     }
436
437     bbox = CGRectMake (bbox.origin.x / emscale,
438                        bbox.origin.y / emscale,
439                        bbox.size.width / emscale,
440                        bbox.size.height / emscale);
441
442     /* Should we want to always integer-align glyph extents, we can do so in this way */
443 #if 0
444     {
445         CGAffineTransform textMatrix;
446         textMatrix = CGAffineTransformMake (font->base.scale.xx,
447                                             -font->base.scale.yx,
448                                             -font->base.scale.xy,
449                                             font->base.scale.yy,
450                                             0.0f, 0.0f);
451
452         bbox = CGRectApplyAffineTransform (bbox, textMatrix);
453         bbox = CGRectIntegral (bbox);
454         bbox = CGRectApplyAffineTransform (bbox, CGAffineTransformInvert (textMatrix));
455     }
456 #endif
457
458 #if 0
459     fprintf (stderr, "[0x%04x] bbox: %f %f %f %f\n", glyph,
460              bbox.origin.x / emscale, bbox.origin.y / emscale,
461              bbox.size.width / emscale, bbox.size.height / emscale);
462 #endif
463
464     xmin = CGRectGetMinX(bbox);
465     ymin = CGRectGetMinY(bbox);
466     xmax = CGRectGetMaxX(bbox);
467     ymax = CGRectGetMaxY(bbox);
468
469     extents.x_bearing = xmin;
470     extents.y_bearing = - ymax;
471     extents.width = xmax - xmin;
472     extents.height = ymax - ymin;
473
474     extents.x_advance = (double) advance / emscale;
475     extents.y_advance = 0.0;
476
477 #if 0
478     fprintf (stderr, "[0x%04x] extents: bearings: %f %f dim: %f %f adv: %f\n\n", glyph,
479              extents.x_bearing, extents.y_bearing, extents.width, extents.height, extents.x_advance);
480 #endif
481
482   FAIL:
483     _cairo_scaled_glyph_set_metrics (scaled_glyph,
484                                      &font->base,
485                                      &extents);
486
487     return status;
488 }
489
490 static void
491 _cairo_quartz_path_apply_func (void *info, const CGPathElement *el)
492 {
493     cairo_path_fixed_t *path = (cairo_path_fixed_t *) info;
494     cairo_status_t status;
495
496     switch (el->type) {
497         case kCGPathElementMoveToPoint:
498             status = _cairo_path_fixed_move_to (path,
499                                                 _cairo_fixed_from_double(el->points[0].x),
500                                                 _cairo_fixed_from_double(el->points[0].y));
501             assert(!status);
502             break;
503         case kCGPathElementAddLineToPoint:
504             status = _cairo_path_fixed_line_to (path,
505                                                 _cairo_fixed_from_double(el->points[0].x),
506                                                 _cairo_fixed_from_double(el->points[0].y));
507             assert(!status);
508             break;
509         case kCGPathElementAddQuadCurveToPoint: {
510             cairo_fixed_t fx, fy;
511             double x, y;
512             if (!_cairo_path_fixed_get_current_point (path, &fx, &fy))
513                 fx = fy = 0;
514             x = _cairo_fixed_to_double (fx);
515             y = _cairo_fixed_to_double (fy);
516
517             status = _cairo_path_fixed_curve_to (path,
518                                                  _cairo_fixed_from_double((x + el->points[0].x * 2.0) / 3.0),
519                                                  _cairo_fixed_from_double((y + el->points[0].y * 2.0) / 3.0),
520                                                  _cairo_fixed_from_double((el->points[0].x * 2.0 + el->points[1].x) / 3.0),
521                                                  _cairo_fixed_from_double((el->points[0].y * 2.0 + el->points[1].y) / 3.0),
522                                                  _cairo_fixed_from_double(el->points[1].x),
523                                                  _cairo_fixed_from_double(el->points[1].y));
524         }
525             assert(!status);
526             break;
527         case kCGPathElementAddCurveToPoint:
528             status = _cairo_path_fixed_curve_to (path,
529                                                  _cairo_fixed_from_double(el->points[0].x),
530                                                  _cairo_fixed_from_double(el->points[0].y),
531                                                  _cairo_fixed_from_double(el->points[1].x),
532                                                  _cairo_fixed_from_double(el->points[1].y),
533                                                  _cairo_fixed_from_double(el->points[2].x),
534                                                  _cairo_fixed_from_double(el->points[2].y));
535             assert(!status);        
536             break;
537         case kCGPathElementCloseSubpath:
538             status = _cairo_path_fixed_close_path (path);
539             assert(!status);
540             break;
541     }
542 }
543
544 static cairo_int_status_t
545 _cairo_quartz_init_glyph_path (cairo_quartz_scaled_font_t *font,
546                                cairo_scaled_glyph_t *scaled_glyph)
547 {
548     cairo_quartz_font_face_t *font_face = _cairo_quartz_scaled_to_face(font);
549     CGGlyph glyph = _cairo_quartz_scaled_glyph_index (scaled_glyph);
550     CGAffineTransform textMatrix;
551     CGPathRef glyphPath;
552     cairo_path_fixed_t *path;
553
554     if (glyph == INVALID_GLYPH) {
555         _cairo_scaled_glyph_set_path (scaled_glyph, &font->base, _cairo_path_fixed_create());
556         return CAIRO_STATUS_SUCCESS;
557     }
558
559     /* scale(1,-1) * font->base.scale */
560     textMatrix = CGAffineTransformMake (font->base.scale.xx,
561                                         font->base.scale.yx,
562                                         -font->base.scale.xy,
563                                         -font->base.scale.yy,
564                                         0, 0);
565
566     glyphPath = CGFontGetGlyphPathPtr (font_face->cgFont, &textMatrix, 0, glyph);
567     if (!glyphPath)
568         return CAIRO_INT_STATUS_UNSUPPORTED;
569
570     path = _cairo_path_fixed_create ();
571     if (!path) {
572         CGPathRelease (glyphPath);
573         return _cairo_error(CAIRO_STATUS_NO_MEMORY);
574     }
575
576     CGPathApply (glyphPath, path, _cairo_quartz_path_apply_func);
577
578     CGPathRelease (glyphPath);
579
580     _cairo_scaled_glyph_set_path (scaled_glyph, &font->base, path);
581
582     return CAIRO_STATUS_SUCCESS;
583 }
584
585 static cairo_int_status_t
586 _cairo_quartz_init_glyph_surface (cairo_quartz_scaled_font_t *font,
587                                   cairo_scaled_glyph_t *scaled_glyph)
588 {
589     cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
590
591     cairo_quartz_font_face_t *font_face = _cairo_quartz_scaled_to_face(font);
592
593     cairo_image_surface_t *surface = NULL;
594
595     CGGlyph glyph = _cairo_quartz_scaled_glyph_index (scaled_glyph);
596
597     int advance;
598     CGRect bbox;
599     double width, height;
600     double emscale = CGFontGetUnitsPerEmPtr (font_face->cgFont);
601
602     CGContextRef cgContext = NULL;
603     CGAffineTransform textMatrix;
604     CGRect glyphRect, glyphRectInt;
605     CGPoint glyphOrigin;
606
607     //fprintf (stderr, "scaled_glyph: %p surface: %p\n", scaled_glyph, scaled_glyph->surface);
608
609     /* Create blank 2x2 image if we don't have this character.
610      * Maybe we should draw a better missing-glyph slug or something,
611      * but this is ok for now.
612      */
613     if (glyph == INVALID_GLYPH) {
614         surface = (cairo_image_surface_t*) cairo_image_surface_create (CAIRO_FORMAT_A8, 2, 2);
615         status = cairo_surface_status ((cairo_surface_t *) surface);
616         if (status)
617             return status;
618
619         _cairo_scaled_glyph_set_surface (scaled_glyph,
620                                          &font->base,
621                                          surface);
622         return CAIRO_STATUS_SUCCESS;
623     }
624
625     if (!CGFontGetGlyphAdvancesPtr (font_face->cgFont, &glyph, 1, &advance) ||
626         !CGFontGetGlyphBBoxesPtr (font_face->cgFont, &glyph, 1, &bbox))
627     {
628         return CAIRO_INT_STATUS_UNSUPPORTED;
629     }
630
631     /* scale(1,-1) * font->base.scale * scale(1,-1) */
632     textMatrix = CGAffineTransformMake (font->base.scale.xx,
633                                         -font->base.scale.yx,
634                                         -font->base.scale.xy,
635                                         font->base.scale.yy,
636                                         0, -0);
637     glyphRect = CGRectMake (bbox.origin.x / emscale,
638                             bbox.origin.y / emscale,
639                             bbox.size.width / emscale,
640                             bbox.size.height / emscale);
641
642     glyphRect = CGRectApplyAffineTransform (glyphRect, textMatrix);
643
644     /* Round the rectangle outwards, so that we don't have to deal
645      * with non-integer-pixel origins or dimensions.
646      */
647     glyphRectInt = CGRectIntegral (glyphRect);
648
649 #if 0
650     fprintf (stderr, "glyphRect[o]: %f %f %f %f\n",
651              glyphRect.origin.x, glyphRect.origin.y, glyphRect.size.width, glyphRect.size.height);
652     fprintf (stderr, "glyphRectInt: %f %f %f %f\n",
653              glyphRectInt.origin.x, glyphRectInt.origin.y, glyphRectInt.size.width, glyphRectInt.size.height);
654 #endif
655
656     glyphOrigin = glyphRectInt.origin;
657
658     //textMatrix = CGAffineTransformConcat (textMatrix, CGAffineTransformInvert (ctm));
659
660     width = glyphRectInt.size.width;
661     height = glyphRectInt.size.height;
662
663     //fprintf (stderr, "glyphRect[n]: %f %f %f %f\n", glyphRect.origin.x, glyphRect.origin.y, glyphRect.size.width, glyphRect.size.height);
664
665     surface = (cairo_image_surface_t*) cairo_image_surface_create (CAIRO_FORMAT_A8, width, height);
666     if (surface->base.status)
667         return surface->base.status;
668
669     if (surface->width != 0 && surface->height != 0) {
670         cgContext = CGBitmapContextCreate (surface->data,
671                                            surface->width,
672                                            surface->height,
673                                            8,
674                                            surface->stride,
675                                            NULL,
676                                            kCGImageAlphaOnly);
677
678         if (cgContext == NULL) {
679             cairo_surface_destroy (&surface->base);
680             return _cairo_error (CAIRO_STATUS_NO_MEMORY);
681         }
682
683         CGContextSetFont (cgContext, font_face->cgFont);
684         CGContextSetFontSize (cgContext, 1.0);
685         CGContextSetTextMatrix (cgContext, textMatrix);
686
687         switch (font->base.options.antialias) {
688         case CAIRO_ANTIALIAS_SUBPIXEL:
689         case CAIRO_ANTIALIAS_BEST:
690             CGContextSetShouldAntialias (cgContext, TRUE);
691             CGContextSetShouldSmoothFonts (cgContext, TRUE);
692             if (CGContextSetAllowsFontSmoothingPtr &&
693                 !CGContextGetAllowsFontSmoothingPtr (cgContext))
694                 CGContextSetAllowsFontSmoothingPtr (cgContext, TRUE);
695             break;
696         case CAIRO_ANTIALIAS_NONE:
697             CGContextSetShouldAntialias (cgContext, FALSE);
698             break;
699         case CAIRO_ANTIALIAS_GRAY:
700         case CAIRO_ANTIALIAS_GOOD:
701         case CAIRO_ANTIALIAS_FAST:
702             CGContextSetShouldAntialias (cgContext, TRUE);
703             CGContextSetShouldSmoothFonts (cgContext, FALSE);
704             break;
705         case CAIRO_ANTIALIAS_DEFAULT:
706         default:
707             /* Don't do anything */
708             break;
709         }
710
711         CGContextSetAlpha (cgContext, 1.0);
712         CGContextShowGlyphsAtPoint (cgContext, - glyphOrigin.x, - glyphOrigin.y, &glyph, 1);
713
714         CGContextRelease (cgContext);
715     }
716
717     cairo_surface_set_device_offset (&surface->base,
718                                      - glyphOrigin.x,
719                                      height + glyphOrigin.y);
720
721     _cairo_scaled_glyph_set_surface (scaled_glyph, &font->base, surface);
722
723     return status;
724 }
725
726 static cairo_int_status_t
727 _cairo_quartz_scaled_glyph_init (void *abstract_font,
728                                  cairo_scaled_glyph_t *scaled_glyph,
729                                  cairo_scaled_glyph_info_t info)
730 {
731     cairo_quartz_scaled_font_t *font = (cairo_quartz_scaled_font_t *) abstract_font;
732     cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
733
734     if (!status && (info & CAIRO_SCALED_GLYPH_INFO_METRICS))
735         status = _cairo_quartz_init_glyph_metrics (font, scaled_glyph);
736
737     if (!status && (info & CAIRO_SCALED_GLYPH_INFO_PATH))
738         status = _cairo_quartz_init_glyph_path (font, scaled_glyph);
739
740     if (!status && (info & CAIRO_SCALED_GLYPH_INFO_SURFACE))
741         status = _cairo_quartz_init_glyph_surface (font, scaled_glyph);
742
743     return status;
744 }
745
746 static unsigned long
747 _cairo_quartz_ucs4_to_index (void *abstract_font,
748                              uint32_t ucs4)
749 {
750     cairo_quartz_scaled_font_t *font = (cairo_quartz_scaled_font_t*) abstract_font;
751     cairo_quartz_font_face_t *ffont = _cairo_quartz_scaled_to_face(font);
752     UniChar u = (UniChar) ucs4;
753     CGGlyph glyph;
754
755     CGFontGetGlyphsForUnicharsPtr (ffont->cgFont, &u, &glyph, 1);
756
757     return glyph;
758 }
759
760 static cairo_int_status_t
761 _cairo_quartz_load_truetype_table (void             *abstract_font,
762                                    unsigned long     tag,
763                                    long              offset,
764                                    unsigned char    *buffer,
765                                    unsigned long    *length)
766 {
767     cairo_quartz_font_face_t *font_face = _cairo_quartz_scaled_to_face (abstract_font);
768     CFDataRef data = NULL;
769
770     if (likely (CGFontCopyTableForTagPtr))
771         data = CGFontCopyTableForTagPtr (font_face->cgFont, tag);
772
773     if (!data)
774         return CAIRO_INT_STATUS_UNSUPPORTED;
775
776     if (buffer == NULL) {
777         *length = CFDataGetLength (data);
778         CFRelease (data);
779         return CAIRO_STATUS_SUCCESS;
780     }
781
782     if (CFDataGetLength (data) < offset + (long) *length) {
783         CFRelease (data);
784         return CAIRO_INT_STATUS_UNSUPPORTED;
785     }
786
787     CFDataGetBytes (data, CFRangeMake (offset, *length), buffer);
788     CFRelease (data);
789
790     return CAIRO_STATUS_SUCCESS;
791 }
792
793 static const cairo_scaled_font_backend_t _cairo_quartz_scaled_font_backend = {
794     CAIRO_FONT_TYPE_QUARTZ,
795     _cairo_quartz_scaled_font_fini,
796     _cairo_quartz_scaled_glyph_init,
797     NULL, /* text_to_glyphs */
798     _cairo_quartz_ucs4_to_index,
799     _cairo_quartz_load_truetype_table,
800     NULL, /* map_glyphs_to_unicode */
801 };
802
803 /*
804  * private methods that the quartz surface uses
805  */
806
807 CGFontRef
808 _cairo_quartz_scaled_font_get_cg_font_ref (cairo_scaled_font_t *abstract_font)
809 {
810     cairo_quartz_font_face_t *ffont = _cairo_quartz_scaled_to_face(abstract_font);
811
812     return ffont->cgFont;
813 }
814
815 /*
816  * compat with old ATSUI backend
817  */
818
819 /**
820  * cairo_quartz_font_face_create_for_atsu_font_id:
821  * @font_id: an ATSUFontID for the font.
822  *
823  * Creates a new font for the Quartz font backend based on an
824  * #ATSUFontID. This font can then be used with
825  * cairo_set_font_face() or cairo_scaled_font_create().
826  *
827  * Return value: a newly created #cairo_font_face_t. Free with
828  *  cairo_font_face_destroy() when you are done using it.
829  *
830  * Since: 1.6
831  **/
832 cairo_font_face_t *
833 cairo_quartz_font_face_create_for_atsu_font_id (ATSUFontID font_id)
834 {
835     quartz_font_ensure_symbols();
836
837     if (FMGetATSFontRefFromFontPtr != NULL) {
838         ATSFontRef atsFont = FMGetATSFontRefFromFontPtr (font_id);
839         CGFontRef cgFont = CGFontCreateWithPlatformFont (&atsFont);
840         cairo_font_face_t *ff;
841
842         ff = cairo_quartz_font_face_create_for_cgfont (cgFont);
843
844         CGFontRelease (cgFont);
845
846         return ff;
847     } else {
848         _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
849         return (cairo_font_face_t *)&_cairo_font_face_nil;
850     }
851 }
852
853 /* This is the old name for the above function, exported for compat purposes */
854 cairo_font_face_t *cairo_atsui_font_face_create_for_atsu_font_id (ATSUFontID font_id);
855
856 cairo_font_face_t *
857 cairo_atsui_font_face_create_for_atsu_font_id (ATSUFontID font_id)
858 {
859     return cairo_quartz_font_face_create_for_atsu_font_id (font_id);
860 }