Updated: Sudoku no longer crashes
[moon.git] / cairo / src / cairo-quartz-font.c
blob2bca37200eb27d31b13b6c672f3b5cc7cde47668
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 Corporation.
33 * Contributor(s):
34 * Vladimir Vukicevic <vladimir@mozilla.com>
37 #include "cairoint.h"
39 #include <dlfcn.h>
41 #include "cairo-quartz.h"
42 #include "cairo-quartz-private.h"
44 /* CreateWithFontName exists in 10.5, but not in 10.4; CreateWithName isn't public in 10.4 */
45 static CGFontRef (*CGFontCreateWithFontNamePtr) (CFStringRef) = NULL;
46 static CGFontRef (*CGFontCreateWithNamePtr) (const char *) = NULL;
48 /* These aren't public before 10.5, and some have different names in 10.4 */
49 static int (*CGFontGetUnitsPerEmPtr) (CGFontRef) = NULL;
50 static bool (*CGFontGetGlyphAdvancesPtr) (CGFontRef, const CGGlyph[], size_t, int[]) = NULL;
51 static bool (*CGFontGetGlyphBBoxesPtr) (CGFontRef, const CGGlyph[], size_t, CGRect[]) = NULL;
52 static CGRect (*CGFontGetFontBBoxPtr) (CGFontRef) = NULL;
54 /* Not public, but present */
55 static void (*CGFontGetGlyphsForUnicharsPtr) (CGFontRef, const UniChar[], const CGGlyph[], size_t) = NULL;
57 /* Not public in the least bit */
58 static CGPathRef (*CGFontGetGlyphPathPtr) (CGFontRef fontRef, CGAffineTransform *textTransform, int unknown, CGGlyph glyph) = NULL;
60 /* CGFontGetHMetrics isn't public, but the other functions are public/present in 10.5 */
61 typedef struct {
62 int ascent;
63 int descent;
64 int leading;
65 } quartz_CGFontMetrics;
66 static quartz_CGFontMetrics* (*CGFontGetHMetricsPtr) (CGFontRef fontRef) = NULL;
67 static int (*CGFontGetAscentPtr) (CGFontRef fontRef) = NULL;
68 static int (*CGFontGetDescentPtr) (CGFontRef fontRef) = NULL;
69 static int (*CGFontGetLeadingPtr) (CGFontRef fontRef) = NULL;
71 static cairo_bool_t _cairo_quartz_font_symbol_lookup_done = FALSE;
72 static cairo_bool_t _cairo_quartz_font_symbols_present = FALSE;
74 static void
75 quartz_font_ensure_symbols(void)
77 if (_cairo_quartz_font_symbol_lookup_done)
78 return;
80 /* Look for the 10.5 versions first */
81 CGFontGetGlyphBBoxesPtr = dlsym(RTLD_DEFAULT, "CGFontGetGlyphBBoxes");
82 if (!CGFontGetGlyphBBoxesPtr)
83 CGFontGetGlyphBBoxesPtr = dlsym(RTLD_DEFAULT, "CGFontGetGlyphBoundingBoxes");
85 CGFontGetGlyphsForUnicharsPtr = dlsym(RTLD_DEFAULT, "CGFontGetGlyphsForUnichars");
86 if (!CGFontGetGlyphsForUnicharsPtr)
87 CGFontGetGlyphsForUnicharsPtr = dlsym(RTLD_DEFAULT, "CGFontGetGlyphsForUnicodes");
89 CGFontGetFontBBoxPtr = dlsym(RTLD_DEFAULT, "CGFontGetFontBBox");
91 /* We just need one of these two */
92 CGFontCreateWithFontNamePtr = dlsym(RTLD_DEFAULT, "CGFontCreateWithFontName");
93 CGFontCreateWithNamePtr = dlsym(RTLD_DEFAULT, "CGFontCreateWithName");
95 /* These have the same name in 10.4 and 10.5 */
96 CGFontGetUnitsPerEmPtr = dlsym(RTLD_DEFAULT, "CGFontGetUnitsPerEm");
97 CGFontGetGlyphAdvancesPtr = dlsym(RTLD_DEFAULT, "CGFontGetGlyphAdvances");
98 CGFontGetGlyphPathPtr = dlsym(RTLD_DEFAULT, "CGFontGetGlyphPath");
100 CGFontGetHMetricsPtr = dlsym(RTLD_DEFAULT, "CGFontGetHMetrics");
101 CGFontGetAscentPtr = dlsym(RTLD_DEFAULT, "CGFontGetAscent");
102 CGFontGetDescentPtr = dlsym(RTLD_DEFAULT, "CGFontGetDescent");
103 CGFontGetLeadingPtr = dlsym(RTLD_DEFAULT, "CGFontGetLeading");
105 if ((CGFontCreateWithFontNamePtr || CGFontCreateWithNamePtr) &&
106 CGFontGetGlyphBBoxesPtr &&
107 CGFontGetGlyphsForUnicharsPtr &&
108 CGFontGetUnitsPerEmPtr &&
109 CGFontGetGlyphAdvancesPtr &&
110 CGFontGetGlyphPathPtr &&
111 (CGFontGetHMetricsPtr || (CGFontGetAscentPtr && CGFontGetDescentPtr && CGFontGetLeadingPtr)))
112 _cairo_quartz_font_symbols_present = TRUE;
114 _cairo_quartz_font_symbol_lookup_done = TRUE;
117 typedef struct _cairo_quartz_font_face cairo_quartz_font_face_t;
118 typedef struct _cairo_quartz_scaled_font cairo_quartz_scaled_font_t;
120 struct _cairo_quartz_scaled_font {
121 cairo_scaled_font_t base;
124 struct _cairo_quartz_font_face {
125 cairo_font_face_t base;
127 CGFontRef cgFont;
131 * font face backend
134 static void
135 _cairo_quartz_font_face_destroy (void *abstract_face)
137 cairo_quartz_font_face_t *font_face = (cairo_quartz_font_face_t*) abstract_face;
139 CGFontRelease (font_face->cgFont);
142 static cairo_status_t
143 _cairo_quartz_font_face_scaled_font_create (void *abstract_face,
144 const cairo_matrix_t *font_matrix,
145 const cairo_matrix_t *ctm,
146 const cairo_font_options_t *options,
147 cairo_scaled_font_t **font_out)
149 cairo_quartz_font_face_t *font_face = abstract_face;
150 cairo_quartz_scaled_font_t *font = NULL;
151 cairo_status_t status;
152 cairo_font_extents_t fs_metrics;
153 double ems;
154 CGRect bbox;
156 quartz_font_ensure_symbols();
157 if (!_cairo_quartz_font_symbols_present)
158 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
160 font = malloc(sizeof(cairo_quartz_scaled_font_t));
161 if (font == NULL)
162 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
164 memset (font, 0, sizeof(cairo_quartz_scaled_font_t));
166 status = _cairo_scaled_font_init (&font->base,
167 &font_face->base, font_matrix, ctm, options,
168 &_cairo_quartz_scaled_font_backend);
169 if (status)
170 goto FINISH;
172 ems = CGFontGetUnitsPerEmPtr (font_face->cgFont);
174 /* initialize metrics */
175 if (CGFontGetFontBBoxPtr && CGFontGetAscentPtr) {
176 fs_metrics.ascent = (CGFontGetAscentPtr (font_face->cgFont) / ems);
177 fs_metrics.descent = - (CGFontGetDescentPtr (font_face->cgFont) / ems);
178 fs_metrics.height = fs_metrics.ascent + fs_metrics.descent +
179 (CGFontGetLeadingPtr (font_face->cgFont) / ems);
181 bbox = CGFontGetFontBBoxPtr (font_face->cgFont);
182 fs_metrics.max_x_advance = CGRectGetMaxX(bbox) / ems;
183 fs_metrics.max_y_advance = 0.0;
184 } else {
185 CGGlyph wGlyph;
186 UniChar u;
188 quartz_CGFontMetrics *m;
189 m = CGFontGetHMetricsPtr (font_face->cgFont);
191 /* On OX 10.4, GetHMetricsPtr sometimes returns NULL for unknown reasons */
192 if (!m) {
193 status = _cairo_error(CAIRO_STATUS_NULL_POINTER);
194 goto FINISH;
197 fs_metrics.ascent = (m->ascent / ems);
198 fs_metrics.descent = - (m->descent / ems);
199 fs_metrics.height = fs_metrics.ascent + fs_metrics.descent + (m->leading / ems);
201 /* We kind of have to guess here; W's big, right? */
202 u = (UniChar) 'W';
203 CGFontGetGlyphsForUnicharsPtr (font_face->cgFont, &u, &wGlyph, 1);
204 if (wGlyph && CGFontGetGlyphBBoxesPtr (font_face->cgFont, &wGlyph, 1, &bbox)) {
205 fs_metrics.max_x_advance = CGRectGetMaxX(bbox) / ems;
206 fs_metrics.max_y_advance = 0.0;
207 } else {
208 fs_metrics.max_x_advance = 0.0;
209 fs_metrics.max_y_advance = 0.0;
213 status = _cairo_scaled_font_set_metrics (&font->base, &fs_metrics);
215 FINISH:
216 if (status != CAIRO_STATUS_SUCCESS) {
217 free (font);
218 } else {
219 *font_out = (cairo_scaled_font_t*) font;
222 return status;
225 static const cairo_font_face_backend_t _cairo_quartz_font_face_backend = {
226 CAIRO_FONT_TYPE_QUARTZ,
227 _cairo_quartz_font_face_destroy,
228 NULL, /* direct implementation */
229 _cairo_quartz_font_face_scaled_font_create
233 * cairo_quartz_font_face_create_for_cgfont
234 * @font: a #CGFontRef obtained through a method external to cairo.
236 * Creates a new font for the Quartz font backend based on a
237 * #CGFontRef. This font can then be used with
238 * cairo_set_font_face() or cairo_scaled_font_create().
240 * Return value: a newly created #cairo_font_face_t. Free with
241 * cairo_font_face_destroy() when you are done using it.
243 * Since: 1.6
245 cairo_font_face_t *
246 cairo_quartz_font_face_create_for_cgfont (CGFontRef font)
248 cairo_quartz_font_face_t *font_face;
250 quartz_font_ensure_symbols();
252 font_face = malloc (sizeof (cairo_quartz_font_face_t));
253 if (!font_face) {
254 _cairo_error (CAIRO_STATUS_NO_MEMORY);
255 return (cairo_font_face_t *)&_cairo_font_face_nil;
258 font_face->cgFont = CGFontRetain (font);
260 _cairo_font_face_init (&font_face->base, &_cairo_quartz_font_face_backend);
262 return &font_face->base;
266 * scaled font backend
269 static cairo_quartz_font_face_t *
270 _cairo_quartz_scaled_to_face (void *abstract_font)
272 cairo_quartz_scaled_font_t *sfont = (cairo_quartz_scaled_font_t*) abstract_font;
273 cairo_font_face_t *font_face = cairo_scaled_font_get_font_face (&sfont->base);
274 if (!font_face || font_face->backend->type != CAIRO_FONT_TYPE_QUARTZ)
275 return NULL;
277 return (cairo_quartz_font_face_t*) font_face;
280 static cairo_status_t
281 _cairo_quartz_font_get_implementation (cairo_toy_font_face_t *toy_face,
282 cairo_scaled_font_t **font_face_out)
284 static cairo_user_data_key_t impl_font_face_key;
285 cairo_font_face_t *face;
286 cairo_status_t status;
287 const char *family = toy_face->family;
288 char *full_name = malloc(strlen(family) + 64); // give us a bit of room to tack on Bold, Oblique, etc.
289 CFStringRef cgFontName = NULL;
290 CGFontRef cgFont = NULL;
291 int loop;
293 face = cairo_font_face_get_user_data (&toy_face->base,
294 &impl_font_face_key);
295 if (face) {
296 *font_face_out = face;
297 return CAIRO_STATUS_SUCCESS;
300 quartz_font_ensure_symbols();
301 if (! _cairo_quartz_font_symbols_present)
302 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
304 /* handle CSS-ish faces */
305 if (!strcmp(family, "serif") || !strcmp(family, "Times Roman"))
306 family = "Times";
307 else if (!strcmp(family, "sans-serif") || !strcmp(family, "sans"))
308 family = "Helvetica";
309 else if (!strcmp(family, "cursive"))
310 family = "Apple Chancery";
311 else if (!strcmp(family, "fantasy"))
312 family = "Papyrus";
313 else if (!strcmp(family, "monospace") || !strcmp(family, "mono"))
314 family = "Courier";
316 /* Try to build up the full name, e.g. "Helvetica Bold Oblique" first,
317 * then drop the bold, then drop the slant, then drop both.. finally
318 * just use "Helvetica". And if Helvetica doesn't exist, give up.
320 for (loop = 0; loop < 5; loop++) {
321 if (loop == 4)
322 family = "Helvetica";
324 strcpy (full_name, family);
326 if (loop < 3 && (loop & 1) == 0) {
327 if (toy_face->weight == CAIRO_FONT_WEIGHT_BOLD)
328 strcat (full_name, " Bold");
331 if (loop < 3 && (loop & 2) == 0) {
332 if (toy_face->slant == CAIRO_FONT_SLANT_ITALIC)
333 strcat (full_name, " Italic");
334 else if (toy_face->slant == CAIRO_FONT_SLANT_OBLIQUE)
335 strcat (full_name, " Oblique");
338 if (CGFontCreateWithFontNamePtr) {
339 cgFontName = CFStringCreateWithCString (NULL, full_name, kCFStringEncodingASCII);
340 cgFont = CGFontCreateWithFontNamePtr (cgFontName);
341 CFRelease (cgFontName);
342 } else {
343 cgFont = CGFontCreateWithNamePtr (full_name);
346 if (cgFont)
347 break;
350 if (!cgFont) {
351 /* Give up */
352 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
355 face = cairo_quartz_font_face_create_for_cgfont (cgFont);
356 CGFontRelease (cgFont);
358 if (face->status)
359 return face->status;
361 status = cairo_font_face_set_user_data (&toy_face->base,
362 &impl_font_face_key,
363 face,
364 (cairo_destroy_func_t) cairo_font_face_destroy);
366 if (status) {
367 cairo_font_face_destroy (face);
368 return status;
371 *font_face_out = face;
372 return CAIRO_STATUS_SUCCESS;
375 static cairo_status_t
376 _cairo_quartz_font_create_toy (cairo_toy_font_face_t *toy_face,
377 const cairo_matrix_t *font_matrix,
378 const cairo_matrix_t *ctm,
379 const cairo_font_options_t *options,
380 cairo_scaled_font_t **font_out)
382 cairo_font_face_t *face;
383 cairo_scaled_font_t *scaled_font;
384 cairo_status_t status;
386 status = _cairo_quartz_font_get_implementation (toy_face, &face);
387 if (status)
388 return status;
390 status = _cairo_quartz_font_face_scaled_font_create (face,
391 font_matrix, ctm,
392 options,
393 &scaled_font);
394 cairo_font_face_destroy (face);
395 if (status)
396 return status;
398 *font_out = scaled_font;
399 return CAIRO_STATUS_SUCCESS;
402 static void
403 _cairo_quartz_font_fini(void *abstract_font)
407 #define INVALID_GLYPH 0x00
409 static inline CGGlyph
410 _cairo_quartz_scaled_glyph_index (cairo_scaled_glyph_t *scaled_glyph) {
411 unsigned long index = _cairo_scaled_glyph_index (scaled_glyph);
412 if (index > 0xffff)
413 return INVALID_GLYPH;
414 return (CGGlyph) index;
417 static inline cairo_status_t
418 _cairo_matrix_to_unit_quartz_matrix (const cairo_matrix_t *m, CGAffineTransform *txout,
419 double *xout, double *yout)
421 CGAffineTransform transform;
422 double xscale, yscale;
423 cairo_status_t status;
425 status = _cairo_matrix_compute_basis_scale_factors (m, &xscale, &yscale, 1);
426 if (status)
427 return status;
429 transform = CGAffineTransformMake (m->xx, - m->yx,
430 - m->xy, m->yy,
431 0.0f, 0.0f);
432 if (xout)
433 *xout = xscale;
434 if (yout)
435 *yout = yscale;
437 if (xscale)
438 xscale = 1.0 / xscale;
439 if (yscale)
440 yscale = 1.0 / yscale;
442 *txout = CGAffineTransformScale (transform, xscale, yscale);
444 return CAIRO_STATUS_SUCCESS;
447 static cairo_int_status_t
448 _cairo_quartz_init_glyph_metrics (cairo_quartz_scaled_font_t *font,
449 cairo_scaled_glyph_t *scaled_glyph)
451 cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
453 cairo_quartz_font_face_t *font_face = _cairo_quartz_scaled_to_face(font);
454 cairo_text_extents_t extents = {0, 0, 0, 0, 0, 0};
455 CGAffineTransform textMatrix;
456 CGGlyph glyph = _cairo_quartz_scaled_glyph_index (scaled_glyph);
457 int advance;
458 CGRect bbox;
459 double emscale = CGFontGetUnitsPerEmPtr (font_face->cgFont);
460 double xscale, yscale;
461 double xmin, ymin, xmax, ymax;
463 if (glyph == INVALID_GLYPH)
464 goto FAIL;
466 if (!CGFontGetGlyphAdvancesPtr (font_face->cgFont, &glyph, 1, &advance) ||
467 !CGFontGetGlyphBBoxesPtr (font_face->cgFont, &glyph, 1, &bbox))
468 goto FAIL;
470 status = _cairo_matrix_compute_basis_scale_factors (&font->base.scale,
471 &xscale, &yscale, 1);
472 if (status)
473 goto FAIL;
475 bbox = CGRectMake (bbox.origin.x / emscale,
476 bbox.origin.y / emscale,
477 bbox.size.width / emscale,
478 bbox.size.height / emscale);
480 /* Should we want to always integer-align glyph extents, we can do so in this way */
481 #if 0
483 CGAffineTransform textMatrix;
484 textMatrix = CGAffineTransformMake (font->base.scale.xx,
485 -font->base.scale.yx,
486 -font->base.scale.xy,
487 font->base.scale.yy,
488 0.0f, 0.0f);
490 bbox = CGRectApplyAffineTransform (bbox, textMatrix);
491 bbox = CGRectIntegral (bbox);
492 bbox = CGRectApplyAffineTransform (bbox, CGAffineTransformInvert (textMatrix));
494 #endif
496 #if 0
497 fprintf (stderr, "[0x%04x] bbox: %f %f %f %f\n", glyph,
498 bbox.origin.x / emscale, bbox.origin.y / emscale,
499 bbox.size.width / emscale, bbox.size.height / emscale);
500 #endif
502 xmin = CGRectGetMinX(bbox);
503 ymin = CGRectGetMinY(bbox);
504 xmax = CGRectGetMaxX(bbox);
505 ymax = CGRectGetMaxY(bbox);
507 extents.x_bearing = xmin;
508 extents.y_bearing = - ymax;
509 extents.width = xmax - xmin;
510 extents.height = ymax - ymin;
512 extents.x_advance = (double) advance / emscale;
513 extents.y_advance = 0.0;
515 #if 0
516 fprintf (stderr, "[0x%04x] extents: bearings: %f %f dim: %f %f adv: %f\n\n", glyph,
517 extents.x_bearing, extents.y_bearing, extents.width, extents.height, extents.x_advance);
518 #endif
520 FAIL:
521 _cairo_scaled_glyph_set_metrics (scaled_glyph,
522 &font->base,
523 &extents);
525 return status;
528 static void
529 _cairo_quartz_path_apply_func (void *info, const CGPathElement *el)
531 cairo_path_fixed_t *path = (cairo_path_fixed_t *) info;
533 switch (el->type) {
534 case kCGPathElementMoveToPoint:
535 _cairo_path_fixed_move_to (path,
536 _cairo_fixed_from_double(el->points[0].x),
537 _cairo_fixed_from_double(el->points[0].y));
538 break;
539 case kCGPathElementAddLineToPoint:
540 _cairo_path_fixed_line_to (path,
541 _cairo_fixed_from_double(el->points[0].x),
542 _cairo_fixed_from_double(el->points[0].y));
543 break;
544 case kCGPathElementAddQuadCurveToPoint: {
545 cairo_fixed_t fx, fy;
546 double x, y;
547 if (!_cairo_path_fixed_get_current_point (path, &fx, &fy))
548 fx = fy = 0;
549 x = _cairo_fixed_to_double (fx);
550 y = _cairo_fixed_to_double (fy);
552 _cairo_path_fixed_curve_to (path,
553 _cairo_fixed_from_double((x + el->points[0].x * 2.0) / 3.0),
554 _cairo_fixed_from_double((y + el->points[0].y * 2.0) / 3.0),
555 _cairo_fixed_from_double((el->points[0].x * 2.0 + el->points[1].x) / 3.0),
556 _cairo_fixed_from_double((el->points[0].y * 2.0 + el->points[1].y) / 3.0),
557 _cairo_fixed_from_double(el->points[1].x),
558 _cairo_fixed_from_double(el->points[1].y));
560 break;
561 case kCGPathElementAddCurveToPoint:
562 _cairo_path_fixed_curve_to (path,
563 _cairo_fixed_from_double(el->points[0].x),
564 _cairo_fixed_from_double(el->points[0].y),
565 _cairo_fixed_from_double(el->points[1].x),
566 _cairo_fixed_from_double(el->points[1].y),
567 _cairo_fixed_from_double(el->points[2].x),
568 _cairo_fixed_from_double(el->points[2].y));
569 break;
570 case kCGPathElementCloseSubpath:
571 _cairo_path_fixed_close_path (path);
572 break;
576 static cairo_int_status_t
577 _cairo_quartz_init_glyph_path (cairo_quartz_scaled_font_t *font,
578 cairo_scaled_glyph_t *scaled_glyph)
580 cairo_quartz_font_face_t *font_face = _cairo_quartz_scaled_to_face(font);
581 CGGlyph glyph = _cairo_quartz_scaled_glyph_index (scaled_glyph);
582 CGAffineTransform textMatrix;
583 CGPathRef glyphPath;
584 cairo_path_fixed_t *path;
586 if (glyph == INVALID_GLYPH) {
587 _cairo_scaled_glyph_set_path (scaled_glyph, &font->base, _cairo_path_fixed_create());
588 return CAIRO_STATUS_SUCCESS;
591 textMatrix = CGAffineTransformMake (font->base.scale.xx,
592 -font->base.scale.yx,
593 -font->base.scale.xy,
594 font->base.scale.yy,
595 font->base.scale.x0,
596 font->base.scale.y0);
598 textMatrix = CGAffineTransformConcat (textMatrix, CGAffineTransformMake (1.0, 0.0, 0.0, -1.0, 0.0, 0.0));
600 glyphPath = CGFontGetGlyphPathPtr (font_face->cgFont, &textMatrix, 0, glyph);
601 if (!glyphPath)
602 return CAIRO_INT_STATUS_UNSUPPORTED;
604 path = _cairo_path_fixed_create ();
605 if (!path) {
606 CGPathRelease (glyphPath);
607 return _cairo_error(CAIRO_STATUS_NO_MEMORY);
610 CGPathApply (glyphPath, path, _cairo_quartz_path_apply_func);
612 CGPathRelease (glyphPath);
614 _cairo_scaled_glyph_set_path (scaled_glyph, &font->base, path);
616 return CAIRO_STATUS_SUCCESS;
619 static cairo_int_status_t
620 _cairo_quartz_init_glyph_surface (cairo_quartz_scaled_font_t *font,
621 cairo_scaled_glyph_t *scaled_glyph)
623 cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
625 cairo_quartz_font_face_t *font_face = _cairo_quartz_scaled_to_face(font);
627 cairo_image_surface_t *surface = NULL;
629 CGGlyph glyph = _cairo_quartz_scaled_glyph_index (scaled_glyph);
631 int advance;
632 CGRect bbox;
633 double width, height;
634 double xscale, yscale;
635 double emscale = CGFontGetUnitsPerEmPtr (font_face->cgFont);
637 CGColorSpaceRef gray;
638 CGContextRef cgContext = NULL;
639 CGAffineTransform textMatrix;
640 CGRect glyphRect, glyphRectInt;
641 CGPoint glyphOrigin;
643 //fprintf (stderr, "scaled_glyph: %p surface: %p\n", scaled_glyph, scaled_glyph->surface);
645 /* Create blank 2x2 image if we don't have this character.
646 * Maybe we should draw a better missing-glyph slug or something,
647 * but this is ok for now.
649 if (glyph == INVALID_GLYPH) {
650 surface = (cairo_image_surface_t*) cairo_image_surface_create (CAIRO_FORMAT_A8, 2, 2);
651 status = cairo_surface_status ((cairo_surface_t *) surface);
652 if (status)
653 return status;
655 _cairo_scaled_glyph_set_surface (scaled_glyph,
656 &font->base,
657 surface);
658 return CAIRO_STATUS_SUCCESS;
661 if (!CGFontGetGlyphAdvancesPtr (font_face->cgFont, &glyph, 1, &advance) ||
662 !CGFontGetGlyphBBoxesPtr (font_face->cgFont, &glyph, 1, &bbox))
664 return CAIRO_INT_STATUS_UNSUPPORTED;
667 status = _cairo_matrix_compute_basis_scale_factors (&font->base.scale,
668 &xscale, &yscale, 1);
669 if (status)
670 return status;
672 textMatrix = CGAffineTransformMake (font->base.scale.xx,
673 -font->base.scale.yx,
674 -font->base.scale.xy,
675 font->base.scale.yy,
676 0.0f, 0.0f);
677 glyphRect = CGRectMake (bbox.origin.x / emscale,
678 bbox.origin.y / emscale,
679 bbox.size.width / emscale,
680 bbox.size.height / emscale);
682 glyphRect = CGRectApplyAffineTransform (glyphRect, textMatrix);
684 /* Round the rectangle outwards, so that we don't have to deal
685 * with non-integer-pixel origins or dimensions.
687 glyphRectInt = CGRectIntegral (glyphRect);
689 #if 0
690 fprintf (stderr, "glyphRect[o]: %f %f %f %f\n",
691 glyphRect.origin.x, glyphRect.origin.y, glyphRect.size.width, glyphRect.size.height);
692 fprintf (stderr, "glyphRectInt: %f %f %f %f\n",
693 glyphRectInt.origin.x, glyphRectInt.origin.y, glyphRectInt.size.width, glyphRectInt.size.height);
694 #endif
696 glyphOrigin = glyphRectInt.origin;
698 //textMatrix = CGAffineTransformConcat (textMatrix, CGAffineTransformInvert (ctm));
700 width = glyphRectInt.size.width;
701 height = glyphRectInt.size.height;
703 //fprintf (stderr, "glyphRect[n]: %f %f %f %f\n", glyphRect.origin.x, glyphRect.origin.y, glyphRect.size.width, glyphRect.size.height);
705 surface = (cairo_image_surface_t*) cairo_image_surface_create (CAIRO_FORMAT_A8, width, height);
706 if (surface->base.status)
707 return surface->base.status;
709 gray = CGColorSpaceCreateDeviceGray ();
710 cgContext = CGBitmapContextCreate (surface->data,
711 surface->width,
712 surface->height,
714 surface->stride,
715 gray,
716 kCGImageAlphaNone);
717 CGColorSpaceRelease (gray);
719 CGContextSetFont (cgContext, font_face->cgFont);
720 CGContextSetFontSize (cgContext, 1.0);
721 CGContextSetTextMatrix (cgContext, textMatrix);
723 CGContextClearRect (cgContext, CGRectMake (0.0f, 0.0f, width, height));
725 if (font->base.options.antialias == CAIRO_ANTIALIAS_NONE)
726 CGContextSetShouldAntialias (cgContext, false);
728 CGContextSetRGBFillColor (cgContext, 1.0, 1.0, 1.0, 1.0);
729 CGContextShowGlyphsAtPoint (cgContext, - glyphOrigin.x, - glyphOrigin.y, &glyph, 1);
731 CGContextRelease (cgContext);
733 cairo_surface_set_device_offset (&surface->base,
734 - glyphOrigin.x,
735 height + glyphOrigin.y);
737 _cairo_scaled_glyph_set_surface (scaled_glyph, &font->base, surface);
739 return status;
742 static cairo_int_status_t
743 _cairo_quartz_font_scaled_glyph_init (void *abstract_font,
744 cairo_scaled_glyph_t *scaled_glyph,
745 cairo_scaled_glyph_info_t info)
747 cairo_quartz_scaled_font_t *font = (cairo_quartz_scaled_font_t *) abstract_font;
748 cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
750 if (!status && (info & CAIRO_SCALED_GLYPH_INFO_METRICS))
751 status = _cairo_quartz_init_glyph_metrics (font, scaled_glyph);
753 if (!status && (info & CAIRO_SCALED_GLYPH_INFO_PATH))
754 status = _cairo_quartz_init_glyph_path (font, scaled_glyph);
756 if (!status && (info & CAIRO_SCALED_GLYPH_INFO_SURFACE))
757 status = _cairo_quartz_init_glyph_surface (font, scaled_glyph);
759 return status;
762 static unsigned long
763 _cairo_quartz_ucs4_to_index (void *abstract_font,
764 uint32_t ucs4)
766 cairo_quartz_scaled_font_t *font = (cairo_quartz_scaled_font_t*) abstract_font;
767 cairo_quartz_font_face_t *ffont = _cairo_quartz_scaled_to_face(font);
768 UniChar u = (UniChar) ucs4;
769 CGGlyph glyph;
771 CGFontGetGlyphsForUnicharsPtr (ffont->cgFont, &u, &glyph, 1);
773 return glyph;
776 const cairo_scaled_font_backend_t _cairo_quartz_scaled_font_backend = {
777 CAIRO_FONT_TYPE_QUARTZ,
778 _cairo_quartz_font_get_implementation,
779 _cairo_quartz_font_create_toy,
780 _cairo_quartz_font_fini,
781 _cairo_quartz_font_scaled_glyph_init,
782 NULL, /* text_to_glyphs */
783 _cairo_quartz_ucs4_to_index,
784 NULL, /* show_glyphs */
785 NULL, /* load_truetype_table */
786 NULL, /* map_glyphs_to_unicode */
790 * private methods that the quartz surface uses
793 CGFontRef
794 _cairo_quartz_scaled_font_get_cg_font_ref (cairo_scaled_font_t *abstract_font)
796 cairo_quartz_font_face_t *ffont = _cairo_quartz_scaled_to_face(abstract_font);
798 return ffont->cgFont;
803 * compat with old ATSUI backend
807 * cairo_quartz_font_face_create_for_atsu_font_id
808 * @font_id: an ATSUFontID for the font.
810 * Creates a new font for the Quartz font backend based on an
811 * #ATSUFontID. This font can then be used with
812 * cairo_set_font_face() or cairo_scaled_font_create().
814 * Return value: a newly created #cairo_font_face_t. Free with
815 * cairo_font_face_destroy() when you are done using it.
817 * Since: 1.6
819 cairo_font_face_t *
820 cairo_quartz_font_face_create_for_atsu_font_id (ATSUFontID font_id)
822 ATSFontRef atsFont = FMGetATSFontRefFromFont (font_id);
823 CGFontRef cgFont = CGFontCreateWithPlatformFont (&atsFont);
824 cairo_font_face_t *ff;
826 ff = cairo_quartz_font_face_create_for_cgfont (cgFont);
828 CGFontRelease (cgFont);
830 return ff;
833 /* This is the old name for the above function, exported for compat purposes */
834 cairo_font_face_t *cairo_atsui_font_face_create_for_atsu_font_id (ATSUFontID font_id);
836 cairo_font_face_t *
837 cairo_atsui_font_face_create_for_atsu_font_id (ATSUFontID font_id)
839 return cairo_quartz_font_face_create_for_atsu_font_id (font_id);