beta-0.89.2
[luatex.git] / source / libs / cairo / cairo-src / src / cairo-quartz-font.c
blobfeee61a0d861fad1190aa545b5de65b09c13e7f8
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
4 * Copyright � 2008 Mozilla Corporation
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.
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
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/
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.
29 * The Original Code is the cairo graphics library.
31 * The Initial Developer of the Original Code is Mozilla Foundation.
33 * Contributor(s):
34 * Vladimir Vukicevic <vladimir@mozilla.com>
37 #include "cairoint.h"
39 #include <dlfcn.h>
41 #include "cairo-image-surface-private.h"
42 #include "cairo-quartz.h"
43 #include "cairo-quartz-private.h"
45 #include "cairo-error-private.h"
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
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 **/
58 /**
59 * CAIRO_HAS_QUARTZ_FONT:
61 * Defined if the Quartz font backend is available.
62 * This macro can be used to conditionally compile backend-specific code.
64 * Since: 1.6
65 **/
67 static CFDataRef (*CGFontCopyTableForTagPtr) (CGFontRef font, uint32_t tag) = NULL;
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;
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;
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;
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;
95 /* Not public anymore in 64-bits nor in 10.7 */
96 static ATSFontRef (*FMGetATSFontRefFromFontPtr) (FMFont iFont) = NULL;
98 static cairo_bool_t _cairo_quartz_font_symbol_lookup_done = FALSE;
99 static cairo_bool_t _cairo_quartz_font_symbols_present = FALSE;
101 static void
102 quartz_font_ensure_symbols(void)
104 if (_cairo_quartz_font_symbol_lookup_done)
105 return;
107 CGFontCopyTableForTagPtr = dlsym(RTLD_DEFAULT, "CGFontCopyTableForTag");
109 /* Look for the 10.5 versions first */
110 CGFontGetGlyphBBoxesPtr = dlsym(RTLD_DEFAULT, "CGFontGetGlyphBBoxes");
111 if (!CGFontGetGlyphBBoxesPtr)
112 CGFontGetGlyphBBoxesPtr = dlsym(RTLD_DEFAULT, "CGFontGetGlyphBoundingBoxes");
114 CGFontGetGlyphsForUnicharsPtr = dlsym(RTLD_DEFAULT, "CGFontGetGlyphsForUnichars");
115 if (!CGFontGetGlyphsForUnicharsPtr)
116 CGFontGetGlyphsForUnicharsPtr = dlsym(RTLD_DEFAULT, "CGFontGetGlyphsForUnicodes");
118 CGFontGetFontBBoxPtr = dlsym(RTLD_DEFAULT, "CGFontGetFontBBox");
120 /* We just need one of these two */
121 CGFontCreateWithFontNamePtr = dlsym(RTLD_DEFAULT, "CGFontCreateWithFontName");
122 CGFontCreateWithNamePtr = dlsym(RTLD_DEFAULT, "CGFontCreateWithName");
124 /* These have the same name in 10.4 and 10.5 */
125 CGFontGetUnitsPerEmPtr = dlsym(RTLD_DEFAULT, "CGFontGetUnitsPerEm");
126 CGFontGetGlyphAdvancesPtr = dlsym(RTLD_DEFAULT, "CGFontGetGlyphAdvances");
128 CGFontGetHMetricsPtr = dlsym(RTLD_DEFAULT, "CGFontGetHMetrics");
129 CGFontGetAscentPtr = dlsym(RTLD_DEFAULT, "CGFontGetAscent");
130 CGFontGetDescentPtr = dlsym(RTLD_DEFAULT, "CGFontGetDescent");
131 CGFontGetLeadingPtr = dlsym(RTLD_DEFAULT, "CGFontGetLeading");
133 CGContextGetAllowsFontSmoothingPtr = dlsym(RTLD_DEFAULT, "CGContextGetAllowsFontSmoothing");
134 CGContextSetAllowsFontSmoothingPtr = dlsym(RTLD_DEFAULT, "CGContextSetAllowsFontSmoothing");
136 FMGetATSFontRefFromFontPtr = dlsym(RTLD_DEFAULT, "FMGetATSFontRefFromFont");
138 if ((CGFontCreateWithFontNamePtr || CGFontCreateWithNamePtr) &&
139 CGFontGetGlyphBBoxesPtr &&
140 CGFontGetGlyphsForUnicharsPtr &&
141 CGFontGetUnitsPerEmPtr &&
142 CGFontGetGlyphAdvancesPtr &&
143 (CGFontGetHMetricsPtr || (CGFontGetAscentPtr && CGFontGetDescentPtr && CGFontGetLeadingPtr)))
144 _cairo_quartz_font_symbols_present = TRUE;
146 _cairo_quartz_font_symbol_lookup_done = TRUE;
149 typedef struct _cairo_quartz_font_face cairo_quartz_font_face_t;
150 typedef struct _cairo_quartz_scaled_font cairo_quartz_scaled_font_t;
152 struct _cairo_quartz_scaled_font {
153 cairo_scaled_font_t base;
156 struct _cairo_quartz_font_face {
157 cairo_font_face_t base;
159 CGFontRef cgFont;
163 * font face backend
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)
170 const char *family;
171 char *full_name;
172 CFStringRef cgFontName = NULL;
173 CGFontRef cgFont = NULL;
174 int loop;
176 quartz_font_ensure_symbols();
177 if (! _cairo_quartz_font_symbols_present)
178 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
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";
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.
198 for (loop = 0; loop < 5; loop++) {
199 if (loop == 4)
200 family = "Helvetica";
202 strcpy (full_name, family);
204 if (loop < 3 && (loop & 1) == 0) {
205 if (toy_face->weight == CAIRO_FONT_WEIGHT_BOLD)
206 strcat (full_name, " Bold");
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");
216 if (CGFontCreateWithFontNamePtr) {
217 cgFontName = CFStringCreateWithCString (NULL, full_name, kCFStringEncodingASCII);
218 cgFont = CGFontCreateWithFontNamePtr (cgFontName);
219 CFRelease (cgFontName);
220 } else {
221 cgFont = CGFontCreateWithNamePtr (full_name);
224 if (cgFont)
225 break;
228 if (!cgFont) {
229 /* Give up */
230 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
233 *font_face = cairo_quartz_font_face_create_for_cgfont (cgFont);
234 CGFontRelease (cgFont);
236 return CAIRO_STATUS_SUCCESS;
239 static cairo_bool_t
240 _cairo_quartz_font_face_destroy (void *abstract_face)
242 cairo_quartz_font_face_t *font_face = (cairo_quartz_font_face_t*) abstract_face;
244 CGFontRelease (font_face->cgFont);
245 return TRUE;
248 static const cairo_scaled_font_backend_t _cairo_quartz_scaled_font_backend;
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)
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;
264 quartz_font_ensure_symbols();
265 if (!_cairo_quartz_font_symbols_present)
266 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
268 font = malloc(sizeof(cairo_quartz_scaled_font_t));
269 if (font == NULL)
270 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
272 memset (font, 0, sizeof(cairo_quartz_scaled_font_t));
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;
280 ems = CGFontGetUnitsPerEmPtr (font_face->cgFont);
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);
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;
296 quartz_CGFontMetrics *m;
297 m = CGFontGetHMetricsPtr (font_face->cgFont);
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;
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);
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;
321 status = _cairo_scaled_font_set_metrics (&font->base, &fs_metrics);
323 FINISH:
324 if (status != CAIRO_STATUS_SUCCESS) {
325 free (font);
326 } else {
327 *font_out = (cairo_scaled_font_t*) font;
330 return status;
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
341 * cairo_quartz_font_face_create_for_cgfont:
342 * @font: a #CGFontRef obtained through a method external to cairo.
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().
348 * Return value: a newly created #cairo_font_face_t. Free with
349 * cairo_font_face_destroy() when you are done using it.
351 * Since: 1.6
353 cairo_font_face_t *
354 cairo_quartz_font_face_create_for_cgfont (CGFontRef font)
356 cairo_quartz_font_face_t *font_face;
358 quartz_font_ensure_symbols();
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;
367 font_face->cgFont = CGFontRetain (font);
369 _cairo_font_face_init (&font_face->base, &_cairo_quartz_font_face_backend);
371 return &font_face->base;
375 * scaled font backend
378 static cairo_quartz_font_face_t *
379 _cairo_quartz_scaled_to_face (void *abstract_font)
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;
387 static void
388 _cairo_quartz_scaled_font_fini(void *abstract_font)
392 #define INVALID_GLYPH 0x00
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;
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)
406 cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
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;
416 if (glyph == INVALID_GLYPH)
417 goto FAIL;
419 if (!CGFontGetGlyphAdvancesPtr (font_face->cgFont, &glyph, 1, &advance) ||
420 !CGFontGetGlyphBBoxesPtr (font_face->cgFont, &glyph, 1, &bbox))
421 goto FAIL;
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;
433 bbox = CGRectMake (bbox.origin.x / emscale,
434 bbox.origin.y / emscale,
435 bbox.size.width / emscale,
436 bbox.size.height / emscale);
438 /* Should we want to always integer-align glyph extents, we can do so in this way */
439 #if 0
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);
448 bbox = CGRectApplyAffineTransform (bbox, textMatrix);
449 bbox = CGRectIntegral (bbox);
450 bbox = CGRectApplyAffineTransform (bbox, CGAffineTransformInvert (textMatrix));
452 #endif
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
460 xmin = CGRectGetMinX(bbox);
461 ymin = CGRectGetMinY(bbox);
462 xmax = CGRectGetMaxX(bbox);
463 ymax = CGRectGetMaxY(bbox);
465 extents.x_bearing = xmin;
466 extents.y_bearing = - ymax;
467 extents.width = xmax - xmin;
468 extents.height = ymax - ymin;
470 extents.x_advance = (double) advance / emscale;
471 extents.y_advance = 0.0;
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
478 FAIL:
479 _cairo_scaled_glyph_set_metrics (scaled_glyph,
480 &font->base,
481 &extents);
483 return status;
486 static void
487 _cairo_quartz_path_apply_func (void *info, const CGPathElement *el)
489 cairo_path_fixed_t *path = (cairo_path_fixed_t *) info;
490 cairo_status_t status;
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);
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));
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;
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)
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;
551 if (glyph == INVALID_GLYPH) {
552 _cairo_scaled_glyph_set_path (scaled_glyph, &font->base, _cairo_path_fixed_create());
553 return CAIRO_STATUS_SUCCESS;
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);
563 ctFont = CTFontCreateWithGraphicsFont (font_face->cgFont, 1.0, NULL, NULL);
564 glyphPath = CTFontCreatePathForGlyph (ctFont, glyph, &textMatrix);
565 CFRelease (ctFont);
566 if (!glyphPath)
567 return CAIRO_INT_STATUS_UNSUPPORTED;
569 path = _cairo_path_fixed_create ();
570 if (!path) {
571 CGPathRelease (glyphPath);
572 return _cairo_error(CAIRO_STATUS_NO_MEMORY);
575 CGPathApply (glyphPath, path, _cairo_quartz_path_apply_func);
577 CGPathRelease (glyphPath);
579 _cairo_scaled_glyph_set_path (scaled_glyph, &font->base, path);
581 return CAIRO_STATUS_SUCCESS;
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)
588 cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
590 cairo_quartz_font_face_t *font_face = _cairo_quartz_scaled_to_face(font);
592 cairo_image_surface_t *surface = NULL;
594 CGGlyph glyph = _cairo_quartz_scaled_glyph_index (scaled_glyph);
596 int advance;
597 CGRect bbox;
598 double width, height;
599 double emscale = CGFontGetUnitsPerEmPtr (font_face->cgFont);
601 CGContextRef cgContext = NULL;
602 CGAffineTransform textMatrix;
603 CGRect glyphRect, glyphRectInt;
604 CGPoint glyphOrigin;
606 //fprintf (stderr, "scaled_glyph: %p surface: %p\n", scaled_glyph, scaled_glyph->surface);
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.
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;
618 _cairo_scaled_glyph_set_surface (scaled_glyph,
619 &font->base,
620 surface);
621 return CAIRO_STATUS_SUCCESS;
624 if (!CGFontGetGlyphAdvancesPtr (font_face->cgFont, &glyph, 1, &advance) ||
625 !CGFontGetGlyphBBoxesPtr (font_face->cgFont, &glyph, 1, &bbox))
627 return CAIRO_INT_STATUS_UNSUPPORTED;
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);
641 glyphRect = CGRectApplyAffineTransform (glyphRect, textMatrix);
643 /* Round the rectangle outwards, so that we don't have to deal
644 * with non-integer-pixel origins or dimensions.
646 glyphRectInt = CGRectIntegral (glyphRect);
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
655 glyphOrigin = glyphRectInt.origin;
657 //textMatrix = CGAffineTransformConcat (textMatrix, CGAffineTransformInvert (ctm));
659 width = glyphRectInt.size.width;
660 height = glyphRectInt.size.height;
662 //fprintf (stderr, "glyphRect[n]: %f %f %f %f\n", glyphRect.origin.x, glyphRect.origin.y, glyphRect.size.width, glyphRect.size.height);
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;
668 if (surface->width != 0 && surface->height != 0) {
669 cgContext = CGBitmapContextCreate (surface->data,
670 surface->width,
671 surface->height,
673 surface->stride,
674 NULL,
675 kCGImageAlphaOnly);
677 if (cgContext == NULL) {
678 cairo_surface_destroy (&surface->base);
679 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
682 CGContextSetFont (cgContext, font_face->cgFont);
683 CGContextSetFontSize (cgContext, 1.0);
684 CGContextSetTextMatrix (cgContext, textMatrix);
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;
710 CGContextSetAlpha (cgContext, 1.0);
711 CGContextShowGlyphsAtPoint (cgContext, - glyphOrigin.x, - glyphOrigin.y, &glyph, 1);
713 CGContextRelease (cgContext);
716 cairo_surface_set_device_offset (&surface->base,
717 - glyphOrigin.x,
718 height + glyphOrigin.y);
720 _cairo_scaled_glyph_set_surface (scaled_glyph, &font->base, surface);
722 return status;
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)
730 cairo_quartz_scaled_font_t *font = (cairo_quartz_scaled_font_t *) abstract_font;
731 cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
733 if (!status && (info & CAIRO_SCALED_GLYPH_INFO_METRICS))
734 status = _cairo_quartz_init_glyph_metrics (font, scaled_glyph);
736 if (!status && (info & CAIRO_SCALED_GLYPH_INFO_PATH))
737 status = _cairo_quartz_init_glyph_path (font, scaled_glyph);
739 if (!status && (info & CAIRO_SCALED_GLYPH_INFO_SURFACE))
740 status = _cairo_quartz_init_glyph_surface (font, scaled_glyph);
742 return status;
745 static unsigned long
746 _cairo_quartz_ucs4_to_index (void *abstract_font,
747 uint32_t ucs4)
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;
754 CGFontGetGlyphsForUnicharsPtr (ffont->cgFont, &u, &glyph, 1);
756 return glyph;
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)
766 cairo_quartz_font_face_t *font_face = _cairo_quartz_scaled_to_face (abstract_font);
767 CFDataRef data = NULL;
769 if (likely (CGFontCopyTableForTagPtr))
770 data = CGFontCopyTableForTagPtr (font_face->cgFont, tag);
772 if (!data)
773 return CAIRO_INT_STATUS_UNSUPPORTED;
775 if (buffer == NULL) {
776 *length = CFDataGetLength (data);
777 CFRelease (data);
778 return CAIRO_STATUS_SUCCESS;
781 if (CFDataGetLength (data) < offset + (long) *length) {
782 CFRelease (data);
783 return CAIRO_INT_STATUS_UNSUPPORTED;
786 CFDataGetBytes (data, CFRangeMake (offset, *length), buffer);
787 CFRelease (data);
789 return CAIRO_STATUS_SUCCESS;
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 */
803 * private methods that the quartz surface uses
806 CGFontRef
807 _cairo_quartz_scaled_font_get_cg_font_ref (cairo_scaled_font_t *abstract_font)
809 cairo_quartz_font_face_t *ffont = _cairo_quartz_scaled_to_face(abstract_font);
811 return ffont->cgFont;
815 * compat with old ATSUI backend
819 * cairo_quartz_font_face_create_for_atsu_font_id:
820 * @font_id: an ATSUFontID for the font.
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().
826 * Return value: a newly created #cairo_font_face_t. Free with
827 * cairo_font_face_destroy() when you are done using it.
829 * Since: 1.6
831 cairo_font_face_t *
832 cairo_quartz_font_face_create_for_atsu_font_id (ATSUFontID font_id)
834 quartz_font_ensure_symbols();
836 if (FMGetATSFontRefFromFontPtr != NULL) {
837 ATSFontRef atsFont = FMGetATSFontRefFromFontPtr (font_id);
838 CGFontRef cgFont = CGFontCreateWithPlatformFont (&atsFont);
839 cairo_font_face_t *ff;
841 ff = cairo_quartz_font_face_create_for_cgfont (cgFont);
843 CGFontRelease (cgFont);
845 return ff;
846 } else {
847 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
848 return (cairo_font_face_t *)&_cairo_font_face_nil;
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);
855 cairo_font_face_t *
856 cairo_atsui_font_face_create_for_atsu_font_id (ATSUFontID font_id)
858 return cairo_quartz_font_face_create_for_atsu_font_id (font_id);