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