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.
34 * Vladimir Vukicevic <vladimir@mozilla.com>
41 #include "cairo-image-surface-private.h"
42 #include "cairo-quartz.h"
43 #include "cairo-quartz-private.h"
45 #include "cairo-error-private.h"
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.
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.
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 */
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
;
102 quartz_font_ensure_symbols(void)
104 if (_cairo_quartz_font_symbol_lookup_done
)
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
;
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
)
172 CFStringRef cgFontName
= NULL
;
173 CGFontRef cgFont
= NULL
;
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"))
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"))
191 else if (!strcmp(family
, "monospace") || !strcmp(family
, "mono"))
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
++) {
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
);
221 cgFont
= CGFontCreateWithNamePtr (full_name
);
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
;
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
);
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
;
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
));
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
);
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;
296 quartz_CGFontMetrics
*m
;
297 m
= CGFontGetHMetricsPtr (font_face
->cgFont
);
299 /* On OX 10.4, GetHMetricsPtr sometimes returns NULL for unknown reasons */
301 status
= _cairo_error(CAIRO_STATUS_NULL_POINTER
);
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? */
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;
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
);
324 if (status
!= CAIRO_STATUS_SUCCESS
) {
327 *font_out
= (cairo_scaled_font_t
*) font
;
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.
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
));
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
;
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
);
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
);
413 double emscale
= CGFontGetUnitsPerEmPtr (font_face
->cgFont
);
414 double xmin
, ymin
, xmax
, ymax
;
416 if (glyph
== INVALID_GLYPH
)
419 if (!CGFontGetGlyphAdvancesPtr (font_face
->cgFont
, &glyph
, 1, &advance
) ||
420 !CGFontGetGlyphBBoxesPtr (font_face
->cgFont
, &glyph
, 1, &bbox
))
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 */
441 CGAffineTransform textMatrix
;
442 textMatrix
= CGAffineTransformMake (font
->base
.scale
.xx
,
443 -font
->base
.scale
.yx
,
444 -font
->base
.scale
.xy
,
448 bbox
= CGRectApplyAffineTransform (bbox
, textMatrix
);
449 bbox
= CGRectIntegral (bbox
);
450 bbox
= CGRectApplyAffineTransform (bbox
, CGAffineTransformInvert (textMatrix
));
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
);
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;
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
);
479 _cairo_scaled_glyph_set_metrics (scaled_glyph
,
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
;
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
));
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
));
505 case kCGPathElementAddQuadCurveToPoint
: {
506 cairo_fixed_t fx
, fy
;
508 if (!_cairo_path_fixed_get_current_point (path
, &fx
, &fy
))
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
));
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
));
533 case kCGPathElementCloseSubpath
:
534 status
= _cairo_path_fixed_close_path (path
);
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
;
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
,
559 -font
->base
.scale
.xy
,
560 -font
->base
.scale
.yy
,
563 ctFont
= CTFontCreateWithGraphicsFont (font_face
->cgFont
, 1.0, NULL
, NULL
);
564 glyphPath
= CTFontCreatePathForGlyph (ctFont
, glyph
, &textMatrix
);
567 return CAIRO_INT_STATUS_UNSUPPORTED
;
569 path
= _cairo_path_fixed_create ();
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
);
598 double width
, height
;
599 double emscale
= CGFontGetUnitsPerEmPtr (font_face
->cgFont
);
601 CGContextRef cgContext
= NULL
;
602 CGAffineTransform textMatrix
;
603 CGRect glyphRect
, glyphRectInt
;
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
);
618 _cairo_scaled_glyph_set_surface (scaled_glyph
,
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
,
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
);
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
);
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
,
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
);
695 case CAIRO_ANTIALIAS_NONE
:
696 CGContextSetShouldAntialias (cgContext
, FALSE
);
698 case CAIRO_ANTIALIAS_GRAY
:
699 case CAIRO_ANTIALIAS_GOOD
:
700 case CAIRO_ANTIALIAS_FAST
:
701 CGContextSetShouldAntialias (cgContext
, TRUE
);
702 CGContextSetShouldSmoothFonts (cgContext
, FALSE
);
704 case CAIRO_ANTIALIAS_DEFAULT
:
706 /* Don't do anything */
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
,
718 height
+ glyphOrigin
.y
);
720 _cairo_scaled_glyph_set_surface (scaled_glyph
, &font
->base
, surface
);
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
);
746 _cairo_quartz_ucs4_to_index (void *abstract_font
,
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
;
754 CGFontGetGlyphsForUnicharsPtr (ffont
->cgFont
, &u
, &glyph
, 1);
759 static cairo_int_status_t
760 _cairo_quartz_load_truetype_table (void *abstract_font
,
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
);
773 return CAIRO_INT_STATUS_UNSUPPORTED
;
775 if (buffer
== NULL
) {
776 *length
= CFDataGetLength (data
);
778 return CAIRO_STATUS_SUCCESS
;
781 if (CFDataGetLength (data
) < offset
+ (long) *length
) {
783 return CAIRO_INT_STATUS_UNSUPPORTED
;
786 CFDataGetBytes (data
, CFRangeMake (offset
, *length
), buffer
);
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
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.
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
);
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
);
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
);