1
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
2
/*
3
 * Copyright © 2005 Keith Packard
4
 *
5
 * This library is free software; you can redistribute it and/or
6
 * modify it either under the terms of the GNU Lesser General Public
7
 * License version 2.1 as published by the Free Software Foundation
8
 * (the "LGPL") or, at your option, under the terms of the Mozilla
9
 * Public License Version 1.1 (the "MPL"). If you do not alter this
10
 * notice, a recipient may use your version of this file under either
11
 * the MPL or the LGPL.
12
 *
13
 * You should have received a copy of the LGPL along with this library
14
 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
15
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
16
 * You should have received a copy of the MPL along with this library
17
 * in the file COPYING-MPL-1.1
18
 *
19
 * The contents of this file are subject to the Mozilla Public License
20
 * Version 1.1 (the "License"); you may not use this file except in
21
 * compliance with the License. You may obtain a copy of the License at
22
 * http://www.mozilla.org/MPL/
23
 *
24
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
25
 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
26
 * the specific language governing rights and limitations.
27
 *
28
 * The Original Code is the cairo graphics library.
29
 *
30
 * The Initial Developer of the Original Code is Keith Packard
31
 *
32
 * Contributor(s):
33
 *      Keith Packard <keithp@keithp.com>
34
 *	Carl D. Worth <cworth@cworth.org>
35
 *      Graydon Hoare <graydon@redhat.com>
36
 *      Owen Taylor <otaylor@redhat.com>
37
 *      Behdad Esfahbod <behdad@behdad.org>
38
 *      Chris Wilson <chris@chris-wilson.co.uk>
39
 */
40

            
41
#include "cairoint.h"
42
#include "cairo-array-private.h"
43
#include "cairo-error-private.h"
44
#include "cairo-image-surface-private.h"
45
#include "cairo-list-inline.h"
46
#include "cairo-pattern-private.h"
47
#include "cairo-scaled-font-private.h"
48
#include "cairo-surface-backend-private.h"
49

            
50
/**
51
 * SECTION:cairo-scaled-font
52
 * @Title: cairo_scaled_font_t
53
 * @Short_Description: Font face at particular size and options
54
 * @See_Also: #cairo_font_face_t, #cairo_matrix_t, #cairo_font_options_t
55
 *
56
 * #cairo_scaled_font_t represents a realization of a font face at a particular
57
 * size and transformation and a certain set of font options.
58
 **/
59

            
60
static uintptr_t
61
_cairo_scaled_font_compute_hash (cairo_scaled_font_t *scaled_font);
62

            
63
/* Global Glyph Cache
64
 *
65
 * We maintain a global pool of glyphs split between all active fonts. This
66
 * allows a heavily used individual font to cache more glyphs than we could
67
 * manage if we used per-font glyph caches, but at the same time maintains
68
 * fairness across all fonts and provides a cap on the maximum number of
69
 * global glyphs.
70
 *
71
 * The glyphs are allocated in pages, which are capped in the global pool.
72
 * Using pages means we can reduce the frequency at which we have to probe the
73
 * global pool and ameliorates the memory allocation pressure.
74
 */
75

            
76
/* XXX: This number is arbitrary---we've never done any measurement of this. */
77
#define MAX_GLYPH_PAGES_CACHED 512
78
static cairo_cache_t cairo_scaled_glyph_page_cache;
79

            
80
#define CAIRO_SCALED_GLYPH_PAGE_SIZE 32
81
struct _cairo_scaled_glyph_page {
82
    cairo_cache_entry_t cache_entry;
83
    cairo_scaled_font_t *scaled_font;
84
    cairo_list_t link;
85

            
86
    unsigned int num_glyphs;
87
    cairo_scaled_glyph_t glyphs[CAIRO_SCALED_GLYPH_PAGE_SIZE];
88
};
89

            
90
/*
91
 *  Notes:
92
 *
93
 *  To store rasterizations of glyphs, we use an image surface and the
94
 *  device offset to represent the glyph origin.
95
 *
96
 *  A device_transform converts from device space (a conceptual space) to
97
 *  surface space.  For simple cases of translation only, it's called a
98
 *  device_offset and is public API (cairo_surface_[gs]et_device_offset()).
99
 *  A possibly better name for those functions could have been
100
 *  cairo_surface_[gs]et_origin().  So, that's what they do: they set where
101
 *  the device-space origin (0,0) is in the surface.  If the origin is inside
102
 *  the surface, device_offset values are positive.  It may look like this:
103
 *
104
 *  Device space:
105
 *        (-x,-y) <-- negative numbers
106
 *           +----------------+
107
 *           |      .         |
108
 *           |      .         |
109
 *           |......(0,0) <---|-- device-space origin
110
 *           |                |
111
 *           |                |
112
 *           +----------------+
113
 *                    (width-x,height-y)
114
 *
115
 *  Surface space:
116
 *         (0,0) <-- surface-space origin
117
 *           +---------------+
118
 *           |      .        |
119
 *           |      .        |
120
 *           |......(x,y) <--|-- device_offset
121
 *           |               |
122
 *           |               |
123
 *           +---------------+
124
 *                     (width,height)
125
 *
126
 *  In other words: device_offset is the coordinates of the device-space
127
 *  origin relative to the top-left of the surface.
128
 *
129
 *  We use device offsets in a couple of places:
130
 *
131
 *    - Public API: To let toolkits like Gtk+ give user a surface that
132
 *      only represents part of the final destination (say, the expose
133
 *      area), but has the same device space as the destination.  In these
134
 *      cases device_offset is typically negative.  Example:
135
 *
136
 *           application window
137
 *           +---------------+
138
 *           |      .        |
139
 *           | (x,y).        |
140
 *           |......+---+    |
141
 *           |      |   | <--|-- expose area
142
 *           |      +---+    |
143
 *           +---------------+
144
 *
145
 *      In this case, the user of cairo API can set the device_space on
146
 *      the expose area to (-x,-y) to move the device space origin to that
147
 *      of the application window, such that drawing in the expose area
148
 *      surface and painting it in the application window has the same
149
 *      effect as drawing in the application window directly.  Gtk+ has
150
 *      been using this feature.
151
 *
152
 *    - Glyph surfaces: In most font rendering systems, glyph surfaces
153
 *      have an origin at (0,0) and a bounding box that is typically
154
 *      represented as (x_bearing,y_bearing,width,height).  Depending on
155
 *      which way y progresses in the system, y_bearing may typically be
156
 *      negative (for systems similar to cairo, with origin at top left),
157
 *      or be positive (in systems like PDF with origin at bottom left).
158
 *      No matter which is the case, it is important to note that
159
 *      (x_bearing,y_bearing) is the coordinates of top-left of the glyph
160
 *      relative to the glyph origin.  That is, for example:
161
 *
162
 *      Scaled-glyph space:
163
 *
164
 *        (x_bearing,y_bearing) <-- negative numbers
165
 *           +----------------+
166
 *           |      .         |
167
 *           |      .         |
168
 *           |......(0,0) <---|-- glyph origin
169
 *           |                |
170
 *           |                |
171
 *           +----------------+
172
 *                    (width+x_bearing,height+y_bearing)
173
 *
174
 *      Note the similarity of the origin to the device space.  That is
175
 *      exactly how we use the device_offset to represent scaled glyphs:
176
 *      to use the device-space origin as the glyph origin.
177
 *
178
 *  Now compare the scaled-glyph space to device-space and surface-space
179
 *  and convince yourself that:
180
 *
181
 *	(x_bearing,y_bearing) = (-x,-y) = - device_offset
182
 *
183
 *  That's right.  If you are not convinced yet, contrast the definition
184
 *  of the two:
185
 *
186
 *	"(x_bearing,y_bearing) is the coordinates of top-left of the
187
 *	 glyph relative to the glyph origin."
188
 *
189
 *	"In other words: device_offset is the coordinates of the
190
 *	 device-space origin relative to the top-left of the surface."
191
 *
192
 *  and note that glyph origin = device-space origin.
193
 */
194

            
195
static void
196
_cairo_scaled_font_fini_internal (cairo_scaled_font_t *scaled_font);
197

            
198
static void
199
30
_cairo_scaled_glyph_fini (cairo_scaled_font_t *scaled_font,
200
			  cairo_scaled_glyph_t *scaled_glyph)
201
{
202
30
    while (! cairo_list_is_empty (&scaled_glyph->dev_privates)) {
203
	cairo_scaled_glyph_private_t *private =
204
	    cairo_list_first_entry (&scaled_glyph->dev_privates,
205
				    cairo_scaled_glyph_private_t,
206
				    link);
207
	private->destroy (private, scaled_glyph, scaled_font);
208
    }
209

            
210
30
    _cairo_image_scaled_glyph_fini (scaled_font, scaled_glyph);
211

            
212
30
    if (scaled_glyph->surface != NULL)
213
	cairo_surface_destroy (&scaled_glyph->surface->base);
214

            
215
30
    if (scaled_glyph->path != NULL)
216
	_cairo_path_fixed_destroy (scaled_glyph->path);
217

            
218
30
    if (scaled_glyph->recording_surface != NULL) {
219
	cairo_status_t status;
220

            
221
	/* If the recording surface contains other fonts, destroying
222
	 * it while holding _cairo_scaled_glyph_page_cache_mutex will
223
	 * result in deadlock when the recording surface font is
224
	 * destroyed. Instead, move the recording surface to a list of
225
	 * surfaces to free and free it in
226
	 * _cairo_scaled_font_thaw_cache() after
227
	 * _cairo_scaled_glyph_page_cache_mutex is unlocked. */
228
30
	status = _cairo_array_append (&scaled_font->recording_surfaces_to_free, &scaled_glyph->recording_surface);
229
30
	assert (status == CAIRO_STATUS_SUCCESS);
230
    }
231

            
232
30
    if (scaled_glyph->color_surface != NULL)
233
	cairo_surface_destroy (&scaled_glyph->color_surface->base);
234
30
}
235

            
236
#define ZOMBIE 0
237
static const cairo_scaled_font_t _cairo_scaled_font_nil = {
238
    { ZOMBIE },			/* hash_entry */
239
    CAIRO_STATUS_NO_MEMORY,	/* status */
240
    CAIRO_REFERENCE_COUNT_INVALID,	/* ref_count */
241
    { 0, 0, 0, NULL },		/* user_data */
242
    NULL,			/* original_font_face */
243
    NULL,			/* font_face */
244
    { 1., 0., 0., 1., 0, 0},	/* font_matrix */
245
    { 1., 0., 0., 1., 0, 0},	/* ctm */
246
    { CAIRO_ANTIALIAS_DEFAULT,	/* options */
247
      CAIRO_SUBPIXEL_ORDER_DEFAULT,
248
      CAIRO_HINT_STYLE_DEFAULT,
249
      CAIRO_HINT_METRICS_DEFAULT} ,
250
    FALSE,			/* placeholder */
251
    FALSE,			/* holdover */
252
    TRUE,			/* finished */
253
    { 1., 0., 0., 1., 0, 0},	/* scale */
254
    { 1., 0., 0., 1., 0, 0},	/* scale_inverse */
255
    1.,				/* max_scale */
256
    { 0., 0., 0., 0., 0. },	/* extents */
257
    { 0., 0., 0., 0., 0. },	/* fs_extents */
258
    CAIRO_MUTEX_NIL_INITIALIZER,/* mutex */
259
    NULL,			/* glyphs */
260
    { NULL, NULL },		/* pages */
261
    FALSE,			/* cache_frozen */
262
    FALSE,			/* global_cache_frozen */
263
    { 0, 0, sizeof(cairo_surface_t*), NULL }, /* recording_surfaces_to_free */
264
    { NULL, NULL },		/* privates */
265
    NULL			/* backend */
266
};
267

            
268
/**
269
 * _cairo_scaled_font_set_error:
270
 * @scaled_font: a scaled_font
271
 * @status: a status value indicating an error
272
 *
273
 * Atomically sets scaled_font->status to @status and calls _cairo_error;
274
 * Does nothing if status is %CAIRO_STATUS_SUCCESS.
275
 *
276
 * All assignments of an error status to scaled_font->status should happen
277
 * through _cairo_scaled_font_set_error(). Note that due to the nature of
278
 * the atomic operation, it is not safe to call this function on the nil
279
 * objects.
280
 *
281
 * The purpose of this function is to allow the user to set a
282
 * breakpoint in _cairo_error() to generate a stack trace for when the
283
 * user causes cairo to detect an error.
284
 *
285
 * Return value: the error status.
286
 **/
287
cairo_status_t
288
68211
_cairo_scaled_font_set_error (cairo_scaled_font_t *scaled_font,
289
			      cairo_status_t status)
290
{
291
68211
    if (status == CAIRO_STATUS_SUCCESS)
292
68211
	return status;
293

            
294
    /* Don't overwrite an existing error. This preserves the first
295
     * error, which is the most significant. */
296
    _cairo_status_set_error (&scaled_font->status, status);
297

            
298
    return _cairo_error (status);
299
}
300

            
301
/**
302
 * cairo_scaled_font_get_type:
303
 * @scaled_font: a #cairo_scaled_font_t
304
 *
305
 * This function returns the type of the backend used to create
306
 * a scaled font. See #cairo_font_type_t for available types.
307
 * However, this function never returns %CAIRO_FONT_TYPE_TOY.
308
 *
309
 * Return value: The type of @scaled_font.
310
 *
311
 * Since: 1.2
312
 **/
313
cairo_font_type_t
314
3
cairo_scaled_font_get_type (cairo_scaled_font_t *scaled_font)
315
{
316
6
    if (CAIRO_REFERENCE_COUNT_IS_INVALID (&scaled_font->ref_count))
317
	return CAIRO_FONT_TYPE_TOY;
318

            
319
3
    return scaled_font->backend->type;
320
}
321

            
322
/**
323
 * cairo_scaled_font_status:
324
 * @scaled_font: a #cairo_scaled_font_t
325
 *
326
 * Checks whether an error has previously occurred for this
327
 * scaled_font.
328
 *
329
 * Return value: %CAIRO_STATUS_SUCCESS or another error such as
330
 *   %CAIRO_STATUS_NO_MEMORY.
331
 *
332
 * Since: 1.0
333
 **/
334
cairo_status_t
335
344833
cairo_scaled_font_status (cairo_scaled_font_t *scaled_font)
336
{
337
344833
    return scaled_font->status;
338
}
339

            
340
/* Here we keep a unique mapping from
341
 * font_face/matrix/ctm/font_options => #cairo_scaled_font_t.
342
 *
343
 * Here are the things that we want to map:
344
 *
345
 *  a) All otherwise referenced #cairo_scaled_font_t's
346
 *  b) Some number of not otherwise referenced #cairo_scaled_font_t's
347
 *
348
 * The implementation uses a hash table which covers (a)
349
 * completely. Then, for (b) we have an array of otherwise
350
 * unreferenced fonts (holdovers) which are expired in
351
 * least-recently-used order.
352
 *
353
 * The cairo_scaled_font_create() code gets to treat this like a regular
354
 * hash table. All of the magic for the little holdover cache is in
355
 * cairo_scaled_font_reference() and cairo_scaled_font_destroy().
356
 */
