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.
34 * Vladimir Vukicevic <vladimir@mozilla.com>
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 */
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
;
75 quartz_font_ensure_symbols(void)
77 if (_cairo_quartz_font_symbol_lookup_done
)
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
;
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
;
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
));
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
);
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;
188 quartz_CGFontMetrics
*m
;
189 m
= CGFontGetHMetricsPtr (font_face
->cgFont
);
191 /* On OX 10.4, GetHMetricsPtr sometimes returns NULL for unknown reasons */
193 status
= _cairo_error(CAIRO_STATUS_NULL_POINTER
);
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? */
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;
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
);
216 if (status
!= CAIRO_STATUS_SUCCESS
) {
219 *font_out
= (cairo_scaled_font_t
*) font
;
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.
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
));
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
)
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
;
293 face
= cairo_font_face_get_user_data (&toy_face
->base
,
294 &impl_font_face_key
);
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"))
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"))
313 else if (!strcmp(family
, "monospace") || !strcmp(family
, "mono"))
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
++) {
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
);
343 cgFont
= CGFontCreateWithNamePtr (full_name
);
352 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
355 face
= cairo_quartz_font_face_create_for_cgfont (cgFont
);
356 CGFontRelease (cgFont
);
361 status
= cairo_font_face_set_user_data (&toy_face
->base
,
364 (cairo_destroy_func_t
) cairo_font_face_destroy
);
367 cairo_font_face_destroy (face
);
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
);
390 status
= _cairo_quartz_font_face_scaled_font_create (face
,
394 cairo_font_face_destroy (face
);
398 *font_out
= scaled_font
;
399 return CAIRO_STATUS_SUCCESS
;
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
);
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);
429 transform
= CGAffineTransformMake (m
->xx
, - m
->yx
,
438 xscale
= 1.0 / xscale
;
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
);
459 double emscale
= CGFontGetUnitsPerEmPtr (font_face
->cgFont
);
460 double xscale
, yscale
;
461 double xmin
, ymin
, xmax
, ymax
;
463 if (glyph
== INVALID_GLYPH
)
466 if (!CGFontGetGlyphAdvancesPtr (font_face
->cgFont
, &glyph
, 1, &advance
) ||
467 !CGFontGetGlyphBBoxesPtr (font_face
->cgFont
, &glyph
, 1, &bbox
))
470 status
= _cairo_matrix_compute_basis_scale_factors (&font
->base
.scale
,
471 &xscale
, &yscale
, 1);
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 */
483 CGAffineTransform textMatrix
;
484 textMatrix
= CGAffineTransformMake (font
->base
.scale
.xx
,
485 -font
->base
.scale
.yx
,
486 -font
->base
.scale
.xy
,
490 bbox
= CGRectApplyAffineTransform (bbox
, textMatrix
);
491 bbox
= CGRectIntegral (bbox
);
492 bbox
= CGRectApplyAffineTransform (bbox
, CGAffineTransformInvert (textMatrix
));
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
);
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;
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
);
521 _cairo_scaled_glyph_set_metrics (scaled_glyph
,
529 _cairo_quartz_path_apply_func (void *info
, const CGPathElement
*el
)
531 cairo_path_fixed_t
*path
= (cairo_path_fixed_t
*) info
;
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
));
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
));
544 case kCGPathElementAddQuadCurveToPoint
: {
545 cairo_fixed_t fx
, fy
;
547 if (!_cairo_path_fixed_get_current_point (path
, &fx
, &fy
))
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
));
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
));
570 case kCGPathElementCloseSubpath
:
571 _cairo_path_fixed_close_path (path
);
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
;
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
,
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
);
602 return CAIRO_INT_STATUS_UNSUPPORTED
;
604 path
= _cairo_path_fixed_create ();
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
);
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
;
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
);
655 _cairo_scaled_glyph_set_surface (scaled_glyph
,
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);
672 textMatrix
= CGAffineTransformMake (font
->base
.scale
.xx
,
673 -font
->base
.scale
.yx
,
674 -font
->base
.scale
.xy
,
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
);
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
);
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
,
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
,
735 height
+ glyphOrigin
.y
);
737 _cairo_scaled_glyph_set_surface (scaled_glyph
, &font
->base
, surface
);
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
);
763 _cairo_quartz_ucs4_to_index (void *abstract_font
,
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
;
771 CGFontGetGlyphsForUnicharsPtr (ffont
->cgFont
, &u
, &glyph
, 1);
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
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.
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
);
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
);
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
);