Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

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