357

            
358
/* This defines the size of the holdover array ... that is, the number
359
 * of scaled fonts we keep around even when not otherwise referenced
360
 */
361
#define CAIRO_SCALED_FONT_MAX_HOLDOVERS 256
362

            
363
typedef struct _cairo_scaled_font_map {
364
    cairo_scaled_font_t *mru_scaled_font;
365
    cairo_hash_table_t *hash_table;
366
    cairo_scaled_font_t *holdovers[CAIRO_SCALED_FONT_MAX_HOLDOVERS];
367
    int num_holdovers;
368
} cairo_scaled_font_map_t;
369

            
370
static cairo_scaled_font_map_t *cairo_scaled_font_map;
371

            
372
static int
373
_cairo_scaled_font_keys_equal (const void *abstract_key_a, const void *abstract_key_b);
374

            
375
static cairo_scaled_font_map_t *
376
341862
_cairo_scaled_font_map_lock (void)
377
{
378
341862
    CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
379

            
380
341862
    if (cairo_scaled_font_map == NULL) {
381
299
	cairo_scaled_font_map = _cairo_calloc (sizeof (cairo_scaled_font_map_t));
382
299
	if (unlikely (cairo_scaled_font_map == NULL))
383
	    goto CLEANUP_MUTEX_LOCK;
384

            
385
299
	cairo_scaled_font_map->mru_scaled_font = NULL;
386
598
	cairo_scaled_font_map->hash_table =
387
299
	    _cairo_hash_table_create (_cairo_scaled_font_keys_equal);
388

            
389
299
	if (unlikely (cairo_scaled_font_map->hash_table == NULL))
390
	    goto CLEANUP_SCALED_FONT_MAP;
391

            
392
299
	cairo_scaled_font_map->num_holdovers = 0;
393
    }
394

            
395
341862
    return cairo_scaled_font_map;
396

            
397
 CLEANUP_SCALED_FONT_MAP:
398
    free (cairo_scaled_font_map);
399
    cairo_scaled_font_map = NULL;
400
 CLEANUP_MUTEX_LOCK:
401
    CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
402
    _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
403
    return NULL;
404
}
405

            
406
static void
407
341862
_cairo_scaled_font_map_unlock (void)
408
{
409
341862
   CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
410
341862
}
411

            
412
void
413
608
_cairo_scaled_font_map_destroy (void)
414
{
415
    cairo_scaled_font_map_t *font_map;
416
    cairo_scaled_font_t *scaled_font;
417

            
418
608
    CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
419

            
420
608
    font_map = cairo_scaled_font_map;
421
608
    if (unlikely (font_map == NULL)) {
422
608
        goto CLEANUP_MUTEX_LOCK;
423
    }
424

            
425
    scaled_font = font_map->mru_scaled_font;
426
    if (scaled_font != NULL) {
427
	CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
428
	cairo_scaled_font_destroy (scaled_font);
429
	CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
430
    }
431

            
432
    /* remove scaled_fonts starting from the end so that font_map->holdovers
433
     * is always in a consistent state when we release the mutex. */
434
    while (font_map->num_holdovers) {
435
	scaled_font = font_map->holdovers[font_map->num_holdovers-1];
436
	assert (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count));
437
	_cairo_hash_table_remove (font_map->hash_table,
438
				  &scaled_font->hash_entry);
439

            
440
	font_map->num_holdovers--;
441

            
442
	/* This releases the font_map lock to avoid the possibility of a
443
	 * recursive deadlock when the scaled font destroy closure gets
444
	 * called
445
	 */
446
	_cairo_scaled_font_fini (scaled_font);
447

            
448
	free (scaled_font);
449
    }
450

            
451
    _cairo_hash_table_destroy (font_map->hash_table);
452

            
453
    free (cairo_scaled_font_map);
454
    cairo_scaled_font_map = NULL;
455

            
456
608
 CLEANUP_MUTEX_LOCK:
457
608
    CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
458
608
}
459

            
460
static void
461
_cairo_scaled_glyph_page_destroy (cairo_scaled_font_t *scaled_font,
462
				  cairo_scaled_glyph_page_t *page)
463
{
464
    unsigned int n;
465

            
466
    assert (!scaled_font->cache_frozen);
467
    assert (!scaled_font->global_cache_frozen);
468

            
469
    for (n = 0; n < page->num_glyphs; n++) {
470
	_cairo_hash_table_remove (scaled_font->glyphs,
471
				  &page->glyphs[n].hash_entry);
472
	_cairo_scaled_glyph_fini (scaled_font, &page->glyphs[n]);
473
    }
474

            
475
    cairo_list_del (&page->link);
476
    free (page);
477
}
478

            
479
static void
480
_cairo_scaled_glyph_page_pluck (void *closure)
481
{
482
    cairo_scaled_glyph_page_t *page = closure;
483
    cairo_scaled_font_t *scaled_font;
484

            
485
    assert (! cairo_list_is_empty (&page->link));
486

            
487
    scaled_font = page->scaled_font;
488

            
489
    /* The font is locked in _cairo_scaled_glyph_page_can_remove () */
490
    _cairo_scaled_glyph_page_destroy (scaled_font, page);
491
    CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
492
}
493

            
494
/* If a scaled font wants to unlock the font map while still being
495
 * created (needed for user-fonts), we need to take extra care not
496
 * ending up with multiple identical scaled fonts being created.
497
 *
498
 * What we do is, we create a fake identical scaled font, and mark
499
 * it as placeholder, lock its mutex, and insert that in the fontmap
500
 * hash table.  This makes other code trying to create an identical
501
 * scaled font to just wait and retry.
502
 *
503
 * The reason we have to create a fake scaled font instead of just using
504
 * scaled_font is for lifecycle management: we need to (or rather,
505
 * other code needs to) reference the scaled_font in the hash table.
506
 * We can't do that on the input scaled_font as it may be freed by
507
 * font backend upon error.
508
 */
509

            
510
cairo_status_t
511
78
_cairo_scaled_font_register_placeholder_and_unlock_font_map (cairo_scaled_font_t *scaled_font)
512
{
513
    cairo_status_t status;
514
    cairo_scaled_font_t *placeholder_scaled_font;
515

            
516
    assert (CAIRO_MUTEX_IS_LOCKED (_cairo_scaled_font_map_mutex));
517

            
518
78
    status = scaled_font->status;
519
78
    if (unlikely (status))
520
	return status;
521

            
522
78
    placeholder_scaled_font = _cairo_calloc (sizeof (cairo_scaled_font_t));
523
78
    if (unlikely (placeholder_scaled_font == NULL))
524
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
525

            
526
    /* full initialization is wasteful, but who cares... */
527
78
    status = _cairo_scaled_font_init (placeholder_scaled_font,
528
				      scaled_font->font_face,
529
78
				      &scaled_font->font_matrix,
530
78
				      &scaled_font->ctm,
531
78
				      &scaled_font->options,
532
				      NULL);
533
78
    if (unlikely (status))
534
	goto FREE_PLACEHOLDER;
535

            
536
78
    placeholder_scaled_font->placeholder = TRUE;
537

            
538
    placeholder_scaled_font->hash_entry.hash
539
78
	= _cairo_scaled_font_compute_hash (placeholder_scaled_font);
540
78
    status = _cairo_hash_table_insert (cairo_scaled_font_map->hash_table,
541
				       &placeholder_scaled_font->hash_entry);
542
78
    if (unlikely (status))
543
	goto FINI_PLACEHOLDER;
544

            
545
78
    CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
546
78
    CAIRO_MUTEX_LOCK (placeholder_scaled_font->mutex);
547

            
548
78
    return CAIRO_STATUS_SUCCESS;
549

            
550
  FINI_PLACEHOLDER:
551
    _cairo_scaled_font_fini_internal (placeholder_scaled_font);
552
  FREE_PLACEHOLDER:
553
    free (placeholder_scaled_font);
554

            
555
    return _cairo_scaled_font_set_error (scaled_font, status);
556
}
557

            
558
void
559
78
_cairo_scaled_font_unregister_placeholder_and_lock_font_map (cairo_scaled_font_t *scaled_font)
560
{
561
    cairo_scaled_font_t *placeholder_scaled_font;
562

            
563
78
    CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
564

            
565
    /* temporary hash value to match the placeholder */
566
    scaled_font->hash_entry.hash
567
78
	= _cairo_scaled_font_compute_hash (scaled_font);
568
    placeholder_scaled_font =
569
78
	_cairo_hash_table_lookup (cairo_scaled_font_map->hash_table,
570
				  &scaled_font->hash_entry);
571
78
    assert (placeholder_scaled_font != NULL);
572
78
    assert (placeholder_scaled_font->placeholder);
573
    assert (CAIRO_MUTEX_IS_LOCKED (placeholder_scaled_font->mutex));
574

            
575
78
    _cairo_hash_table_remove (cairo_scaled_font_map->hash_table,
576
			      &placeholder_scaled_font->hash_entry);
577

            
578
78
    CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
579

            
580
78
    CAIRO_MUTEX_UNLOCK (placeholder_scaled_font->mutex);
581
78
    cairo_scaled_font_destroy (placeholder_scaled_font);
582

            
583
78
    CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
584
78
}
585

            
586
static void
587
_cairo_scaled_font_placeholder_wait_for_creation_to_finish (cairo_scaled_font_t *placeholder_scaled_font)
588
{
589
    /* reference the place holder so it doesn't go away */
590
    cairo_scaled_font_reference (placeholder_scaled_font);
591

            
592
    /* now unlock the fontmap mutex so creation has a chance to finish */
593
    CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
594

            
595
    /* wait on placeholder mutex until we are awaken */
596
    CAIRO_MUTEX_LOCK (placeholder_scaled_font->mutex);
597

            
598
    /* ok, creation done.  just clean up and back out */
599
    CAIRO_MUTEX_UNLOCK (placeholder_scaled_font->mutex);
600
    cairo_scaled_font_destroy (placeholder_scaled_font);
601

            
602
    CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
603
}
604

            
605
/* Fowler / Noll / Vo (FNV) Hash (http://www.isthe.com/chongo/tech/comp/fnv/)
606
 *
607
 * Not necessarily better than a lot of other hashes, but should be OK, and
608
 * well tested with binary data.
609
 */
610

            
611
#define FNV_64_PRIME ((uint64_t)0x00000100000001B3)
612
#define FNV1_64_INIT ((uint64_t)0xcbf29ce484222325)
613

            
614
static uint64_t
615
163310
_hash_matrix_fnv (const cairo_matrix_t	*matrix,
616
		  uint64_t		 hval)
617
{
618
163310
    const uint8_t *buffer = (const uint8_t *) matrix;
619
163310
    int len = sizeof (cairo_matrix_t);
620
    do {
621
7838880
	hval *= FNV_64_PRIME;
622
7838880
	hval ^= *buffer++;
623
7838880
    } while (--len);
624

            
625
163310
    return hval;
626
}
627

            
628
static uint64_t
629
163310
_hash_mix_bits (uint64_t hash)
630
{
631
163310
    hash += hash << 12;
632
163310
    hash ^= hash >> 7;
633
163310
    hash += hash << 3;
634
163310
    hash ^= hash >> 17;
635
163310
    hash += hash << 5;
636
163310
    return hash;
637
}
638

            
639
static uintptr_t
640
81655
_cairo_scaled_font_compute_hash (cairo_scaled_font_t *scaled_font)
641
{
642
81655
    uint64_t hash = FNV1_64_INIT;
643

            
644
    /* We do a bytewise hash on the font matrices */
645
81655
    hash = _hash_matrix_fnv (&scaled_font->font_matrix, hash);
646
81655
    hash = _hash_matrix_fnv (&scaled_font->ctm, hash);
647
81655
    hash = _hash_mix_bits (hash);
648

            
649
81655
    hash ^= (uintptr_t) scaled_font->original_font_face;
650
81655
    hash ^= cairo_font_options_hash (&scaled_font->options);
651

            
652
    /* final mixing of bits */
653
81655
    hash = _hash_mix_bits (hash);
654
81655
    assert (hash != ZOMBIE);
655

            
656
81655
    return hash;
657
}
658

            
659
static void
660
80462
_cairo_scaled_font_init_key (cairo_scaled_font_t        *scaled_font,
661
			     cairo_font_face_t	        *font_face,
662
			     const cairo_matrix_t       *font_matrix,
663
			     const cairo_matrix_t       *ctm,
664
			     const cairo_font_options_t *options)
665
{
666
80462
    scaled_font->status = CAIRO_STATUS_SUCCESS;
667
80462
    scaled_font->placeholder = FALSE;
668
80462
    scaled_font->font_face = font_face;
669
80462
    scaled_font->original_font_face = font_face;
670
80462
    scaled_font->font_matrix = *font_matrix;
671
80462
    scaled_font->ctm = *ctm;
672
    /* ignore translation values in the ctm */
673
80462
    scaled_font->ctm.x0 = 0.;
674
80462
    scaled_font->ctm.y0 = 0.;
675
80462
    _cairo_font_options_init_copy (&scaled_font->options, options);
676

            
677
80462
    scaled_font->hash_entry.hash =
678
80462
	_cairo_scaled_font_compute_hash (scaled_font);
679
80462
}
680

            
681
static void
682
80462
_cairo_scaled_font_fini_key (cairo_scaled_font_t *scaled_font)
683
{
684
80462
    _cairo_font_options_fini (&scaled_font->options);
685
80462
}
686

            
687
static cairo_bool_t
688
79518
_cairo_scaled_font_keys_equal (const void *abstract_key_a,
689
			       const void *abstract_key_b)
690
{
691
79518
    const cairo_scaled_font_t *key_a = abstract_key_a;
692
79518
    const cairo_scaled_font_t *key_b = abstract_key_b;
693

            
694
159036
    return key_a->original_font_face == key_b->original_font_face &&
695
79518
	    memcmp ((unsigned char *)(&key_a->font_matrix.xx),
696
79518
		    (unsigned char *)(&key_b->font_matrix.xx),
697
79518
		    sizeof(cairo_matrix_t)) == 0 &&
698
79518
	    memcmp ((unsigned char *)(&key_a->ctm.xx),
699
79518
		    (unsigned char *)(&key_b->ctm.xx),
700
159036
		    sizeof(cairo_matrix_t)) == 0 &&
701
79518
	    cairo_font_options_equal (&key_a->options, &key_b->options);
702
}
703

            
704
static cairo_bool_t
705
130278
_cairo_scaled_font_matches (const cairo_scaled_font_t *scaled_font,
706
	                    const cairo_font_face_t *font_face,
707
			    const cairo_matrix_t *font_matrix,
708
			    const cairo_matrix_t *ctm,
709
			    const cairo_font_options_t *options)
710
{
711
194355
    return scaled_font->original_font_face == font_face &&
712
64077
	    memcmp ((unsigned char *)(&scaled_font->font_matrix.xx),
713
64077
		    (unsigned char *)(&font_matrix->xx),
714
61722
		    sizeof(cairo_matrix_t)) == 0 &&
715
61722
	    memcmp ((unsigned char *)(&scaled_font->ctm.xx),
716
61722
		    (unsigned char *)(&ctm->xx),
717
194355
		    sizeof(cairo_matrix_t)) == 0 &&
718
50223
	    cairo_font_options_equal (&scaled_font->options, options);
719
}
720

            
721
/*
722
 * Basic #cairo_scaled_font_t object management
723
 */
724

            
725
cairo_status_t
726
1124
_cairo_scaled_font_init (cairo_scaled_font_t               *scaled_font,
727
			 cairo_font_face_t		   *font_face,
728
			 const cairo_matrix_t              *font_matrix,
729
			 const cairo_matrix_t              *ctm,
730
			 const cairo_font_options_t	   *options,
731
			 const cairo_scaled_font_backend_t *backend)
732
{
733
    cairo_status_t status;
734

            
735
1124
    status = cairo_font_options_status ((cairo_font_options_t *) options);
736
1124
    if (unlikely (status))
737
	return status;
738

            
739
1124
    scaled_font->status = CAIRO_STATUS_SUCCESS;
740
1124
    scaled_font->placeholder = FALSE;
741
1124
    scaled_font->font_face = font_face;
742
1124
    scaled_font->original_font_face = font_face;
743
1124
    scaled_font->font_matrix = *font_matrix;
744
1124
    scaled_font->ctm = *ctm;
745
    /* ignore translation values in the ctm */
746
1124
    scaled_font->ctm.x0 = 0.;
747
1124
    scaled_font->ctm.y0 = 0.;
748
1124
    _cairo_font_options_init_copy (&scaled_font->options, options);
749

            
750
1124
    cairo_matrix_multiply (&scaled_font->scale,
751
1124
			   &scaled_font->font_matrix,
752
1124
			   &scaled_font->ctm);
753

            
754
1124
    scaled_font->max_scale = MAX (fabs (scaled_font->scale.xx) + fabs (scaled_font->scale.xy),
755
				  fabs (scaled_font->scale.yx) + fabs (scaled_font->scale.yy));
756
1124
    scaled_font->scale_inverse = scaled_font->scale;
757
1124
    status = cairo_matrix_invert (&scaled_font->scale_inverse);
758
1124
    if (unlikely (status)) {
759
	/* If the font scale matrix is rank 0, just using an all-zero inverse matrix
760
	 * makes everything work correctly.  This make font size 0 work without
761
	 * producing an error.
762
	 *
763
	 * FIXME:  If the scale is rank 1, we still go into error mode.  But then
764
	 * again, that's what we do everywhere in cairo.
765
	 *
766
	 * Also, the check for == 0. below may be too harsh...
767
	 */
768
18
        if (_cairo_matrix_is_scale_0 (&scaled_font->scale)) {
769
9
	    cairo_matrix_init (&scaled_font->scale_inverse,
770
			       0, 0, 0, 0,
771
9
			       -scaled_font->scale.x0,
772
9
			       -scaled_font->scale.y0);
773
	} else
774
9
	    return status;
775
    }
776

            
777
1115
    scaled_font->glyphs = _cairo_hash_table_create (NULL);
778
1115
    if (unlikely (scaled_font->glyphs == NULL))
779
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
780

            
781
1115
    cairo_list_init (&scaled_font->glyph_pages);
782
1115
    scaled_font->cache_frozen = FALSE;
783
1115
    scaled_font->global_cache_frozen = FALSE;
784
1115
    _cairo_array_init (&scaled_font->recording_surfaces_to_free, sizeof (cairo_surface_t *));
785

            
786
1115
    scaled_font->holdover = FALSE;
787
1115
    scaled_font->finished = FALSE;
788

            
789
1115
    CAIRO_REFERENCE_COUNT_INIT (&scaled_font->ref_count, 1);
790

            
791
1115
    _cairo_user_data_array_init (&scaled_font->user_data);
792

            
793
1115
    cairo_font_face_reference (font_face);
794
1115
    scaled_font->original_font_face = NULL;
795

            
796
1115
    CAIRO_RECURSIVE_MUTEX_INIT (scaled_font->mutex);
797

            
798
1115
    cairo_list_init (&scaled_font->dev_privates);
799

            
800
1115
    scaled_font->backend = backend;
801
1115
    cairo_list_init (&scaled_font->link);
802

            
803
1115
    return CAIRO_STATUS_SUCCESS;
804
}
805

            
806
275922
static void _cairo_scaled_font_free_recording_surfaces (cairo_scaled_font_t *scaled_font)
807
{
808
    int num_recording_surfaces;
809
    cairo_surface_t *surface;
810

            
811
275922
    num_recording_surfaces = _cairo_array_num_elements (&scaled_font->recording_surfaces_to_free);
812
275922
    if (num_recording_surfaces > 0) {
813
60
	for (int i = 0; i < num_recording_surfaces; i++) {
814
30
	    _cairo_array_copy_element (&scaled_font->recording_surfaces_to_free, i, &surface);
815
30
	    cairo_surface_finish (surface);
816
30
	    cairo_surface_destroy (surface);
817
	}
818
30
	_cairo_array_truncate (&scaled_font->recording_surfaces_to_free, 0);
819
    }
820
275922
}
821

            
822
void
823
275844
_cairo_scaled_font_freeze_cache (cairo_scaled_font_t *scaled_font)
824
{
825
    /* ensure we do not modify an error object */
826
275844
    assert (scaled_font->status == CAIRO_STATUS_SUCCESS);
827

            
828
275844
    CAIRO_MUTEX_LOCK (scaled_font->mutex);
829
275844
    scaled_font->cache_frozen = TRUE;
830
275844
}
831

            
832
void
833
275844
_cairo_scaled_font_thaw_cache (cairo_scaled_font_t *scaled_font)
834
{
835
275844
    assert (scaled_font->cache_frozen);
836

            
837
275844
    if (scaled_font->global_cache_frozen) {
838
975
	CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex);
839
975
	_cairo_cache_thaw (&cairo_scaled_glyph_page_cache);
840
975
	CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex);
841
975
	scaled_font->global_cache_frozen = FALSE;
842
    }
843

            
844
275844
    _cairo_scaled_font_free_recording_surfaces (scaled_font);
845

            
846
275844
    scaled_font->cache_frozen = FALSE;
847
275844
    CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
848
275844
}
849

            
850
void
851
78
_cairo_scaled_font_reset_cache (cairo_scaled_font_t *scaled_font)
852
{
853
    cairo_scaled_glyph_page_t *page;
854

            
855
78
    CAIRO_MUTEX_LOCK (scaled_font->mutex);
856
78
    assert (! scaled_font->cache_frozen);
857
78
    assert (! scaled_font->global_cache_frozen);
858
78
    CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex);
859

            
860
78
    cairo_list_foreach_entry (page,
861
			      cairo_scaled_glyph_page_t,
862
			      &scaled_font->glyph_pages,
863
			      link) {
864
	cairo_scaled_glyph_page_cache.size -= page->cache_entry.size;
865
	_cairo_hash_table_remove (cairo_scaled_glyph_page_cache.hash_table,
866
				  (cairo_hash_entry_t *) &page->cache_entry);
867
    }
868

            
869
78
    CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex);
870

            
871
    /* Destroy scaled_font's pages while holding its lock only, and not the
872
     * global page cache lock. The destructor can cause us to recurse and
873
     * end up back here for a different scaled_font. */
874

            
875
78
    while (! cairo_list_is_empty (&scaled_font->glyph_pages)) {
876
	page = cairo_list_first_entry (&scaled_font->glyph_pages,
877
				       cairo_scaled_glyph_page_t,
878
				       link);
879
	_cairo_scaled_glyph_page_destroy (scaled_font, page);
880
    }
881

            
882
78
    CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
883
78
}
884

            
885
cairo_status_t
886
1037
_cairo_scaled_font_set_metrics (cairo_scaled_font_t	    *scaled_font,
887
				cairo_font_extents_t	    *fs_metrics)
888
{
889
    cairo_status_t status;
890
    double  font_scale_x, font_scale_y;
891

            
892
1037
    scaled_font->fs_extents = *fs_metrics;
893

            
894
1037
    status = _cairo_matrix_compute_basis_scale_factors (&scaled_font->font_matrix,
895
						  &font_scale_x, &font_scale_y,
896
						  1);
897
1037
    if (unlikely (status))
898
	return status;
899

            
900
    /*
901
     * The font responded in unscaled units, scale by the font
902
     * matrix scale factors to get to user space
903
     */
904

            
905
1037
    scaled_font->extents.ascent = fs_metrics->ascent * font_scale_y;
906
1037
    scaled_font->extents.descent = fs_metrics->descent * font_scale_y;
907
1037
    scaled_font->extents.height = fs_metrics->height * font_scale_y;
908
1037
    scaled_font->extents.max_x_advance = fs_metrics->max_x_advance * font_scale_x;
909
1037
    scaled_font->extents.max_y_advance = fs_metrics->max_y_advance * font_scale_y;
910

            
911
1037
    return CAIRO_STATUS_SUCCESS;
912
}
913

            
914
static void
915
78
_cairo_scaled_font_fini_internal (cairo_scaled_font_t *scaled_font)
916
{
917
78
    assert (! scaled_font->cache_frozen);
918
78
    assert (! scaled_font->global_cache_frozen);
919
78
    scaled_font->finished = TRUE;
920

            
921
78
    _cairo_scaled_font_reset_cache (scaled_font);
922
78
    _cairo_hash_table_destroy (scaled_font->glyphs);
923
78
    _cairo_font_options_fini (&scaled_font->options);
924

            
925
78
    cairo_font_face_destroy (scaled_font->font_face);
926
78
    cairo_font_face_destroy (scaled_font->original_font_face);
927

            
928
78
    _cairo_scaled_font_free_recording_surfaces (scaled_font);
929
78
    _cairo_array_fini (&scaled_font->recording_surfaces_to_free);
930

            
931
78
    CAIRO_MUTEX_FINI (scaled_font->mutex);
932

            
933
78
    while (! cairo_list_is_empty (&scaled_font->dev_privates)) {
934
	cairo_scaled_font_private_t *private =
935
	    cairo_list_first_entry (&scaled_font->dev_privates,
936
				    cairo_scaled_font_private_t,
937
				    link);
938
	private->destroy (private, scaled_font);
939
    }
940

            
941
78
    if (scaled_font->backend != NULL && scaled_font->backend->fini != NULL)
942
	scaled_font->backend->fini (scaled_font);
943

            
944
78
    _cairo_user_data_array_fini (&scaled_font->user_data);
945
78
}
946

            
947
void
948
_cairo_scaled_font_fini (cairo_scaled_font_t *scaled_font)
949
{
950
    /* Release the lock to avoid the possibility of a recursive
951
     * deadlock when the scaled font destroy closure gets called. */
952
    CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
953
    _cairo_scaled_font_fini_internal (scaled_font);
954
    CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
955
}
956

            
957
void
958
_cairo_scaled_font_attach_private (cairo_scaled_font_t *scaled_font,
959
				   cairo_scaled_font_private_t *private,
960
				   const void *key,
961
				   void (*destroy) (cairo_scaled_font_private_t *,
962
						    cairo_scaled_font_t *))
963
{
964
    private->key = key;
965
    private->destroy = destroy;
966
    cairo_list_add (&private->link, &scaled_font->dev_privates);
967
}
968

            
969
cairo_scaled_font_private_t *
970
_cairo_scaled_font_find_private (cairo_scaled_font_t *scaled_font,
971
				 const void *key)
972
{
973
    cairo_scaled_font_private_t *priv;
974

            
975
    cairo_list_foreach_entry (priv, cairo_scaled_font_private_t,
976
			      &scaled_font->dev_privates, link)
977
    {
978
	if (priv->key == key) {
979
	    if (priv->link.prev != &scaled_font->dev_privates)
980
		cairo_list_move (&priv->link, &scaled_font->dev_privates);
981
	    return priv;
982
	}
983
    }
984

            
985
    return NULL;
986
}
987

            
988
void
989
4962
_cairo_scaled_glyph_attach_private (cairo_scaled_glyph_t *scaled_glyph,
990
				   cairo_scaled_glyph_private_t *private,
991
				   const void *key,
992
				   void (*destroy) (cairo_scaled_glyph_private_t *,
993
						    cairo_scaled_glyph_t *,
994
						    cairo_scaled_font_t *))
995
{
996
4962
    private->key = key;
997
4962
    private->destroy = destroy;
998
4962
    cairo_list_add (&private->link, &scaled_glyph->dev_privates);
999
4962
}
cairo_scaled_glyph_private_t *
17844
_cairo_scaled_glyph_find_private (cairo_scaled_glyph_t *scaled_glyph,
				 const void *key)
{
    cairo_scaled_glyph_private_t *priv;
17844
    cairo_list_foreach_entry (priv, cairo_scaled_glyph_private_t,
			      &scaled_glyph->dev_privates, link)
    {
17844
	if (priv->key == key) {
17844
	    if (priv->link.prev != &scaled_glyph->dev_privates)
		cairo_list_move (&priv->link, &scaled_glyph->dev_privates);
17844
	    return priv;
	}
    }
    return NULL;
}
/**
 * cairo_scaled_font_create:
 * @font_face: a #cairo_font_face_t
 * @font_matrix: font space to user space transformation matrix for the
 *       font. In the simplest case of a N point font, this matrix is
 *       just a scale by N, but it can also be used to shear the font
 *       or stretch it unequally along the two axes. See
 *       cairo_set_font_matrix().
 * @ctm: user to device transformation matrix with which the font will
 *       be used.
 * @options: options to use when getting metrics for the font and
 *           rendering with it.
 *
 * Creates a #cairo_scaled_font_t object from a font face and matrices that
 * describe the size of the font and the environment in which it will
 * be used.
 *
 * Return value: a newly created #cairo_scaled_font_t. Destroy with
 *  cairo_scaled_font_destroy()
 *
 * Since: 1.0
 **/
cairo_scaled_font_t *
130605
cairo_scaled_font_create (cairo_font_face_t          *font_face,
			  const cairo_matrix_t       *font_matrix,
			  const cairo_matrix_t       *ctm,
			  const cairo_font_options_t *options)
{
    cairo_status_t status;
    cairo_scaled_font_map_t *font_map;
130605
    cairo_font_face_t *original_font_face = font_face;
130605
    cairo_scaled_font_t key, *old = NULL, *scaled_font = NULL, *dead = NULL;
    double det;
130605
    status = font_face->status;
130605
    if (unlikely (status))
	return _cairo_scaled_font_create_in_error (status);
130605
    det = _cairo_matrix_compute_determinant (font_matrix);
130605
    if (! ISFINITE (det))
12
	return _cairo_scaled_font_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_MATRIX));
130593
    det = _cairo_matrix_compute_determinant (ctm);
130593
    if (! ISFINITE (det))
6
	return _cairo_scaled_font_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_MATRIX));
130587
    status = cairo_font_options_status ((cairo_font_options_t *) options);
130587
    if (unlikely (status))
1
	return _cairo_scaled_font_create_in_error (status);
    /* Note that degenerate ctm or font_matrix *are* allowed.
     * We want to support a font size of 0. */
130586
    font_map = _cairo_scaled_font_map_lock ();
130586
    if (unlikely (font_map == NULL))
	return _cairo_scaled_font_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
130586
    scaled_font = font_map->mru_scaled_font;
260864
    if (scaled_font != NULL &&
130278
	_cairo_scaled_font_matches (scaled_font,
	                            font_face, font_matrix, ctm, options))
    {
50124
	assert (scaled_font->hash_entry.hash != ZOMBIE);
50124
	assert (! scaled_font->placeholder);
50124
	if (likely (scaled_font->status == CAIRO_STATUS_SUCCESS)) {
	    /* We increment the reference count manually here, (rather
	     * than calling into cairo_scaled_font_reference), since we
	     * must modify the reference count while our lock is still
	     * held. */
50124
	    _cairo_reference_count_inc (&scaled_font->ref_count);
50124
	    _cairo_scaled_font_map_unlock ();
50124
	    return scaled_font;
	}
	/* the font has been put into an error status - abandon the cache */
	_cairo_hash_table_remove (font_map->hash_table,
				  &scaled_font->hash_entry);
	scaled_font->hash_entry.hash = ZOMBIE;
	dead = scaled_font;
	font_map->mru_scaled_font = NULL;
    }
80462
    _cairo_scaled_font_init_key (&key, font_face, font_matrix, ctm, options);
80462
    while ((scaled_font = _cairo_hash_table_lookup (font_map->hash_table,
						    &key.hash_entry)))
    {
79416
	if (! scaled_font->placeholder)
79416
	    break;
	/* If the scaled font is being created (happens for user-font),
	 * just wait until it's done, then retry */
	_cairo_scaled_font_placeholder_wait_for_creation_to_finish (scaled_font);
    }
80462
    _cairo_scaled_font_fini_key (&key);
80462
    if (scaled_font != NULL) {
	/* If the original reference count is 0, then this font must have
	 * been found in font_map->holdovers, (which means this caching is
	 * actually working). So now we remove it from the holdovers
	 * array, unless we caught the font in the middle of destruction.
	 */
158832
	if (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count)) {
67574
	    if (scaled_font->holdover) {
		int i;
73679
		for (i = 0; i < font_map->num_holdovers; i++) {
73679
		    if (font_map->holdovers[i] == scaled_font) {
67574
			font_map->num_holdovers--;
67574
			memmove (&font_map->holdovers[i],
67574
				 &font_map->holdovers[i+1],
67574
				 (font_map->num_holdovers - i) * sizeof (cairo_scaled_font_t*));
67574
			break;
		    }
		}
67574
		scaled_font->holdover = FALSE;
	    }
	    /* reset any error status */
67574
	    scaled_font->status = CAIRO_STATUS_SUCCESS;
	}
79416
	if (likely (scaled_font->status == CAIRO_STATUS_SUCCESS)) {
	    /* We increment the reference count manually here, (rather
	     * than calling into cairo_scaled_font_reference), since we
	     * must modify the reference count while our lock is still
	     * held. */
79416
	    old = font_map->mru_scaled_font;
79416
	    font_map->mru_scaled_font = scaled_font;
	    /* increment reference count for the mru cache */
79416
	    _cairo_reference_count_inc (&scaled_font->ref_count);
	    /* and increment for the returned reference */
79416
	    _cairo_reference_count_inc (&scaled_font->ref_count);
79416
	    _cairo_scaled_font_map_unlock ();
79416
	    cairo_scaled_font_destroy (old);
79416
	    if (font_face != original_font_face)
		cairo_font_face_destroy (font_face);
79416
	    return scaled_font;
	}
	/* the font has been put into an error status - abandon the cache */
	_cairo_hash_table_remove (font_map->hash_table,
				  &scaled_font->hash_entry);
	scaled_font->hash_entry.hash = ZOMBIE;
    }
    /* Otherwise create it and insert it into the hash table. */
1046
    if (font_face->backend->get_implementation != NULL) {
1001
	font_face = font_face->backend->get_implementation (font_face,
							    font_matrix,
							    ctm,
							    options);
1001
	if (unlikely (font_face->status)) {
	    _cairo_scaled_font_map_unlock ();
	    return _cairo_scaled_font_create_in_error (font_face->status);
	}
    }
1046
    status = font_face->backend->scaled_font_create (font_face, font_matrix,
						     ctm, options, &scaled_font);
1046
    if (unlikely (status)) {
	_cairo_scaled_font_map_unlock ();
	if (font_face != original_font_face)
	    cairo_font_face_destroy (font_face);
	if (dead != NULL)
	    cairo_scaled_font_destroy (dead);
	return _cairo_scaled_font_create_in_error (status);
    }
    /* Or did we encounter an error whilst constructing the scaled font? */
1046
    if (unlikely (scaled_font->status)) {
9
	_cairo_scaled_font_map_unlock ();
9
	if (font_face != original_font_face)
9
	    cairo_font_face_destroy (font_face);
9
	if (dead != NULL)
	    cairo_scaled_font_destroy (dead);
9
	return scaled_font;
    }
    /* Our caching above is defeated if the backend switches fonts on us -
     * e.g. old incarnations of toy-font-face and lazily resolved
     * ft-font-faces
     */
1037
    assert (scaled_font->font_face == font_face);
1037
    assert (! scaled_font->cache_frozen);
1037
    assert (! scaled_font->global_cache_frozen);
2074
    scaled_font->original_font_face =
1037
	cairo_font_face_reference (original_font_face);
1037
    scaled_font->hash_entry.hash = _cairo_scaled_font_compute_hash(scaled_font);
1037
    status = _cairo_hash_table_insert (font_map->hash_table,
1037
				       &scaled_font->hash_entry);
1037
    if (likely (status == CAIRO_STATUS_SUCCESS)) {
1037
	old = font_map->mru_scaled_font;
1037
	font_map->mru_scaled_font = scaled_font;
1037
	_cairo_reference_count_inc (&scaled_font->ref_count);
    }
1037
    _cairo_scaled_font_map_unlock ();
1037
    cairo_scaled_font_destroy (old);
1037
    if (font_face != original_font_face)
713
	cairo_font_face_destroy (font_face);
1037
    if (dead != NULL)
	cairo_scaled_font_destroy (dead);
1037
    if (unlikely (status)) {
	/* We can't call _cairo_scaled_font_destroy here since it expects
	 * that the font has already been successfully inserted into the
	 * hash table. */
	_cairo_scaled_font_fini_internal (scaled_font);
	free (scaled_font);
	return _cairo_scaled_font_create_in_error (status);
    }
1037
    return scaled_font;
}
static cairo_scaled_font_t *_cairo_scaled_font_nil_objects[CAIRO_STATUS_LAST_STATUS + 1];
/* XXX This should disappear in favour of a common pool of error objects. */
cairo_scaled_font_t *
42
_cairo_scaled_font_create_in_error (cairo_status_t status)
{
    cairo_scaled_font_t *scaled_font;
42
    assert (status != CAIRO_STATUS_SUCCESS);
42
    if (status == CAIRO_STATUS_NO_MEMORY)
	return (cairo_scaled_font_t *) &_cairo_scaled_font_nil;
42
    CAIRO_MUTEX_LOCK (_cairo_scaled_font_error_mutex);
42
    scaled_font = _cairo_scaled_font_nil_objects[status];
42
    if (unlikely (scaled_font == NULL)) {
9
	scaled_font = _cairo_calloc (sizeof (cairo_scaled_font_t));
9
	if (unlikely (scaled_font == NULL)) {
	    CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_error_mutex);
	    _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
	    return (cairo_scaled_font_t *) &_cairo_scaled_font_nil;
	}
9
	*scaled_font = _cairo_scaled_font_nil;
9
	scaled_font->status = status;
9
	_cairo_scaled_font_nil_objects[status] = scaled_font;
    }
42
    CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_error_mutex);
42
    return scaled_font;
}
void
608
_cairo_scaled_font_reset_static_data (void)
{
    int status;
608
    CAIRO_MUTEX_LOCK (_cairo_scaled_font_error_mutex);
608
    for (status = CAIRO_STATUS_SUCCESS;
28576
	 status <= CAIRO_STATUS_LAST_STATUS;
27968
	 status++)
    {
27968
	free (_cairo_scaled_font_nil_objects[status]);
27968
	_cairo_scaled_font_nil_objects[status] = NULL;
    }
608
    CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_error_mutex);
608
    CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex);
608
    if (cairo_scaled_glyph_page_cache.hash_table != NULL) {
	_cairo_cache_fini (&cairo_scaled_glyph_page_cache);
	cairo_scaled_glyph_page_cache.hash_table = NULL;
    }
608
    CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex);
608
}
/**
 * cairo_scaled_font_reference:
 * @scaled_font: a #cairo_scaled_font_t, (may be %NULL in which case
 * this function does nothing)
 *
 * Increases the reference count on @scaled_font by one. This prevents
 * @scaled_font from being destroyed until a matching call to
 * cairo_scaled_font_destroy() is made.
 *
 * Use cairo_scaled_font_get_reference_count() to get the number of
 * references to a #cairo_scaled_font_t.
 *
 * Returns: the referenced #cairo_scaled_font_t
 *
 * Since: 1.0
 **/
cairo_scaled_font_t *
132118
cairo_scaled_font_reference (cairo_scaled_font_t *scaled_font)
{
132118
    if (scaled_font == NULL ||
1188
	    CAIRO_REFERENCE_COUNT_IS_INVALID (&scaled_font->ref_count))
131524
	return scaled_font;
1188
    assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count));
594
    _cairo_reference_count_inc (&scaled_font->ref_count);
594
    return scaled_font;
}
/**
 * cairo_scaled_font_destroy:
 * @scaled_font: a #cairo_scaled_font_t
 *
 * Decreases the reference count on @font by one. If the result
 * is zero, then @font and all associated resources are freed.
 * See cairo_scaled_font_reference().
 *
 * Since: 1.0
 **/
void
384828
cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font)
{
384828
    cairo_scaled_font_t *lru = NULL;
    cairo_scaled_font_map_t *font_map;
    assert (CAIRO_MUTEX_IS_UNLOCKED (_cairo_scaled_font_map_mutex));
384828
    if (scaled_font == NULL ||
422590
	    CAIRO_REFERENCE_COUNT_IS_INVALID (&scaled_font->ref_count))
173552
	return;
422552
    assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count));
211276
    font_map = _cairo_scaled_font_map_lock ();
211276
    assert (font_map != NULL);
211276
    if (! _cairo_reference_count_dec_and_test (&scaled_font->ref_count))
142925
	goto unlock;
68351
    assert (! scaled_font->cache_frozen);
68351
    assert (! scaled_font->global_cache_frozen);
    /* Another thread may have resurrected the font whilst we waited */
136702
    if (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count)) {
68351
	if (! scaled_font->placeholder &&
68273
	    scaled_font->hash_entry.hash != ZOMBIE)
	{
	    /* Another thread may have already inserted us into the holdovers */
68273
	    if (scaled_font->holdover)
		goto unlock;
	    /* Rather than immediately destroying this object, we put it into
	     * the font_map->holdovers array in case it will get used again
	     * soon (and is why we must hold the lock over the atomic op on
	     * the reference count). To make room for it, we do actually
	     * destroy the least-recently-used holdover.
	     */
68273
	    if (font_map->num_holdovers == CAIRO_SCALED_FONT_MAX_HOLDOVERS) {
		lru = font_map->holdovers[0];
		assert (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&lru->ref_count));
		_cairo_hash_table_remove (font_map->hash_table,
					  &lru->hash_entry);
		font_map->num_holdovers--;
		memmove (&font_map->holdovers[0],
			 &font_map->holdovers[1],
			 font_map->num_holdovers * sizeof (cairo_scaled_font_t*));
	    }
68273
	    font_map->holdovers[font_map->num_holdovers++] = scaled_font;
68273
	    scaled_font->holdover = TRUE;
	} else
78
	    lru = scaled_font;
    }
  unlock:
211276
    _cairo_scaled_font_map_unlock ();
    /* If we pulled an item from the holdovers array, (while the font
     * map lock was held, of course), then there is no way that anyone
     * else could have acquired a reference to it. So we can now
     * safely call fini on it without any lock held. This is desirable
     * as we never want to call into any backend function with a lock
     * held. */
211276
    if (lru != NULL) {
78
	_cairo_scaled_font_fini_internal (lru);
78
	free (lru);
    }
}
/**
 * cairo_scaled_font_get_reference_count:
 * @scaled_font: a #cairo_scaled_font_t
 *
 * Returns the current reference count of @scaled_font.
 *
 * Return value: the current reference count of @scaled_font.  If the
 * object is a nil object, 0 will be returned.
 *
 * Since: 1.4
 **/
unsigned int
cairo_scaled_font_get_reference_count (cairo_scaled_font_t *scaled_font)
{
    if (scaled_font == NULL ||
	    CAIRO_REFERENCE_COUNT_IS_INVALID (&scaled_font->ref_count))
	return 0;
    return CAIRO_REFERENCE_COUNT_GET_VALUE (&scaled_font->ref_count);
}
/**
 * cairo_scaled_font_get_user_data:
 * @scaled_font: a #cairo_scaled_font_t
 * @key: the address of the #cairo_user_data_key_t the user data was
 * attached to
 *
 * Return user data previously attached to @scaled_font using the
 * specified key.  If no user data has been attached with the given
 * key this function returns %NULL.
 *
 * Return value: the user data previously attached or %NULL.
 *
 * Since: 1.4
 **/
void *
495
cairo_scaled_font_get_user_data (cairo_scaled_font_t	     *scaled_font,
				 const cairo_user_data_key_t *key)
{
495
    return _cairo_user_data_array_get_data (&scaled_font->user_data,
					    key);
}
/**
 * cairo_scaled_font_set_user_data:
 * @scaled_font: a #cairo_scaled_font_t
 * @key: the address of a #cairo_user_data_key_t to attach the user data to
 * @user_data: the user data to attach to the #cairo_scaled_font_t
 * @destroy: a #cairo_destroy_func_t which will be called when the
 * #cairo_t is destroyed or when new user data is attached using the
 * same key.
 *
 * Attach user data to @scaled_font.  To remove user data from a surface,
 * call this function with the key that was used to set it and %NULL
 * for @data.
 *
 * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a
 * slot could not be allocated for the user data.
 *
 * Since: 1.4
 **/
cairo_status_t
60
cairo_scaled_font_set_user_data (cairo_scaled_font_t	     *scaled_font,
				 const cairo_user_data_key_t *key,
				 void			     *user_data,
				 cairo_destroy_func_t	      destroy)
{
120
    if (CAIRO_REFERENCE_COUNT_IS_INVALID (&scaled_font->ref_count))
	return scaled_font->status;
60
    return _cairo_user_data_array_set_data (&scaled_font->user_data,
					    key, user_data, destroy);
}
/* Public font API follows. */
/**
 * cairo_scaled_font_extents:
 * @scaled_font: a #cairo_scaled_font_t
 * @extents: a #cairo_font_extents_t which to store the retrieved extents.
 *
 * Gets the metrics for a #cairo_scaled_font_t.
 *
 * Since: 1.0
 **/
void
110796
cairo_scaled_font_extents (cairo_scaled_font_t  *scaled_font,
			   cairo_font_extents_t *extents)
{
110796
    if (scaled_font->status) {
	extents->ascent  = 0.0;
	extents->descent = 0.0;
	extents->height  = 0.0;
	extents->max_x_advance = 0.0;
	extents->max_y_advance = 0.0;
	return;
    }
110796
    *extents = scaled_font->extents;
}
/**
 * cairo_scaled_font_text_extents:
 * @scaled_font: a #cairo_scaled_font_t
 * @utf8: a NUL-terminated string of text, encoded in UTF-8
 * @extents: a #cairo_text_extents_t which to store the retrieved extents.
 *
 * Gets the extents for a string of text. The extents describe a
 * user-space rectangle that encloses the "inked" portion of the text
 * drawn at the origin (0,0) (as it would be drawn by cairo_show_text()
 * if the cairo graphics state were set to the same font_face,
 * font_matrix, ctm, and font_options as @scaled_font).  Additionally,
 * the x_advance and y_advance values indicate the amount by which the
 * current point would be advanced by cairo_show_text().
 *
 * Note that whitespace characters do not directly contribute to the
 * size of the rectangle (extents.width and extents.height). They do
 * contribute indirectly by changing the position of non-whitespace
 * characters. In particular, trailing whitespace characters are
 * likely to not affect the size of the rectangle, though they will
 * affect the x_advance and y_advance values.
 *
 * Since: 1.2
 **/
void
15
cairo_scaled_font_text_extents (cairo_scaled_font_t   *scaled_font,
				const char            *utf8,
				cairo_text_extents_t  *extents)
{
    cairo_status_t status;
15
    cairo_glyph_t *glyphs = NULL;
    int num_glyphs;
15
    if (scaled_font->status)
	goto ZERO_EXTENTS;
15
    if (utf8 == NULL)
3
	goto ZERO_EXTENTS;
12
    status = cairo_scaled_font_text_to_glyphs (scaled_font, 0., 0.,
					       utf8, -1,
					       &glyphs, &num_glyphs,
					       NULL, NULL,
					       NULL);
12
    if (unlikely (status)) {
	status = _cairo_scaled_font_set_error (scaled_font, status);
	goto ZERO_EXTENTS;
    }
12
    cairo_scaled_font_glyph_extents (scaled_font, glyphs, num_glyphs, extents);
12
    free (glyphs);
12
    return;
3
ZERO_EXTENTS:
3
    extents->x_bearing = 0.0;
3
    extents->y_bearing = 0.0;
3
    extents->width  = 0.0;
3
    extents->height = 0.0;
3
    extents->x_advance = 0.0;
3
    extents->y_advance = 0.0;
}
/**
 * cairo_scaled_font_glyph_extents:
 * @scaled_font: a #cairo_scaled_font_t
 * @glyphs: an array of glyph IDs with X and Y offsets.
 * @num_glyphs: the number of glyphs in the @glyphs array
 * @extents: a #cairo_text_extents_t which to store the retrieved extents.
 *
 * Gets the extents for an array of glyphs. The extents describe a
 * user-space rectangle that encloses the "inked" portion of the
 * glyphs, (as they would be drawn by cairo_show_glyphs() if the cairo
 * graphics state were set to the same font_face, font_matrix, ctm,
 * and font_options as @scaled_font).  Additionally, the x_advance and
 * y_advance values indicate the amount by which the current point
 * would be advanced by cairo_show_glyphs().
 *
 * Note that whitespace glyphs do not contribute to the size of the
 * rectangle (extents.width and extents.height).
 *
 * Since: 1.0
 **/
void
68439
cairo_scaled_font_glyph_extents (cairo_scaled_font_t   *scaled_font,
				 const cairo_glyph_t   *glyphs,
				 int                    num_glyphs,
				 cairo_text_extents_t  *extents)
{
    cairo_status_t status;
    int i;
68439
    double min_x = 0.0, min_y = 0.0, max_x = 0.0, max_y = 0.0;
68439
    cairo_bool_t visible = FALSE;
68439
    cairo_scaled_glyph_t *scaled_glyph = NULL;
68439
    extents->x_bearing = 0.0;
68439
    extents->y_bearing = 0.0;
68439
    extents->width  = 0.0;
68439
    extents->height = 0.0;
68439
    extents->x_advance = 0.0;
68439
    extents->y_advance = 0.0;
68439
    if (unlikely (scaled_font->status))
	goto ZERO_EXTENTS;
68439
    if (num_glyphs == 0)
9
	goto ZERO_EXTENTS;
68430
    if (unlikely (num_glyphs < 0)) {
	_cairo_error_throw (CAIRO_STATUS_NEGATIVE_COUNT);
	/* XXX Can't propagate error */
	goto ZERO_EXTENTS;
    }
68430
    if (unlikely (glyphs == NULL)) {
	_cairo_error_throw (CAIRO_STATUS_NULL_POINTER);
	/* XXX Can't propagate error */
	goto ZERO_EXTENTS;
    }
68430
    _cairo_scaled_font_freeze_cache (scaled_font);
279306
    for (i = 0; i < num_glyphs; i++) {
	double			left, top, right, bottom;
210876
	status = _cairo_scaled_glyph_lookup (scaled_font,
210876
					     glyphs[i].index,
					     CAIRO_SCALED_GLYPH_INFO_METRICS,
					     NULL, /* foreground color */
					     &scaled_glyph);
210876
	if (unlikely (status)) {
	    status = _cairo_scaled_font_set_error (scaled_font, status);
	    goto UNLOCK;
	}
	/* "Ink" extents should skip "invisible" glyphs */
210876
	if (scaled_glyph->metrics.width == 0 || scaled_glyph->metrics.height == 0)
744
	    continue;
210132
	left = scaled_glyph->metrics.x_bearing + glyphs[i].x;
210132
	right = left + scaled_glyph->metrics.width;
210132
	top = scaled_glyph->metrics.y_bearing + glyphs[i].y;
210132
	bottom = top + scaled_glyph->metrics.height;
210132
	if (!visible) {
67935
	    visible = TRUE;
67935
	    min_x = left;
67935
	    max_x = right;
67935
	    min_y = top;
67935
	    max_y = bottom;
	} else {
142197
	    if (left < min_x) min_x = left;
142197
	    if (right > max_x) max_x = right;
142197
	    if (top < min_y) min_y = top;
142197
	    if (bottom > max_y) max_y = bottom;
	}
    }
68430
    if (visible) {
67935
	extents->x_bearing = min_x - glyphs[0].x;
67935
	extents->y_bearing = min_y - glyphs[0].y;
67935
	extents->width = max_x - min_x;
67935
	extents->height = max_y - min_y;
    } else {
495
	extents->x_bearing = 0.0;
495
	extents->y_bearing = 0.0;
495
	extents->width = 0.0;
495
	extents->height = 0.0;
    }
68430
    if (num_glyphs) {
        double x0, y0, x1, y1;
68430
	x0 = glyphs[0].x;
68430
	y0 = glyphs[0].y;
	/* scaled_glyph contains the glyph for num_glyphs - 1 already. */
68430
	x1 = glyphs[num_glyphs - 1].x + scaled_glyph->metrics.x_advance;
68430
	y1 = glyphs[num_glyphs - 1].y + scaled_glyph->metrics.y_advance;
68430
	extents->x_advance = x1 - x0;
68430
	extents->y_advance = y1 - y0;
    } else {
	extents->x_advance = 0.0;
	extents->y_advance = 0.0;
    }
68430
 UNLOCK:
68430
    _cairo_scaled_font_thaw_cache (scaled_font);
68430
    return;
9
ZERO_EXTENTS:
9
    extents->x_bearing = 0.0;
9
    extents->y_bearing = 0.0;
9
    extents->width  = 0.0;
9
    extents->height = 0.0;
9
    extents->x_advance = 0.0;
9
    extents->y_advance = 0.0;
}
#define GLYPH_LUT_SIZE 64
static cairo_status_t
99
cairo_scaled_font_text_to_glyphs_internal_cached (cairo_scaled_font_t		 *scaled_font,
						    double			  x,
						    double			  y,
						    const char			 *utf8,
						    cairo_glyph_t		 *glyphs,
						    cairo_text_cluster_t	**clusters,
						    int				  num_chars)
{
    struct glyph_lut_elt {
	unsigned long index;
	double x_advance;
	double y_advance;
    } glyph_lut[GLYPH_LUT_SIZE];
    uint32_t glyph_lut_unicode[GLYPH_LUT_SIZE];
    cairo_status_t status;
    const char *p;
    int i;
6435
    for (i = 0; i < GLYPH_LUT_SIZE; i++)
6336
	glyph_lut_unicode[i] = ~0U;
99
    p = utf8;
25899
    for (i = 0; i < num_chars; i++) {
	int idx, num_bytes;
	uint32_t unicode;
	cairo_scaled_glyph_t *scaled_glyph;
	struct glyph_lut_elt *glyph_slot;
25800
	num_bytes = _cairo_utf8_get_char_validated (p, &unicode);
25800
	p += num_bytes;
25800
	glyphs[i].x = x;
25800
	glyphs[i].y = y;
25800
	idx = unicode % ARRAY_LENGTH (glyph_lut);
25800
	glyph_slot = &glyph_lut[idx];
25800
	if (glyph_lut_unicode[idx] == unicode) {
23973
	    glyphs[i].index = glyph_slot->index;
23973
	    x += glyph_slot->x_advance;
23973
	    y += glyph_slot->y_advance;
	} else {
	    unsigned long g;
1827
	    g = scaled_font->backend->ucs4_to_index (scaled_font, unicode);
1827
	    status = _cairo_scaled_glyph_lookup (scaled_font,
						 g,
						 CAIRO_SCALED_GLYPH_INFO_METRICS,
						 NULL, /* foreground color */
						 &scaled_glyph);
1827
	    if (unlikely (status))
		return status;
1827
	    x += scaled_glyph->metrics.x_advance;
1827
	    y += scaled_glyph->metrics.y_advance;
1827
	    glyph_lut_unicode[idx] = unicode;
1827
	    glyph_slot->index = g;
1827
	    glyph_slot->x_advance = scaled_glyph->metrics.x_advance;
1827
	    glyph_slot->y_advance = scaled_glyph->metrics.y_advance;
1827
	    glyphs[i].index = g;
	}
25800
	if (clusters) {
	    (*clusters)[i].num_bytes  = num_bytes;
	    (*clusters)[i].num_glyphs = 1;
	}
    }
99
    return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
67878
cairo_scaled_font_text_to_glyphs_internal_uncached (cairo_scaled_font_t	 *scaled_font,
						  double		  x,
						  double		  y,
						  const char		 *utf8,
						  cairo_glyph_t		 *glyphs,
						  cairo_text_cluster_t	**clusters,
						  int			  num_chars)
{
    const char *p;
    int i;
67878
    p = utf8;
399042
    for (i = 0; i < num_chars; i++) {
	unsigned long g;
	int num_bytes;
	uint32_t unicode;
	cairo_scaled_glyph_t *scaled_glyph;
	cairo_status_t status;
331164
	num_bytes = _cairo_utf8_get_char_validated (p, &unicode);
331164
	p += num_bytes;
331164
	glyphs[i].x = x;
331164
	glyphs[i].y = y;
331164
	g = scaled_font->backend->ucs4_to_index (scaled_font, unicode);
	/*
	 * No advance needed for a single character string. So, let's speed up
	 * one-character strings by skipping glyph lookup.
	 */
331164
	if (num_chars > 1) {
328938
	    status = _cairo_scaled_glyph_lookup (scaled_font,
					     g,
					     CAIRO_SCALED_GLYPH_INFO_METRICS,
					     NULL, /* foreground color */
					     &scaled_glyph);
328938
	    if (unlikely (status))
		return status;
328938
	    x += scaled_glyph->metrics.x_advance;
328938
	    y += scaled_glyph->metrics.y_advance;
	}
331164
	glyphs[i].index = g;
331164
	if (clusters) {
696
	    (*clusters)[i].num_bytes  = num_bytes;
696
	    (*clusters)[i].num_glyphs = 1;
	}
    }
67878
    return CAIRO_STATUS_SUCCESS;
}
/**
 * cairo_scaled_font_text_to_glyphs:
 * @scaled_font: a #cairo_scaled_font_t
 * @x: X position to place first glyph
 * @y: Y position to place first glyph
 * @utf8: a string of text encoded in UTF-8
 * @utf8_len: length of @utf8 in bytes, or -1 if it is NUL-terminated
 * @glyphs: pointer to array of glyphs to fill
 * @num_glyphs: pointer to number of glyphs
 * @clusters: pointer to array of cluster mapping information to fill, or %NULL
 * @num_clusters: pointer to number of clusters, or %NULL
 * @cluster_flags: pointer to location to store cluster flags corresponding to the
 *                 output @clusters, or %NULL
 *
 * Converts UTF-8 text to an array of glyphs, optionally with cluster
 * mapping, that can be used to render later using @scaled_font.
 *
 * If @glyphs initially points to a non-%NULL value, that array is used
 * as a glyph buffer, and @num_glyphs should point to the number of glyph
 * entries available there.  If the provided glyph array is too short for
 * the conversion, a new glyph array is allocated using cairo_glyph_allocate()
 * and placed in @glyphs.  Upon return, @num_glyphs always contains the
 * number of generated glyphs.  If the value @glyphs points to has changed
 * after the call, the user is responsible for freeing the allocated glyph
 * array using cairo_glyph_free().  This may happen even if the provided
 * array was large enough.
 *
 * If @clusters is not %NULL, @num_clusters and @cluster_flags should not be %NULL,
 * and cluster mapping will be computed.
 * The semantics of how cluster array allocation works is similar to the glyph
 * array.  That is,
 * if @clusters initially points to a non-%NULL value, that array is used
 * as a cluster buffer, and @num_clusters should point to the number of cluster
 * entries available there.  If the provided cluster array is too short for
 * the conversion, a new cluster array is allocated using cairo_text_cluster_allocate()
 * and placed in @clusters.  Upon return, @num_clusters always contains the
 * number of generated clusters.  If the value @clusters points at has changed
 * after the call, the user is responsible for freeing the allocated cluster
 * array using cairo_text_cluster_free().  This may happen even if the provided
 * array was large enough.
 *
 * In the simplest case, @glyphs and @clusters can point to %NULL initially
 * and a suitable array will be allocated.  In code:
 * <informalexample><programlisting>
 * cairo_status_t status;
 *
 * cairo_glyph_t *glyphs = NULL;
 * int num_glyphs;
 * cairo_text_cluster_t *clusters = NULL;
 * int num_clusters;
 * cairo_text_cluster_flags_t cluster_flags;
 *
 * status = cairo_scaled_font_text_to_glyphs (scaled_font,
 *                                            x, y,
 *                                            utf8, utf8_len,
 *                                            &amp;glyphs, &amp;num_glyphs,
 *                                            &amp;clusters, &amp;num_clusters, &amp;cluster_flags);
 *
 * if (status == CAIRO_STATUS_SUCCESS) {
 *     cairo_show_text_glyphs (cr,
 *                             utf8, utf8_len,
 *                             glyphs, num_glyphs,
 *                             clusters, num_clusters, cluster_flags);
 *
 *     cairo_glyph_free (glyphs);
 *     cairo_text_cluster_free (clusters);
 * }
 * </programlisting></informalexample>
 *
 * If no cluster mapping is needed:
 * <informalexample><programlisting>
 * cairo_status_t status;
 *
 * cairo_glyph_t *glyphs = NULL;
 * int num_glyphs;
 *
 * status = cairo_scaled_font_text_to_glyphs (scaled_font,
 *                                            x, y,
 *                                            utf8, utf8_len,
 *                                            &amp;glyphs, &amp;num_glyphs,
 *                                            NULL, NULL,
 *                                            NULL);
 *
 * if (status == CAIRO_STATUS_SUCCESS) {
 *     cairo_show_glyphs (cr, glyphs, num_glyphs);
 *     cairo_glyph_free (glyphs);
 * }
 * </programlisting></informalexample>
 *
 * If stack-based glyph and cluster arrays are to be used for small
 * arrays:
 * <informalexample><programlisting>
 * cairo_status_t status;
 *
 * cairo_glyph_t stack_glyphs[40];
 * cairo_glyph_t *glyphs = stack_glyphs;
 * int num_glyphs = sizeof (stack_glyphs) / sizeof (stack_glyphs[0]);
 * cairo_text_cluster_t stack_clusters[40];
 * cairo_text_cluster_t *clusters = stack_clusters;
 * int num_clusters = sizeof (stack_clusters) / sizeof (stack_clusters[0]);
 * cairo_text_cluster_flags_t cluster_flags;
 *
 * status = cairo_scaled_font_text_to_glyphs (scaled_font,
 *                                            x, y,
 *                                            utf8, utf8_len,
 *                                            &amp;glyphs, &amp;num_glyphs,
 *                                            &amp;clusters, &amp;num_clusters, &amp;cluster_flags);
 *
 * if (status == CAIRO_STATUS_SUCCESS) {
 *     cairo_show_text_glyphs (cr,
 *                             utf8, utf8_len,
 *                             glyphs, num_glyphs,
 *                             clusters, num_clusters, cluster_flags);
 *
 *     if (glyphs != stack_glyphs)
 *         cairo_glyph_free (glyphs);
 *     if (clusters != stack_clusters)
 *         cairo_text_cluster_free (clusters);
 * }
 * </programlisting></informalexample>
 *
 * For details of how @clusters, @num_clusters, and @cluster_flags map input
 * UTF-8 text to the output glyphs see cairo_show_text_glyphs().
 *
 * The output values can be readily passed to cairo_show_text_glyphs()
 * cairo_show_glyphs(), or related functions, assuming that the exact
 * same @scaled_font is used for the operation.
 *
 * Return value: %CAIRO_STATUS_SUCCESS upon success, or an error status
 * if the input values are wrong or if conversion failed.  If the input
 * values are correct but the conversion failed, the error status is also
 * set on @scaled_font.
 *
 * Since: 1.8
 **/
#define CACHING_THRESHOLD 16
cairo_status_t
68007
cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t   *scaled_font,
				  double		 x,
				  double		 y,
				  const char	        *utf8,
				  int		         utf8_len,
				  cairo_glyph_t	       **glyphs,
				  int		        *num_glyphs,
				  cairo_text_cluster_t **clusters,
				  int		        *num_clusters,
				  cairo_text_cluster_flags_t *cluster_flags)
{
68007
    int num_chars = 0;
    cairo_int_status_t status;
    cairo_glyph_t *orig_glyphs;
    cairo_text_cluster_t *orig_clusters;
68007
    status = scaled_font->status;
68007
    if (unlikely (status))
	return status;
    /* A slew of sanity checks */
    /* glyphs and num_glyphs can't be NULL */
68007
    if (glyphs     == NULL ||
	num_glyphs == NULL) {
	status = _cairo_error (CAIRO_STATUS_NULL_POINTER);
	goto BAIL;
    }
    /* Special case for NULL and -1 */
68007
    if (utf8 == NULL && utf8_len == -1)
	utf8_len = 0;
    /* No NULLs for non-NULLs! */
68007
    if ((utf8_len && utf8          == NULL) ||
68007
	(clusters && num_clusters  == NULL) ||
210
	(clusters && cluster_flags == NULL)) {
	status = _cairo_error (CAIRO_STATUS_NULL_POINTER);
	goto BAIL;
    }
    /* A -1 for utf8_len means NUL-terminated */
68007
    if (utf8_len == -1)
33195
	utf8_len = strlen (utf8);
    /* A NULL *glyphs means no prealloced glyphs array */
68007
    if (glyphs && *glyphs == NULL)
33051
	*num_glyphs = 0;
    /* A NULL *clusters means no prealloced clusters array */
68007
    if (clusters && *clusters == NULL)
	*num_clusters = 0;
68007
    if (!clusters && num_clusters) {
34575
	num_clusters = NULL;
    }
68007
    if (cluster_flags) {
34785
	*cluster_flags = FALSE;
    }
68007
    if (!clusters && cluster_flags) {
34575
	cluster_flags = NULL;
    }
    /* Apart from that, no negatives */
68007
    if (utf8_len < 0 ||
68007
	*num_glyphs < 0 ||
210
	(num_clusters && *num_clusters < 0)) {
	status = _cairo_error (CAIRO_STATUS_NEGATIVE_COUNT);
	goto BAIL;
    }
68007
    if (utf8_len == 0) {
12
	status = CAIRO_STATUS_SUCCESS;
12
	goto BAIL;
    }
    /* validate input so backend does not have to */
67995
    status = _cairo_utf8_to_ucs4 (utf8, utf8_len, NULL, &num_chars);
67995
    if (unlikely (status))
	goto BAIL;
67995
    _cairo_scaled_font_freeze_cache (scaled_font);
67995
    orig_glyphs = *glyphs;
67995
    orig_clusters = clusters ? *clusters : NULL;
67995
    if (scaled_font->backend->text_to_glyphs) {
423
	status = scaled_font->backend->text_to_glyphs (scaled_font, x, y,
						       utf8, utf8_len,
						       glyphs, num_glyphs,
						       clusters, num_clusters,
						       cluster_flags);
423
        if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
18
	    if (status == CAIRO_INT_STATUS_SUCCESS) {
	        /* The checks here are crude; we only should do them in
		 * user-font backend, but they don't hurt here.  This stuff
		 * can be hard to get right. */
18
	        if (*num_glyphs < 0) {
		    status = _cairo_error (CAIRO_STATUS_NEGATIVE_COUNT);
		    goto DONE;
		}
18
		if (*num_glyphs != 0 && *glyphs == NULL) {
		    status = _cairo_error (CAIRO_STATUS_NULL_POINTER);
		    goto DONE;
		}
18
		if (clusters) {
		    if (*num_clusters < 0) {
			status = _cairo_error (CAIRO_STATUS_NEGATIVE_COUNT);
			goto DONE;
		    }
		    if (*num_clusters != 0 && *clusters == NULL) {
			status = _cairo_error (CAIRO_STATUS_NULL_POINTER);
			goto DONE;
		    }
		    /* Don't trust the backend, validate clusters! */
		    status =
			_cairo_validate_text_clusters (utf8, utf8_len,
						       *glyphs, *num_glyphs,
						       *clusters, *num_clusters,
						       *cluster_flags);
		}
	    }
18
            goto DONE;
	}
    }
67977
    if (*num_glyphs < num_chars) {
33051
	*glyphs = cairo_glyph_allocate (num_chars);
33051
	if (unlikely (*glyphs == NULL)) {
	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
	    goto DONE;
	}
    }
67977
    *num_glyphs = num_chars;
67977
    if (clusters) {
210
	if (*num_clusters < num_chars) {
	    *clusters = cairo_text_cluster_allocate (num_chars);
	    if (unlikely (*clusters == NULL)) {
		status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
		goto DONE;
	    }
	}
210
	*num_clusters = num_chars;
    }
67977
    if (num_chars > CACHING_THRESHOLD)
99
	status = cairo_scaled_font_text_to_glyphs_internal_cached (scaled_font,
								     x, y,
								     utf8,
								     *glyphs,
								     clusters,
								     num_chars);
    else
67878
	status = cairo_scaled_font_text_to_glyphs_internal_uncached (scaled_font,
								   x, y,
								   utf8,
								   *glyphs,
								   clusters,
								   num_chars);
67995
 DONE: /* error that should be logged on scaled_font happened */
67995
    _cairo_scaled_font_thaw_cache (scaled_font);
67995
    if (unlikely (status)) {
	*num_glyphs = 0;
	if (*glyphs != orig_glyphs) {
	    cairo_glyph_free (*glyphs);
	    *glyphs = orig_glyphs;
	}
	if (clusters) {
	    *num_clusters = 0;
	    if (*clusters != orig_clusters) {
		cairo_text_cluster_free (*clusters);
		*clusters = orig_clusters;
	    }
	}
    }
67995
    return _cairo_scaled_font_set_error (scaled_font, status);
12
 BAIL: /* error with input arguments */
12
    if (num_glyphs)
12
	*num_glyphs = 0;
12
    if (num_clusters)
	*num_clusters = 0;
12
    return status;
}
static inline cairo_bool_t
250527
_range_contains_glyph (const cairo_box_t *extents,
		       cairo_fixed_t left,
		       cairo_fixed_t top,
		       cairo_fixed_t right,
		       cairo_fixed_t bottom)
{
250527
    if (left == right || top == bottom)
6624
	return FALSE;
441645
    return right > extents->p1.x &&
197742
	   left < extents->p2.x &&
487731
	   bottom > extents->p1.y &&
46086
	   top < extents->p2.y;
}
static cairo_status_t
27819
_cairo_scaled_font_single_glyph_device_extents (cairo_scaled_font_t	 *scaled_font,
						const cairo_glyph_t	 *glyph,
						cairo_rectangle_int_t   *extents)
{
    cairo_scaled_glyph_t *scaled_glyph;
    cairo_status_t status;
27819
    _cairo_scaled_font_freeze_cache (scaled_font);
27819
    status = _cairo_scaled_glyph_lookup (scaled_font,
27819
					 glyph->index,
					 CAIRO_SCALED_GLYPH_INFO_METRICS,
					 NULL, /* foreground color */
					 &scaled_glyph);
27819
    if (likely (status == CAIRO_STATUS_SUCCESS)) {
27819
	cairo_bool_t round_xy = _cairo_font_options_get_round_glyph_positions (&scaled_font->options) == CAIRO_ROUND_GLYPH_POS_ON;
	cairo_box_t box;
	cairo_fixed_t v;
27819
	if (round_xy)
27711
	    v = _cairo_fixed_from_int (_cairo_lround (glyph->x));
	else
108
	    v = _cairo_fixed_from_double (glyph->x);
27819
	box.p1.x = v + scaled_glyph->bbox.p1.x;
27819
	box.p2.x = v + scaled_glyph->bbox.p2.x;
27819
	if (round_xy)
27711
	    v = _cairo_fixed_from_int (_cairo_lround (glyph->y));
	else
108
	    v = _cairo_fixed_from_double (glyph->y);
27819
	box.p1.y = v + scaled_glyph->bbox.p1.y;
27819
	box.p2.y = v + scaled_glyph->bbox.p2.y;
27819
	_cairo_box_round_to_rectangle (&box, extents);
    }
27819
    _cairo_scaled_font_thaw_cache (scaled_font);
27819
    return status;
}
/*
 * Compute a device-space bounding box for the glyphs.
 */
cairo_status_t
70143
_cairo_scaled_font_glyph_device_extents (cairo_scaled_font_t	 *scaled_font,
					 const cairo_glyph_t	 *glyphs,
					 int                      num_glyphs,
					 cairo_rectangle_int_t   *extents,
					 cairo_bool_t *overlap_out)
{
70143
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
70143
    cairo_box_t box = { { INT_MAX, INT_MAX }, { INT_MIN, INT_MIN }};
    cairo_scaled_glyph_t *glyph_cache[64];
70143
    cairo_bool_t overlap = overlap_out ? FALSE : TRUE;
70143
    cairo_round_glyph_positions_t round_glyph_positions = _cairo_font_options_get_round_glyph_positions (&scaled_font->options);
    int i;
70143
    if (unlikely (scaled_font->status))
	return scaled_font->status;
70143
    if (num_glyphs == 1) {
27819
	if (overlap_out)
27522
	    *overlap_out = FALSE;
27819
	return _cairo_scaled_font_single_glyph_device_extents (scaled_font,
							       glyphs,
							       extents);
    }
42324
    _cairo_scaled_font_freeze_cache (scaled_font);
42324
    memset (glyph_cache, 0, sizeof (glyph_cache));
902694
    for (i = 0; i < num_glyphs; i++) {
	cairo_scaled_glyph_t	*scaled_glyph;
	cairo_fixed_t x, y, x1, y1, x2, y2;
860370
	int cache_index = glyphs[i].index % ARRAY_LENGTH (glyph_cache);
860370
	scaled_glyph = glyph_cache[cache_index];
860370
	if (scaled_glyph == NULL ||
635922
	    _cairo_scaled_glyph_index (scaled_glyph) != glyphs[i].index)
	{
246645
	    status = _cairo_scaled_glyph_lookup (scaled_font,
246645
						 glyphs[i].index,
						 CAIRO_SCALED_GLYPH_INFO_METRICS,
						 NULL, /* foreground color */
						 &scaled_glyph);
246645
	    if (unlikely (status))
		break;
246645
	    glyph_cache[cache_index] = scaled_glyph;
	}
860370
	if (round_glyph_positions == CAIRO_ROUND_GLYPH_POS_ON)
859830
	    x = _cairo_fixed_from_int (_cairo_lround (glyphs[i].x));
	else
540
	    x = _cairo_fixed_from_double (glyphs[i].x);
860370
	x1 = x + scaled_glyph->bbox.p1.x;
860370
	x2 = x + scaled_glyph->bbox.p2.x;
860370
	if (round_glyph_positions == CAIRO_ROUND_GLYPH_POS_ON)
859830
	    y = _cairo_fixed_from_int (_cairo_lround (glyphs[i].y));
	else
540
	    y = _cairo_fixed_from_double (glyphs[i].y);
860370
	y1 = y + scaled_glyph->bbox.p1.y;
860370
	y2 = y + scaled_glyph->bbox.p2.y;
860370
	if (overlap == FALSE)
250527
	    overlap = _range_contains_glyph (&box, x1, y1, x2, y2);
860370
	if (x1 < box.p1.x) box.p1.x = x1;
860370
	if (x2 > box.p2.x) box.p2.x = x2;
860370
	if (y1 < box.p1.y) box.p1.y = y1;
860370
	if (y2 > box.p2.y) box.p2.y = y2;
    }
42324
    _cairo_scaled_font_thaw_cache (scaled_font);
42324
    if (unlikely (status))
	return _cairo_scaled_font_set_error (scaled_font, status);
42324
    if (box.p1.x < box.p2.x) {
42324
	_cairo_box_round_to_rectangle (&box, extents);
    } else {
	extents->x = extents->y = 0;
	extents->width = extents->height = 0;
    }
42324
    if (overlap_out != NULL)
42270
	*overlap_out = overlap;
42324
    return CAIRO_STATUS_SUCCESS;
}
cairo_bool_t
_cairo_scaled_font_glyph_approximate_extents (cairo_scaled_font_t	 *scaled_font,
					      const cairo_glyph_t	 *glyphs,
					      int                      num_glyphs,
					      cairo_rectangle_int_t   *extents)
{
    double x0, x1, y0, y1, pad;
    int i;
    /* If any of the factors are suspect (i.e. the font is broken), bail */
    if (scaled_font->fs_extents.max_x_advance == 0 ||
	scaled_font->fs_extents.height == 0 ||
	scaled_font->max_scale == 0)
    {
	return FALSE;
    }
    assert (num_glyphs);
    x0 = x1 = glyphs[0].x;
    y0 = y1 = glyphs[0].y;
    for (i = 1; i < num_glyphs; i++) {
	double g;
	g = glyphs[i].x;
	if (g < x0) x0 = g;
	if (g > x1) x1 = g;
	g = glyphs[i].y;
	if (g < y0) y0 = g;
	if (g > y1) y1 = g;
    }
    pad = MAX(scaled_font->fs_extents.max_x_advance,
	      scaled_font->fs_extents.height);
    pad *= scaled_font->max_scale;
    extents->x = floor (x0 - pad);
    extents->width = ceil (x1 + pad) - extents->x;
    extents->y = floor (y0 - pad);
    extents->height = ceil (y1 + pad) - extents->y;
    return TRUE;
}
/* Add a single-device-unit rectangle to a path. */
static cairo_status_t
31416
_add_unit_rectangle_to_path (cairo_path_fixed_t *path,
			     cairo_fixed_t x,
			     cairo_fixed_t y)
{
    cairo_status_t status;
31416
    status = _cairo_path_fixed_move_to (path, x, y);
31416
    if (unlikely (status))
	return status;
31416
    status = _cairo_path_fixed_rel_line_to (path,
					    _cairo_fixed_from_int (1),
					    _cairo_fixed_from_int (0));
31416
    if (unlikely (status))
	return status;
31416
    status = _cairo_path_fixed_rel_line_to (path,
					    _cairo_fixed_from_int (0),
					    _cairo_fixed_from_int (1));
31416
    if (unlikely (status))
	return status;
31416
    status = _cairo_path_fixed_rel_line_to (path,
					    _cairo_fixed_from_int (-1),
					    _cairo_fixed_from_int (0));
31416
    if (unlikely (status))
	return status;
31416
    return _cairo_path_fixed_close_path (path);
}
/**
 * _trace_mask_to_path:
 * @bitmap: An alpha mask (either %CAIRO_FORMAT_A1 or %CAIRO_FORMAT_A8)
 * @path: An initialized path to hold the result
 *
 * Given a mask surface, (an alpha image), fill out the provided path
 * so that when filled it would result in something that approximates
 * the mask.
 *
 * Note: The current tracing code here is extremely primitive. It
 * operates only on an A1 surface, (converting an A8 surface to A1 if
 * necessary), and performs the tracing by drawing a little square
 * around each pixel that is on in the mask. We do not pretend that
 * this is a high-quality result. But we are leaving it up to someone
 * who cares enough about getting a better result to implement
 * something more sophisticated.
 **/
static cairo_status_t
177
_trace_mask_to_path (cairo_image_surface_t *mask,
		     cairo_path_fixed_t *path,
		     double tx, double ty)
{
    const uint8_t *row;
    int rows, cols, bytes_per_row;
    int x, y, bit;
    double xoff, yoff;
    cairo_fixed_t x0, y0;
    cairo_fixed_t px, py;
    cairo_status_t status;
177
    mask = _cairo_image_surface_coerce_to_format (mask, CAIRO_FORMAT_A1);
177
    status = mask->base.status;
177
    if (unlikely (status))
	return status;
177
    cairo_surface_get_device_offset (&mask->base, &xoff, &yoff);
177
    x0 = _cairo_fixed_from_double (tx - xoff);
177
    y0 = _cairo_fixed_from_double (ty - yoff);
177
    bytes_per_row = (mask->width + 7) / 8;
177
    row = mask->data;
4026
    for (y = 0, rows = mask->height; rows--; row += mask->stride, y++) {
3849
	const uint8_t *byte_ptr = row;
3849
	x = 0;
3849
	py = _cairo_fixed_from_int (y);
16473
	for (cols = bytes_per_row; cols--; ) {
12624
	    uint8_t byte = *byte_ptr++;
12624
	    if (byte == 0) {
6792
		x += 8;
6792
		continue;
	    }
5832
	    byte = CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (byte);
51435
	    for (bit = 1 << 7; bit && x < mask->width; bit >>= 1, x++) {
45603
		if (byte & bit) {
31416
		    px = _cairo_fixed_from_int (x);
31416
		    status = _add_unit_rectangle_to_path (path,
							  px + x0,
							  py + y0);
31416
		    if (unlikely (status))
			goto BAIL;
		}
	    }
	}
    }
177
BAIL:
177
    cairo_surface_destroy (&mask->base);
177
    return status;
}
cairo_status_t
216
_cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font,
			       const cairo_glyph_t *glyphs,
			       int		    num_glyphs,
			       cairo_path_fixed_t  *path)
{
    cairo_int_status_t status;
    int	i;
216
    status = scaled_font->status;
216
    if (unlikely (status))
	return status;
216
    _cairo_scaled_font_freeze_cache (scaled_font);
1572
    for (i = 0; i < num_glyphs; i++) {
	cairo_scaled_glyph_t *scaled_glyph;
1356
	status = _cairo_scaled_glyph_lookup (scaled_font,
1356
					     glyphs[i].index,
					     CAIRO_SCALED_GLYPH_INFO_PATH,
					     NULL, /* foreground color */
					     &scaled_glyph);
1356
	if (status == CAIRO_INT_STATUS_SUCCESS) {
3537
	    status = _cairo_path_fixed_append (path,
1179
					       scaled_glyph->path,
1179
					       _cairo_fixed_from_double (glyphs[i].x),
1179
					       _cairo_fixed_from_double (glyphs[i].y));
177
	} else if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
	    /* If the font is incapable of providing a path, then we'll
	     * have to trace our own from a surface.
	     */
177
	    status = _cairo_scaled_glyph_lookup (scaled_font,
177
						 glyphs[i].index,
						 CAIRO_SCALED_GLYPH_INFO_SURFACE,
						 NULL, /* foreground color */
						 &scaled_glyph);
177
	    if (unlikely (status))
		goto BAIL;
177
	    status = _trace_mask_to_path (scaled_glyph->surface, path,
177
					  glyphs[i].x, glyphs[i].y);
	}
1356
	if (unlikely (status))
	    goto BAIL;
    }
216
  BAIL:
216
    _cairo_scaled_font_thaw_cache (scaled_font);
216
    return _cairo_scaled_font_set_error (scaled_font, status);
}
/**
 * _cairo_scaled_glyph_set_metrics:
 * @scaled_glyph: a #cairo_scaled_glyph_t
 * @scaled_font: a #cairo_scaled_font_t
 * @fs_metrics: a #cairo_text_extents_t in font space
 *
 * _cairo_scaled_glyph_set_metrics() stores user space metrics
 * for the specified glyph given font space metrics. It is
 * called by the font backend when initializing a glyph with
 * %CAIRO_SCALED_GLYPH_INFO_METRICS.
 **/
void
5799
_cairo_scaled_glyph_set_metrics (cairo_scaled_glyph_t *scaled_glyph,
				 cairo_scaled_font_t *scaled_font,
				 cairo_text_extents_t *fs_metrics)
{
5799
    cairo_bool_t first = TRUE;
    double hm, wm;
5799
    double min_user_x = 0.0, max_user_x = 0.0, min_user_y = 0.0, max_user_y = 0.0;
5799
    double min_device_x = 0.0, max_device_x = 0.0, min_device_y = 0.0, max_device_y = 0.0;
    double device_x_advance, device_y_advance;
5799
    scaled_glyph->fs_metrics = *fs_metrics;
17397
    for (hm = 0.0; hm <= 1.0; hm += 1.0)
34794
	for (wm = 0.0; wm <= 1.0; wm += 1.0) {
	    double x, y;
	    /* Transform this corner to user space */
23196
	    x = fs_metrics->x_bearing + fs_metrics->width * wm;
23196
	    y = fs_metrics->y_bearing + fs_metrics->height * hm;
23196
	    cairo_matrix_transform_point (&scaled_font->font_matrix,
					  &x, &y);
23196
	    if (first) {
5799
		min_user_x = max_user_x = x;
5799
		min_user_y = max_user_y = y;
	    } else {
17397
		if (x < min_user_x) min_user_x = x;
17397
		if (x > max_user_x) max_user_x = x;
17397
		if (y < min_user_y) min_user_y = y;
17397
		if (y > max_user_y) max_user_y = y;
	    }
	    /* Transform this corner to device space from glyph origin */
23196
	    x = fs_metrics->x_bearing + fs_metrics->width * wm;
23196
	    y = fs_metrics->y_bearing + fs_metrics->height * hm;
23196
	    cairo_matrix_transform_distance (&scaled_font->scale,
					     &x, &y);
23196
	    if (first) {
5799
		min_device_x = max_device_x = x;
5799
		min_device_y = max_device_y = y;
	    } else {
17397
		if (x < min_device_x) min_device_x = x;
17397
		if (x > max_device_x) max_device_x = x;
17397
		if (y < min_device_y) min_device_y = y;
17397
		if (y > max_device_y) max_device_y = y;
	    }
23196
	    first = FALSE;
	}
5799
    scaled_glyph->metrics.x_bearing = min_user_x;
5799
    scaled_glyph->metrics.y_bearing = min_user_y;
5799
    scaled_glyph->metrics.width = max_user_x - min_user_x;
5799
    scaled_glyph->metrics.height = max_user_y - min_user_y;
5799
    scaled_glyph->metrics.x_advance = fs_metrics->x_advance;
5799
    scaled_glyph->metrics.y_advance = fs_metrics->y_advance;
5799
    cairo_matrix_transform_distance (&scaled_font->font_matrix,
				     &scaled_glyph->metrics.x_advance,
				     &scaled_glyph->metrics.y_advance);
5799
    device_x_advance = fs_metrics->x_advance;
5799
    device_y_advance = fs_metrics->y_advance;
5799
    cairo_matrix_transform_distance (&scaled_font->scale,
				     &device_x_advance,
				     &device_y_advance);
5799
    scaled_glyph->bbox.p1.x = _cairo_fixed_from_double (min_device_x);
5799
    scaled_glyph->bbox.p1.y = _cairo_fixed_from_double (min_device_y);
5799
    scaled_glyph->bbox.p2.x = _cairo_fixed_from_double (max_device_x);
5799
    scaled_glyph->bbox.p2.y = _cairo_fixed_from_double (max_device_y);
5799
    scaled_glyph->x_advance = _cairo_lround (device_x_advance);
5799
    scaled_glyph->y_advance = _cairo_lround (device_y_advance);
5799
    scaled_glyph->has_info |= CAIRO_SCALED_GLYPH_INFO_METRICS;
5799
}
void
3663
_cairo_scaled_glyph_set_surface (cairo_scaled_glyph_t *scaled_glyph,
				 cairo_scaled_font_t *scaled_font,
				 cairo_image_surface_t *surface)
{
3663
    if (scaled_glyph->surface != NULL)
	cairo_surface_destroy (&scaled_glyph->surface->base);
    /* sanity check the backend glyph contents */
    _cairo_debug_check_image_surface_is_defined (&surface->base);
3663
    scaled_glyph->surface = surface;
3663
    if (surface != NULL)
3663
	scaled_glyph->has_info |= CAIRO_SCALED_GLYPH_INFO_SURFACE;
    else
	scaled_glyph->has_info &= ~CAIRO_SCALED_GLYPH_INFO_SURFACE;
3663
}
void
621
_cairo_scaled_glyph_set_path (cairo_scaled_glyph_t *scaled_glyph,
			      cairo_scaled_font_t *scaled_font,
			      cairo_path_fixed_t *path)
{
621
    if (scaled_glyph->path != NULL)
	_cairo_path_fixed_destroy (scaled_glyph->path);
621
    scaled_glyph->path = path;
621
    if (path != NULL)
621
	scaled_glyph->has_info |= CAIRO_SCALED_GLYPH_INFO_PATH;
    else
	scaled_glyph->has_info &= ~CAIRO_SCALED_GLYPH_INFO_PATH;
621
}
/**
 * _cairo_scaled_glyph_set_recording_surface:
 * @scaled_glyph: a #cairo_scaled_glyph_t
 * @scaled_font: a #cairo_scaled_font_t
 * @recording_surface: The recording surface
 * @foreground_color: The foreground color that was used to record the
 * glyph, or NULL if foreground color not required.
 *
 * Sets the surface that was used to record the glyph.
 **/
void
1107
_cairo_scaled_glyph_set_recording_surface (cairo_scaled_glyph_t *scaled_glyph,
					   cairo_scaled_font_t  *scaled_font,
					   cairo_surface_t      *recording_surface,
					   const cairo_color_t * foreground_color)
{
1107
    if (scaled_glyph->recording_surface != NULL) {
24
	cairo_surface_finish (scaled_glyph->recording_surface);
24
	cairo_surface_destroy (scaled_glyph->recording_surface);
    }
1107
    scaled_glyph->recording_surface = recording_surface;
1107
    scaled_glyph->recording_uses_foreground_color = foreground_color != NULL;
1107
    if (foreground_color)
42
	scaled_glyph->foreground_color = *foreground_color;
1107
    if (recording_surface != NULL)
1107
	scaled_glyph->has_info |= CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE;
    else
	scaled_glyph->has_info &= ~CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE;
1107
}
/**
 * _cairo_scaled_glyph_set_color_surface:
 * @scaled_glyph: a #cairo_scaled_glyph_t
 * @scaled_font: a #cairo_scaled_font_t
 * @surface: The image surface
 * @foreground_marker_color: The foreground color that was used to
 * substitute the foreground_marker, or NULL if foreground_marker not
 * used when rendering the surface color.
 *
 * Sets the color surface of the glyph.
 **/
void
351
_cairo_scaled_glyph_set_color_surface (cairo_scaled_glyph_t  *scaled_glyph,
	                               cairo_scaled_font_t   *scaled_font,
	                               cairo_image_surface_t *surface,
				       const cairo_color_t   *foreground_marker_color)
{
351
    if (scaled_glyph->color_surface != NULL)
12
	cairo_surface_destroy (&scaled_glyph->color_surface->base);
    /* sanity check the backend glyph contents */
    _cairo_debug_check_image_surface_is_defined (&surface->base);
351
    scaled_glyph->color_surface = surface;
351
    scaled_glyph->recording_uses_foreground_marker = foreground_marker_color != NULL;
351
    if (foreground_marker_color)
33
	scaled_glyph->foreground_color = *foreground_marker_color;
351
    if (surface != NULL)
351
	scaled_glyph->has_info |= CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE;
    else
	scaled_glyph->has_info &= ~CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE;
351
}
/* _cairo_hash_table_random_entry () predicate. To avoid race conditions,
 * the font is locked when tested. The font is unlocked in
 * _cairo_scaled_glyph_page_pluck. */
static cairo_bool_t
_cairo_scaled_glyph_page_can_remove (const void *closure)
{
    const cairo_scaled_glyph_page_t *page = closure;
    cairo_scaled_font_t *scaled_font;
    scaled_font = page->scaled_font;
    if (!CAIRO_MUTEX_TRY_LOCK (scaled_font->mutex))
       return FALSE;
    if (scaled_font->cache_frozen != 0) {
       CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
       return FALSE;
    }
    return TRUE;
}
static cairo_status_t
5787
_cairo_scaled_font_allocate_glyph (cairo_scaled_font_t *scaled_font,
				   cairo_scaled_glyph_t **scaled_glyph)
{
    cairo_scaled_glyph_page_t *page;
    cairo_status_t status;
5787
    assert (scaled_font->cache_frozen);
    /* only the first page in the list may contain available slots */
5787
    if (! cairo_list_is_empty (&scaled_font->glyph_pages)) {
4815
        page = cairo_list_last_entry (&scaled_font->glyph_pages,
                                      cairo_scaled_glyph_page_t,
                                      link);
4815
        if (page->num_glyphs < CAIRO_SCALED_GLYPH_PAGE_SIZE) {
4806
            *scaled_glyph = &page->glyphs[page->num_glyphs++];
4806
            return CAIRO_STATUS_SUCCESS;
        }
    }
981
    page = _cairo_calloc (sizeof (cairo_scaled_glyph_page_t));
981
    if (unlikely (page == NULL))
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
981
    page->cache_entry.hash = (uintptr_t) scaled_font;
981
    page->scaled_font = scaled_font;
981
    page->cache_entry.size = 1; /* XXX occupancy weighting? */
981
    page->num_glyphs = 0;
981
    CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex);
981
    if (scaled_font->global_cache_frozen == FALSE) {
975
	if (unlikely (cairo_scaled_glyph_page_cache.hash_table == NULL)) {
288
	    status = _cairo_cache_init (&cairo_scaled_glyph_page_cache,
					NULL,
					_cairo_scaled_glyph_page_can_remove,
					_cairo_scaled_glyph_page_pluck,
					MAX_GLYPH_PAGES_CACHED);
288
	    if (unlikely (status)) {
		CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex);
		free (page);
		return status;
	    }
	}
975
	_cairo_cache_freeze (&cairo_scaled_glyph_page_cache);
975
	scaled_font->global_cache_frozen = TRUE;
    }
981
    status = _cairo_cache_insert (&cairo_scaled_glyph_page_cache,
				  &page->cache_entry);
981
    CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex);
981
    if (unlikely (status)) {
	free (page);
	return status;
    }
981
    cairo_list_add_tail (&page->link, &scaled_font->glyph_pages);
981
    *scaled_glyph = &page->glyphs[page->num_glyphs++];
981
    return CAIRO_STATUS_SUCCESS;
}
static void
30
_cairo_scaled_font_free_last_glyph (cairo_scaled_font_t *scaled_font,
			           cairo_scaled_glyph_t *scaled_glyph)
{
    cairo_scaled_glyph_page_t *page;
30
    assert (scaled_font->cache_frozen);
30
    assert (! cairo_list_is_empty (&scaled_font->glyph_pages));
30
    page = cairo_list_last_entry (&scaled_font->glyph_pages,
                                  cairo_scaled_glyph_page_t,
                                  link);
30
    assert (scaled_glyph == &page->glyphs[page->num_glyphs-1]);
30
    _cairo_scaled_glyph_fini (scaled_font, scaled_glyph);
30
    if (--page->num_glyphs == 0) {
	_cairo_scaled_font_thaw_cache (scaled_font);
	CAIRO_MUTEX_LOCK (scaled_font->mutex);
	CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex);
	/* Temporarily disconnect callback to avoid recursive locking */
	cairo_scaled_glyph_page_cache.entry_destroy = NULL;
	_cairo_cache_remove (&cairo_scaled_glyph_page_cache,
		             &page->cache_entry);
	_cairo_scaled_glyph_page_destroy (scaled_font, page);
	cairo_scaled_glyph_page_cache.entry_destroy = _cairo_scaled_glyph_page_pluck;
	CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex);
	CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
	_cairo_scaled_font_freeze_cache (scaled_font);
    }
30
}
/**
 * _cairo_scaled_glyph_lookup:
 * @scaled_font: a #cairo_scaled_font_t
 * @index: the glyph to create
 * @info: a #cairo_scaled_glyph_info_t marking which portions of
 * the glyph should be filled in.
 * @foreground_color - foreground color to use when rendering color
 * fonts. Use NULL if not requesting
 * CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE or
 * CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE, or foreground color is
 * unknown.
 * @scaled_glyph_ret: a #cairo_scaled_glyph_t where the glyph
 * is returned.
 *
 * If the desired info is not available, (for example, when trying to
 * get INFO_PATH with a bitmapped font), this function will return
 * %CAIRO_INT_STATUS_UNSUPPORTED.
 *
 * Note: This function must be called with the scaled font frozen, and it must
 * remain frozen for as long as the @scaled_glyph_ret is alive. (If the scaled
 * font was not frozen, then there is no guarantee that the glyph would not be
 * evicted before you tried to access it.) See
 * _cairo_scaled_font_freeze_cache() and _cairo_scaled_font_thaw_cache().
 *
 * Returns: a glyph with the requested portions filled in. Glyph
 * lookup is cached and glyph will be automatically freed along
 * with the scaled_font so no explicit free is required.
 * @info can be one or more of:
 *  %CAIRO_SCALED_GLYPH_INFO_METRICS - glyph metrics and bounding box
 *  %CAIRO_SCALED_GLYPH_INFO_SURFACE - surface holding glyph image
 *  %CAIRO_SCALED_GLYPH_INFO_PATH - path holding glyph outline in device space
 *  %CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE - surface holding recording of glyph
 *  %CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE - surface holding color glyph image
 **/
cairo_int_status_t
821772
_cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font,
			    unsigned long index,
			    cairo_scaled_glyph_info_t info,
			    const cairo_color_t   *foreground_color,
			    cairo_scaled_glyph_t **scaled_glyph_ret)
{
821772
    cairo_int_status_t		 status = CAIRO_INT_STATUS_SUCCESS;
    cairo_scaled_glyph_t	*scaled_glyph;
    cairo_scaled_glyph_info_t	 need_info;
    cairo_hash_entry_t           key;
821772
    *scaled_glyph_ret = NULL;
821772
    if (unlikely (scaled_font->status))
	return scaled_font->status;
    assert (CAIRO_MUTEX_IS_LOCKED(scaled_font->mutex));
821772
    assert (scaled_font->cache_frozen);
    if (CAIRO_INJECT_FAULT ())
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
821772
    if (foreground_color == NULL)
821235
	foreground_color = CAIRO_COLOR_BLACK;
    /*
     * Check cache for glyph
     */
821772
    key.hash = index;
821772
    scaled_glyph = _cairo_hash_table_lookup (scaled_font->glyphs, &key);
821772
    if (scaled_glyph == NULL) {
5787
	status = _cairo_scaled_font_allocate_glyph (scaled_font, &scaled_glyph);
5787
	if (unlikely (status))
	    goto err;
5787
	memset (scaled_glyph, 0, sizeof (cairo_scaled_glyph_t));
5787
	_cairo_scaled_glyph_set_index (scaled_glyph, index);
5787
	cairo_list_init (&scaled_glyph->dev_privates);
	/* ask backend to initialize metrics and shape fields */
	status =
5787
	    scaled_font->backend->scaled_glyph_init (scaled_font,
						     scaled_glyph,
5787
						     info | CAIRO_SCALED_GLYPH_INFO_METRICS,
						     foreground_color);
5787
	if (unlikely (status)) {
30
	    _cairo_scaled_font_free_last_glyph (scaled_font, scaled_glyph);
30
	    goto err;
	}
5757
	status = _cairo_hash_table_insert (scaled_font->glyphs,
5757
					   &scaled_glyph->hash_entry);
5757
	if (unlikely (status)) {
	    _cairo_scaled_font_free_last_glyph (scaled_font, scaled_glyph);
	    goto err;
	}
    }
    /*
     * Check and see if the glyph, as provided,
     * already has the requested data and amend it if not
     */
821742
    need_info = info & ~scaled_glyph->has_info;
    /* If this is not a color glyph, don't try loading the color surface again. */
821742
    if ((need_info & CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE) &&
345
	scaled_glyph->color_glyph_set && !scaled_glyph->color_glyph)
12
	return CAIRO_INT_STATUS_UNSUPPORTED;
    /* If requesting a color surface or recording for a glyph that has
     * used the foreground color to render the recording, and the
     * foreground color has changed, request a new  recording. */
821730
    if ((info & (CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE | CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE)) &&
495
	scaled_glyph->recording_uses_foreground_color &&
24
	!_cairo_color_equal (foreground_color, &scaled_glyph->foreground_color))
    {
24
	need_info |= CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE;
    }
    /* If requesting a color surface for a glyph that has
     * used the foreground color to render the color_surface, and the
     * foreground color has changed, request a new image. */
821730
    if (info & CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE &&
495
	(scaled_glyph->recording_uses_foreground_marker || scaled_glyph->recording_uses_foreground_color) &&
30
	!_cairo_color_equal (foreground_color, &scaled_glyph->foreground_color))
    {
30
	    need_info |= CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE;
    }
821730
    if (need_info) {
3813
	status = scaled_font->backend->scaled_glyph_init (scaled_font,
							  scaled_glyph,
							  need_info,
							  foreground_color);
3813
	if (unlikely (status))
177
	    goto err;
	/* Don't trust the scaled_glyph_init() return value, the font
	 * backend may not even know about some of the info.  For example,
	 * no backend other than the user-fonts knows about recording-surface
	 * glyph info. */
3636
	if (info & ~scaled_glyph->has_info)
	    return CAIRO_INT_STATUS_UNSUPPORTED;
    }
821553
    *scaled_glyph_ret = scaled_glyph;
821553
    return CAIRO_STATUS_SUCCESS;
207
err:
    /* It's not an error for the backend to not support the info we want. */
207
    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
	status = _cairo_scaled_font_set_error (scaled_font, status);
207
    return status;
}
double
69225
_cairo_scaled_font_get_max_scale (cairo_scaled_font_t *scaled_font)
{
69225
    return scaled_font->max_scale;
}
/**
 * cairo_scaled_font_get_font_face:
 * @scaled_font: a #cairo_scaled_font_t
 *
 * Gets the font face that this scaled font uses.  This might be the
 * font face passed to cairo_scaled_font_create(), but this does not
 * hold true for all possible cases.
 *
 * Return value: The #cairo_font_face_t with which @scaled_font was
 * created.  This object is owned by cairo. To keep a reference to it,
 * you must call cairo_scaled_font_reference().
 *
 * Since: 1.2
 **/
cairo_font_face_t *
616
cairo_scaled_font_get_font_face (cairo_scaled_font_t *scaled_font)
{
616
    if (scaled_font->status)
	return (cairo_font_face_t*) &_cairo_font_face_nil;
616
    if (scaled_font->original_font_face != NULL)
553
	return scaled_font->original_font_face;
63
    return scaled_font->font_face;
}
/**
 * cairo_scaled_font_get_font_matrix:
 * @scaled_font: a #cairo_scaled_font_t
 * @font_matrix: return value for the matrix
 *
 * Stores the font matrix with which @scaled_font was created into
 * @matrix.
 *
 * Since: 1.2
 **/
void
cairo_scaled_font_get_font_matrix (cairo_scaled_font_t	*scaled_font,
				   cairo_matrix_t	*font_matrix)
{
    if (scaled_font->status) {
	cairo_matrix_init_identity (font_matrix);
	return;
    }
    *font_matrix = scaled_font->font_matrix;
}
/**
 * cairo_scaled_font_get_ctm:
 * @scaled_font: a #cairo_scaled_font_t
 * @ctm: return value for the CTM
 *
 * Stores the CTM with which @scaled_font was created into @ctm.
 * Note that the translation offsets (x0, y0) of the CTM are ignored
 * by cairo_scaled_font_create().  So, the matrix this
 * function returns always has 0,0 as x0,y0.
 *
 * Since: 1.2
 **/
void
cairo_scaled_font_get_ctm (cairo_scaled_font_t	*scaled_font,
			   cairo_matrix_t	*ctm)
{
    if (scaled_font->status) {
	cairo_matrix_init_identity (ctm);
	return;
    }
    *ctm = scaled_font->ctm;
}
/**
 * cairo_scaled_font_get_scale_matrix:
 * @scaled_font: a #cairo_scaled_font_t
 * @scale_matrix: return value for the matrix
 *
 * Stores the scale matrix of @scaled_font into @matrix.
 * The scale matrix is product of the font matrix and the ctm
 * associated with the scaled font, and hence is the matrix mapping from
 * font space to device space.
 *
 * Since: 1.8
 **/
void
cairo_scaled_font_get_scale_matrix (cairo_scaled_font_t	*scaled_font,
				    cairo_matrix_t	*scale_matrix)
{
    if (scaled_font->status) {
	cairo_matrix_init_identity (scale_matrix);
	return;
    }
    *scale_matrix = scaled_font->scale;
}
/**
 * cairo_scaled_font_get_font_options:
 * @scaled_font: a #cairo_scaled_font_t
 * @options: return value for the font options
 *
 * Stores the font options with which @scaled_font was created into
 * @options.
 *
 * Since: 1.2
 **/
void
1
cairo_scaled_font_get_font_options (cairo_scaled_font_t		*scaled_font,
				    cairo_font_options_t	*options)
{
1
    if (cairo_font_options_status (options))
1
	return;
    if (scaled_font->status) {
	_cairo_font_options_init_default (options);
	return;
    }
    _cairo_font_options_fini (options);
    _cairo_font_options_init_copy (options, &scaled_font->options);
}
cairo_bool_t
141180
_cairo_scaled_font_has_color_glyphs (cairo_scaled_font_t *scaled_font)
{
141180
    if (scaled_font->backend != NULL && scaled_font->backend->has_color_glyphs != NULL)
141180
        return scaled_font->backend->has_color_glyphs (scaled_font);
    else
       return FALSE;
}