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-error-private.h"
43 #include "cairo-scaled-font-private.h"
44 
45 #if _XOPEN_SOURCE >= 600 || defined (_ISOC99_SOURCE)
46 #define ISFINITE(x) isfinite (x)
47 #else
48 #define ISFINITE(x) ((x) * (x) >= 0.) /* check for NaNs */
49 #endif
50 
51 /**
52  * SECTION:cairo-scaled-font
53  * @Title: cairo_scaled_font_t
54  * @Short_Description: Font face at particular size and options
55  * @See_Also: #cairo_font_face_t, #cairo_matrix_t, #cairo_font_options_t
56  *
57  * #cairo_scaled_font_t represents a realization of a font face at a particular
58  * size and transformation and a certain set of font options.
59  */
60 
61 /* Global Glyph Cache
62  *
63  * We maintain a global pool of glyphs split between all active fonts. This
64  * allows a heavily used individual font to cache more glyphs than we could
65  * manage if we used per-font glyph caches, but at the same time maintains
66  * fairness across all fonts and provides a cap on the maximum number of
67  * global glyphs.
68  *
69  * The glyphs are allocated in pages, which are capped in the global pool.
70  * Using pages means we can reduce the frequency at which we have to probe the
71  * global pool and ameliorates the memory allocation pressure.
72  */
73 
74 /* XXX: This number is arbitrary---we've never done any measurement of this. */
75 #define MAX_GLYPH_PAGES_CACHED 256
76 static cairo_cache_t cairo_scaled_glyph_page_cache;
77 
78 #define CAIRO_SCALED_GLYPH_PAGE_SIZE 32
79 struct _cairo_scaled_glyph_page {
80     cairo_cache_entry_t cache_entry;
81 
82     cairo_list_t link;
83 
84     unsigned int num_glyphs;
85     cairo_scaled_glyph_t glyphs[CAIRO_SCALED_GLYPH_PAGE_SIZE];
86 };
87 
88 /*
89  *  Notes:
90  *
91  *  To store rasterizations of glyphs, we use an image surface and the
92  *  device offset to represent the glyph origin.
93  *
94  *  A device_transform converts from device space (a conceptual space) to
95  *  surface space.  For simple cases of translation only, it's called a
96  *  device_offset and is public API (cairo_surface_[gs]et_device_offset()).
97  *  A possibly better name for those functions could have been
98  *  cairo_surface_[gs]et_origin().  So, that's what they do: they set where
99  *  the device-space origin (0,0) is in the surface.  If the origin is inside
100  *  the surface, device_offset values are positive.  It may look like this:
101  *
102  *  Device space:
103  *        (-x,-y) <-- negative numbers
104  *           +----------------+
105  *           |      .         |
106  *           |      .         |
107  *           |......(0,0) <---|-- device-space origin
108  *           |                |
109  *           |                |
110  *           +----------------+
111  *                    (width-x,height-y)
112  *
113  *  Surface space:
114  *         (0,0) <-- surface-space origin
115  *           +---------------+
116  *           |      .        |
117  *           |      .        |
118  *           |......(x,y) <--|-- device_offset
119  *           |               |
120  *           |               |
121  *           +---------------+
122  *                     (width,height)
123  *
124  *  In other words: device_offset is the coordinates of the device-space
125  *  origin relative to the top-left of the surface.
126  *
127  *  We use device offsets in a couple of places:
128  *
129  *    - Public API: To let toolkits like Gtk+ give user a surface that
130  *      only represents part of the final destination (say, the expose
131  *      area), but has the same device space as the destination.  In these
132  *      cases device_offset is typically negative.  Example:
133  *
134  *           application window
135  *           +---------------+
136  *           |      .        |
137  *           | (x,y).        |
138  *           |......+---+    |
139  *           |      |   | <--|-- expose area
140  *           |      +---+    |
141  *           +---------------+
142  *
143  *      In this case, the user of cairo API can set the device_space on
144  *      the expose area to (-x,-y) to move the device space origin to that
145  *      of the application window, such that drawing in the expose area
146  *      surface and painting it in the application window has the same
147  *      effect as drawing in the application window directly.  Gtk+ has
148  *      been using this feature.
149  *
150  *    - Glyph surfaces: In most font rendering systems, glyph surfaces
151  *      have an origin at (0,0) and a bounding box that is typically
152  *      represented as (x_bearing,y_bearing,width,height).  Depending on
153  *      which way y progresses in the system, y_bearing may typically be
154  *      negative (for systems similar to cairo, with origin at top left),
155  *      or be positive (in systems like PDF with origin at bottom left).
156  *      No matter which is the case, it is important to note that
157  *      (x_bearing,y_bearing) is the coordinates of top-left of the glyph
158  *      relative to the glyph origin.  That is, for example:
159  *
160  *      Scaled-glyph space:
161  *
162  *        (x_bearing,y_bearing) <-- negative numbers
163  *           +----------------+
164  *           |      .         |
165  *           |      .         |
166  *           |......(0,0) <---|-- glyph origin
167  *           |                |
168  *           |                |
169  *           +----------------+
170  *                    (width+x_bearing,height+y_bearing)
171  *
172  *      Note the similarity of the origin to the device space.  That is
173  *      exactly how we use the device_offset to represent scaled glyphs:
174  *      to use the device-space origin as the glyph origin.
175  *
176  *  Now compare the scaled-glyph space to device-space and surface-space
177  *  and convince yourself that:
178  *
179  *	(x_bearing,y_bearing) = (-x,-y) = - device_offset
180  *
181  *  That's right.  If you are not convinced yet, contrast the definition
182  *  of the two:
183  *
184  *	"(x_bearing,y_bearing) is the coordinates of top-left of the
185  *	 glyph relative to the glyph origin."
186  *
187  *	"In other words: device_offset is the coordinates of the
188  *	 device-space origin relative to the top-left of the surface."
189  *
190  *  and note that glyph origin = device-space origin.
191  */
192 
193 static void
194 _cairo_scaled_font_fini_internal (cairo_scaled_font_t *scaled_font);
195 
196 static void
_cairo_scaled_glyph_fini(cairo_scaled_font_t * scaled_font,cairo_scaled_glyph_t * scaled_glyph)197 _cairo_scaled_glyph_fini (cairo_scaled_font_t *scaled_font,
198 			  cairo_scaled_glyph_t *scaled_glyph)
199 {
200     const cairo_surface_backend_t *surface_backend = scaled_font->surface_backend;
201 
202     if (surface_backend != NULL && surface_backend->scaled_glyph_fini != NULL)
203 	surface_backend->scaled_glyph_fini (scaled_glyph, scaled_font);
204 
205     if (scaled_glyph->surface != NULL)
206 	cairo_surface_destroy (&scaled_glyph->surface->base);
207 
208     if (scaled_glyph->path != NULL)
209 	_cairo_path_fixed_destroy (scaled_glyph->path);
210 
211     if (scaled_glyph->recording_surface != NULL) {
212 	cairo_surface_finish (scaled_glyph->recording_surface);
213 	cairo_surface_destroy (scaled_glyph->recording_surface);
214     }
215 }
216 
217 #define ZOMBIE 0
218 static const cairo_scaled_font_t _cairo_scaled_font_nil = {
219     { ZOMBIE },			/* hash_entry */
220     CAIRO_STATUS_NO_MEMORY,	/* status */
221     CAIRO_REFERENCE_COUNT_INVALID,	/* ref_count */
222     { 0, 0, 0, NULL },		/* user_data */
223     NULL,			/* original_font_face */
224     NULL,			/* font_face */
225     { 1., 0., 0., 1., 0, 0},	/* font_matrix */
226     { 1., 0., 0., 1., 0, 0},	/* ctm */
227     { CAIRO_ANTIALIAS_DEFAULT,	/* options */
228       CAIRO_SUBPIXEL_ORDER_DEFAULT,
229       CAIRO_HINT_STYLE_DEFAULT,
230       CAIRO_HINT_METRICS_DEFAULT} ,
231     FALSE,			/* placeholder */
232     FALSE,			/* holdover */
233     TRUE,			/* finished */
234     { 1., 0., 0., 1., 0, 0},	/* scale */
235     { 1., 0., 0., 1., 0, 0},	/* scale_inverse */
236     1.,				/* max_scale */
237     { 0., 0., 0., 0., 0. },	/* extents */
238     { 0., 0., 0., 0., 0. },	/* fs_extents */
239     CAIRO_MUTEX_NIL_INITIALIZER,/* mutex */
240     NULL,			/* glyphs */
241     { NULL, NULL },		/* pages */
242     FALSE,			/* cache_frozen */
243     FALSE,			/* global_cache_frozen */
244     NULL,			/* surface_backend */
245     NULL,			/* surface_private */
246     NULL			/* backend */
247 };
248 
249 /**
250  * _cairo_scaled_font_set_error:
251  * @scaled_font: a scaled_font
252  * @status: a status value indicating an error
253  *
254  * Atomically sets scaled_font->status to @status and calls _cairo_error;
255  * Does nothing if status is %CAIRO_STATUS_SUCCESS.
256  *
257  * All assignments of an error status to scaled_font->status should happen
258  * through _cairo_scaled_font_set_error(). Note that due to the nature of
259  * the atomic operation, it is not safe to call this function on the nil
260  * objects.
261  *
262  * The purpose of this function is to allow the user to set a
263  * breakpoint in _cairo_error() to generate a stack trace for when the
264  * user causes cairo to detect an error.
265  *
266  * Return value: the error status.
267  **/
268 cairo_status_t
_cairo_scaled_font_set_error(cairo_scaled_font_t * scaled_font,cairo_status_t status)269 _cairo_scaled_font_set_error (cairo_scaled_font_t *scaled_font,
270 			      cairo_status_t status)
271 {
272     if (status == CAIRO_STATUS_SUCCESS)
273 	return status;
274 
275     /* Don't overwrite an existing error. This preserves the first
276      * error, which is the most significant. */
277     _cairo_status_set_error (&scaled_font->status, status);
278 
279     return _cairo_error (status);
280 }
281 
282 /**
283  * cairo_scaled_font_get_type:
284  * @scaled_font: a #cairo_scaled_font_t
285  *
286  * This function returns the type of the backend used to create
287  * a scaled font. See #cairo_font_type_t for available types.
288  * However, this function never returns %CAIRO_FONT_TYPE_TOY.
289  *
290  * Return value: The type of @scaled_font.
291  *
292  * Since: 1.2
293  **/
294 cairo_font_type_t
cairo_scaled_font_get_type(cairo_scaled_font_t * scaled_font)295 cairo_scaled_font_get_type (cairo_scaled_font_t *scaled_font)
296 {
297     if (CAIRO_REFERENCE_COUNT_IS_INVALID (&scaled_font->ref_count))
298 	return CAIRO_FONT_TYPE_TOY;
299 
300     return scaled_font->backend->type;
301 }
302 
303 /**
304  * cairo_scaled_font_status:
305  * @scaled_font: a #cairo_scaled_font_t
306  *
307  * Checks whether an error has previously occurred for this
308  * scaled_font.
309  *
310  * Return value: %CAIRO_STATUS_SUCCESS or another error such as
311  *   %CAIRO_STATUS_NO_MEMORY.
312  **/
313 cairo_status_t
cairo_scaled_font_status(cairo_scaled_font_t * scaled_font)314 cairo_scaled_font_status (cairo_scaled_font_t *scaled_font)
315 {
316     return scaled_font->status;
317 }
318 slim_hidden_def (cairo_scaled_font_status);
319 
320 /* Here we keep a unique mapping from
321  * font_face/matrix/ctm/font_options => #cairo_scaled_font_t.
322  *
323  * Here are the things that we want to map:
324  *
325  *  a) All otherwise referenced #cairo_scaled_font_t's
326  *  b) Some number of not otherwise referenced #cairo_scaled_font_t's
327  *
328  * The implementation uses a hash table which covers (a)
329  * completely. Then, for (b) we have an array of otherwise
330  * unreferenced fonts (holdovers) which are expired in
331  * least-recently-used order.
332  *
333  * The cairo_scaled_font_create() code gets to treat this like a regular
334  * hash table. All of the magic for the little holdover cache is in
335  * cairo_scaled_font_reference() and cairo_scaled_font_destroy().
336  */
337 
338 /* This defines the size of the holdover array ... that is, the number
339  * of scaled fonts we keep around even when not otherwise referenced
340  */
341 #define CAIRO_SCALED_FONT_MAX_HOLDOVERS 256
342 
343 typedef struct _cairo_scaled_font_map {
344     cairo_scaled_font_t *mru_scaled_font;
345     cairo_hash_table_t *hash_table;
346     cairo_scaled_font_t *holdovers[CAIRO_SCALED_FONT_MAX_HOLDOVERS];
347     int num_holdovers;
348 } cairo_scaled_font_map_t;
349 
350 static cairo_scaled_font_map_t *cairo_scaled_font_map;
351 
352 static int
353 _cairo_scaled_font_keys_equal (const void *abstract_key_a, const void *abstract_key_b);
354 
355 static cairo_scaled_font_map_t *
_cairo_scaled_font_map_lock(void)356 _cairo_scaled_font_map_lock (void)
357 {
358     CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
359 
360     if (cairo_scaled_font_map == NULL) {
361 	cairo_scaled_font_map = malloc (sizeof (cairo_scaled_font_map_t));
362 	if (unlikely (cairo_scaled_font_map == NULL))
363 	    goto CLEANUP_MUTEX_LOCK;
364 
365 	cairo_scaled_font_map->mru_scaled_font = NULL;
366 	cairo_scaled_font_map->hash_table =
367 	    _cairo_hash_table_create (_cairo_scaled_font_keys_equal);
368 
369 	if (unlikely (cairo_scaled_font_map->hash_table == NULL))
370 	    goto CLEANUP_SCALED_FONT_MAP;
371 
372 	cairo_scaled_font_map->num_holdovers = 0;
373     }
374 
375     return cairo_scaled_font_map;
376 
377  CLEANUP_SCALED_FONT_MAP:
378     free (cairo_scaled_font_map);
379     cairo_scaled_font_map = NULL;
380  CLEANUP_MUTEX_LOCK:
381     CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
382     _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
383     return NULL;
384 }
385 
386 static void
_cairo_scaled_font_map_unlock(void)387 _cairo_scaled_font_map_unlock (void)
388 {
389    CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
390 }
391 
392 void
_cairo_scaled_font_map_destroy(void)393 _cairo_scaled_font_map_destroy (void)
394 {
395     cairo_scaled_font_map_t *font_map;
396     cairo_scaled_font_t *scaled_font;
397 
398     CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
399 
400     font_map = cairo_scaled_font_map;
401     if (unlikely (font_map == NULL)) {
402         goto CLEANUP_MUTEX_LOCK;
403     }
404 
405     scaled_font = font_map->mru_scaled_font;
406     if (scaled_font != NULL) {
407 	CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
408 	cairo_scaled_font_destroy (scaled_font);
409 	CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
410     }
411 
412     /* remove scaled_fonts starting from the end so that font_map->holdovers
413      * is always in a consistent state when we release the mutex. */
414     while (font_map->num_holdovers) {
415 	scaled_font = font_map->holdovers[font_map->num_holdovers-1];
416 	assert (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count));
417 	_cairo_hash_table_remove (font_map->hash_table,
418 				  &scaled_font->hash_entry);
419 
420 	font_map->num_holdovers--;
421 
422 	/* This releases the font_map lock to avoid the possibility of a
423 	 * recursive deadlock when the scaled font destroy closure gets
424 	 * called
425 	 */
426 	_cairo_scaled_font_fini (scaled_font);
427 
428 	free (scaled_font);
429     }
430 
431     _cairo_hash_table_destroy (font_map->hash_table);
432 
433     free (cairo_scaled_font_map);
434     cairo_scaled_font_map = NULL;
435 
436  CLEANUP_MUTEX_LOCK:
437     CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
438 }
439 static void
_cairo_scaled_glyph_page_destroy(void * closure)440 _cairo_scaled_glyph_page_destroy (void *closure)
441 {
442     cairo_scaled_glyph_page_t *page = closure;
443     cairo_scaled_font_t *scaled_font;
444     unsigned int n;
445 
446     scaled_font = (cairo_scaled_font_t *) page->cache_entry.hash;
447     for (n = 0; n < page->num_glyphs; n++) {
448 	_cairo_hash_table_remove (scaled_font->glyphs,
449 				  &page->glyphs[n].hash_entry);
450 	_cairo_scaled_glyph_fini (scaled_font, &page->glyphs[n]);
451     }
452 
453     cairo_list_del (&page->link);
454 
455     free (page);
456 }
457 
458 /* If a scaled font wants to unlock the font map while still being
459  * created (needed for user-fonts), we need to take extra care not
460  * ending up with multiple identical scaled fonts being created.
461  *
462  * What we do is, we create a fake identical scaled font, and mark
463  * it as placeholder, lock its mutex, and insert that in the fontmap
464  * hash table.  This makes other code trying to create an identical
465  * scaled font to just wait and retry.
466  *
467  * The reason we have to create a fake scaled font instead of just using
468  * scaled_font is for lifecycle management: we need to (or rather,
469  * other code needs to) reference the scaled_font in the hash table.
470  * We can't do that on the input scaled_font as it may be freed by
471  * font backend upon error.
472  */
473 
474 cairo_status_t
_cairo_scaled_font_register_placeholder_and_unlock_font_map(cairo_scaled_font_t * scaled_font)475 _cairo_scaled_font_register_placeholder_and_unlock_font_map (cairo_scaled_font_t *scaled_font)
476 {
477     cairo_status_t status;
478     cairo_scaled_font_t *placeholder_scaled_font;
479 
480     assert (CAIRO_MUTEX_IS_LOCKED (_cairo_scaled_font_map_mutex));
481 
482     status = scaled_font->status;
483     if (unlikely (status))
484 	return status;
485 
486     placeholder_scaled_font = malloc (sizeof (cairo_scaled_font_t));
487     if (unlikely (placeholder_scaled_font == NULL))
488 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
489 
490     /* full initialization is wasteful, but who cares... */
491     status = _cairo_scaled_font_init (placeholder_scaled_font,
492 				      scaled_font->font_face,
493 				      &scaled_font->font_matrix,
494 				      &scaled_font->ctm,
495 				      &scaled_font->options,
496 				      NULL);
497     if (unlikely (status))
498 	goto FREE_PLACEHOLDER;
499 
500     placeholder_scaled_font->placeholder = TRUE;
501 
502     status = _cairo_hash_table_insert (cairo_scaled_font_map->hash_table,
503 				       &placeholder_scaled_font->hash_entry);
504     if (unlikely (status))
505 	goto FINI_PLACEHOLDER;
506 
507     CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
508     CAIRO_MUTEX_LOCK (placeholder_scaled_font->mutex);
509 
510     return CAIRO_STATUS_SUCCESS;
511 
512   FINI_PLACEHOLDER:
513     _cairo_scaled_font_fini_internal (placeholder_scaled_font);
514   FREE_PLACEHOLDER:
515     free (placeholder_scaled_font);
516 
517     return _cairo_scaled_font_set_error (scaled_font, status);
518 }
519 
520 void
_cairo_scaled_font_unregister_placeholder_and_lock_font_map(cairo_scaled_font_t * scaled_font)521 _cairo_scaled_font_unregister_placeholder_and_lock_font_map (cairo_scaled_font_t *scaled_font)
522 {
523     cairo_scaled_font_t *placeholder_scaled_font;
524 
525     CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
526 
527     placeholder_scaled_font =
528 	_cairo_hash_table_lookup (cairo_scaled_font_map->hash_table,
529 				  &scaled_font->hash_entry);
530     assert (placeholder_scaled_font != NULL);
531     assert (placeholder_scaled_font->placeholder);
532     assert (CAIRO_MUTEX_IS_LOCKED (placeholder_scaled_font->mutex));
533 
534     _cairo_hash_table_remove (cairo_scaled_font_map->hash_table,
535 			      &placeholder_scaled_font->hash_entry);
536 
537     CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
538 
539     CAIRO_MUTEX_UNLOCK (placeholder_scaled_font->mutex);
540     cairo_scaled_font_destroy (placeholder_scaled_font);
541 
542     CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
543 }
544 
545 static void
_cairo_scaled_font_placeholder_wait_for_creation_to_finish(cairo_scaled_font_t * placeholder_scaled_font)546 _cairo_scaled_font_placeholder_wait_for_creation_to_finish (cairo_scaled_font_t *placeholder_scaled_font)
547 {
548     /* reference the place holder so it doesn't go away */
549     cairo_scaled_font_reference (placeholder_scaled_font);
550 
551     /* now unlock the fontmap mutex so creation has a chance to finish */
552     CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
553 
554     /* wait on placeholder mutex until we are awaken */
555     CAIRO_MUTEX_LOCK (placeholder_scaled_font->mutex);
556 
557     /* ok, creation done.  just clean up and back out */
558     CAIRO_MUTEX_UNLOCK (placeholder_scaled_font->mutex);
559     cairo_scaled_font_destroy (placeholder_scaled_font);
560 
561     CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
562 }
563 
564 /* Fowler / Noll / Vo (FNV) Hash (http://www.isthe.com/chongo/tech/comp/fnv/)
565  *
566  * Not necessarily better than a lot of other hashes, but should be OK, and
567  * well tested with binary data.
568  */
569 
570 #define FNV_32_PRIME ((uint32_t)0x01000193)
571 #define FNV1_32_INIT ((uint32_t)0x811c9dc5)
572 
573 static uint32_t
_hash_matrix_fnv(const cairo_matrix_t * matrix,uint32_t hval)574 _hash_matrix_fnv (const cairo_matrix_t	*matrix,
575 		  uint32_t		 hval)
576 {
577     const uint8_t *buffer = (const uint8_t *) matrix;
578     int len = sizeof (cairo_matrix_t);
579     do {
580 	hval *= FNV_32_PRIME;
581 	hval ^= *buffer++;
582     } while (--len);
583 
584     return hval;
585 }
586 
587 static uint32_t
_hash_mix_bits(uint32_t hash)588 _hash_mix_bits (uint32_t hash)
589 {
590     hash += hash << 12;
591     hash ^= hash >> 7;
592     hash += hash << 3;
593     hash ^= hash >> 17;
594     hash += hash << 5;
595     return hash;
596 }
597 
598 static void
_cairo_scaled_font_init_key(cairo_scaled_font_t * scaled_font,cairo_font_face_t * font_face,const cairo_matrix_t * font_matrix,const cairo_matrix_t * ctm,const cairo_font_options_t * options)599 _cairo_scaled_font_init_key (cairo_scaled_font_t        *scaled_font,
600 			     cairo_font_face_t	        *font_face,
601 			     const cairo_matrix_t       *font_matrix,
602 			     const cairo_matrix_t       *ctm,
603 			     const cairo_font_options_t *options)
604 {
605     uint32_t hash = FNV1_32_INIT;
606 
607     scaled_font->status = CAIRO_STATUS_SUCCESS;
608     scaled_font->placeholder = FALSE;
609     scaled_font->font_face = font_face;
610     scaled_font->font_matrix = *font_matrix;
611     scaled_font->ctm = *ctm;
612     /* ignore translation values in the ctm */
613     scaled_font->ctm.x0 = 0.;
614     scaled_font->ctm.y0 = 0.;
615     _cairo_font_options_init_copy (&scaled_font->options, options);
616 
617     /* We do a bytewise hash on the font matrices */
618     hash = _hash_matrix_fnv (&scaled_font->font_matrix, hash);
619     hash = _hash_matrix_fnv (&scaled_font->ctm, hash);
620     hash = _hash_mix_bits (hash);
621 
622     hash ^= (uintptr_t) scaled_font->font_face;
623     hash ^= cairo_font_options_hash (&scaled_font->options);
624 
625     /* final mixing of bits */
626     hash = _hash_mix_bits (hash);
627 
628     assert (hash != ZOMBIE);
629     scaled_font->hash_entry.hash = hash;
630 }
631 
632 static cairo_bool_t
_cairo_scaled_font_keys_equal(const void * abstract_key_a,const void * abstract_key_b)633 _cairo_scaled_font_keys_equal (const void *abstract_key_a,
634 			       const void *abstract_key_b)
635 {
636     const cairo_scaled_font_t *key_a = abstract_key_a;
637     const cairo_scaled_font_t *key_b = abstract_key_b;
638 
639     if (key_a->hash_entry.hash != key_b->hash_entry.hash)
640 	return FALSE;
641 
642     return key_a->font_face == key_b->font_face &&
643 	    memcmp ((unsigned char *)(&key_a->font_matrix.xx),
644 		    (unsigned char *)(&key_b->font_matrix.xx),
645 		    sizeof(cairo_matrix_t)) == 0 &&
646 	    memcmp ((unsigned char *)(&key_a->ctm.xx),
647 		    (unsigned char *)(&key_b->ctm.xx),
648 		    sizeof(cairo_matrix_t)) == 0 &&
649 	    cairo_font_options_equal (&key_a->options, &key_b->options);
650 }
651 
652 static cairo_bool_t
_cairo_scaled_font_matches(const cairo_scaled_font_t * scaled_font,const cairo_font_face_t * font_face,const cairo_matrix_t * font_matrix,const cairo_matrix_t * ctm,const cairo_font_options_t * options)653 _cairo_scaled_font_matches (const cairo_scaled_font_t *scaled_font,
654 	                    const cairo_font_face_t *font_face,
655 			    const cairo_matrix_t *font_matrix,
656 			    const cairo_matrix_t *ctm,
657 			    const cairo_font_options_t *options)
658 {
659     return scaled_font->original_font_face == font_face &&
660 	    memcmp ((unsigned char *)(&scaled_font->font_matrix.xx),
661 		    (unsigned char *)(&font_matrix->xx),
662 		    sizeof(cairo_matrix_t)) == 0 &&
663 	    memcmp ((unsigned char *)(&scaled_font->ctm.xx),
664 		    (unsigned char *)(&ctm->xx),
665 		    sizeof(cairo_matrix_t)) == 0 &&
666 	    cairo_font_options_equal (&scaled_font->options, options);
667 }
668 
669 static cairo_bool_t
_cairo_scaled_glyphs_equal(const void * abstract_a,const void * abstract_b)670 _cairo_scaled_glyphs_equal (const void *abstract_a, const void *abstract_b)
671 {
672     const cairo_scaled_glyph_t *a = abstract_a;
673     const cairo_scaled_glyph_t *b = abstract_b;
674 
675     return a->hash_entry.hash == b->hash_entry.hash;
676 }
677 
678 /*
679  * Basic #cairo_scaled_font_t object management
680  */
681 
682 cairo_status_t
_cairo_scaled_font_init(cairo_scaled_font_t * scaled_font,cairo_font_face_t * font_face,const cairo_matrix_t * font_matrix,const cairo_matrix_t * ctm,const cairo_font_options_t * options,const cairo_scaled_font_backend_t * backend)683 _cairo_scaled_font_init (cairo_scaled_font_t               *scaled_font,
684 			 cairo_font_face_t		   *font_face,
685 			 const cairo_matrix_t              *font_matrix,
686 			 const cairo_matrix_t              *ctm,
687 			 const cairo_font_options_t	   *options,
688 			 const cairo_scaled_font_backend_t *backend)
689 {
690     cairo_status_t status;
691 
692     status = cairo_font_options_status ((cairo_font_options_t *) options);
693     if (unlikely (status))
694 	return status;
695 
696     _cairo_scaled_font_init_key (scaled_font, font_face,
697 				 font_matrix, ctm, options);
698 
699     cairo_matrix_multiply (&scaled_font->scale,
700 			   &scaled_font->font_matrix,
701 			   &scaled_font->ctm);
702 
703     scaled_font->max_scale = MAX (fabs (scaled_font->scale.xx) + fabs (scaled_font->scale.xy),
704 				  fabs (scaled_font->scale.yx) + fabs (scaled_font->scale.yy));
705     scaled_font->scale_inverse = scaled_font->scale;
706     status = cairo_matrix_invert (&scaled_font->scale_inverse);
707     if (unlikely (status)) {
708 	/* If the font scale matrix is rank 0, just using an all-zero inverse matrix
709 	 * makes everything work correctly.  This make font size 0 work without
710 	 * producing an error.
711 	 *
712 	 * FIXME:  If the scale is rank 1, we still go into error mode.  But then
713 	 * again, that's what we do everywhere in cairo.
714 	 *
715 	 * Also, the check for == 0. below may be too harsh...
716 	 */
717         if (_cairo_matrix_is_scale_0 (&scaled_font->scale)) {
718 	    cairo_matrix_init (&scaled_font->scale_inverse,
719 			       0, 0, 0, 0,
720 			       -scaled_font->scale.x0,
721 			       -scaled_font->scale.y0);
722 	} else
723 	    return status;
724     }
725 
726     scaled_font->glyphs = _cairo_hash_table_create (_cairo_scaled_glyphs_equal);
727     if (unlikely (scaled_font->glyphs == NULL))
728 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
729 
730     cairo_list_init (&scaled_font->glyph_pages);
731     scaled_font->cache_frozen = FALSE;
732     scaled_font->global_cache_frozen = FALSE;
733 
734     scaled_font->holdover = FALSE;
735     scaled_font->finished = FALSE;
736 
737     CAIRO_REFERENCE_COUNT_INIT (&scaled_font->ref_count, 1);
738 
739     _cairo_user_data_array_init (&scaled_font->user_data);
740 
741     cairo_font_face_reference (font_face);
742     scaled_font->original_font_face = NULL;
743 
744     CAIRO_MUTEX_INIT (scaled_font->mutex);
745 
746     scaled_font->surface_backend = NULL;
747     scaled_font->surface_private = NULL;
748 
749     scaled_font->backend = backend;
750     cairo_list_init (&scaled_font->link);
751 
752     return CAIRO_STATUS_SUCCESS;
753 }
754 
755 void
_cairo_scaled_font_freeze_cache(cairo_scaled_font_t * scaled_font)756 _cairo_scaled_font_freeze_cache (cairo_scaled_font_t *scaled_font)
757 {
758     /* ensure we do not modify an error object */
759     assert (scaled_font->status == CAIRO_STATUS_SUCCESS);
760 
761     CAIRO_MUTEX_LOCK (scaled_font->mutex);
762     scaled_font->cache_frozen = TRUE;
763 }
764 
765 void
_cairo_scaled_font_thaw_cache(cairo_scaled_font_t * scaled_font)766 _cairo_scaled_font_thaw_cache (cairo_scaled_font_t *scaled_font)
767 {
768     scaled_font->cache_frozen = FALSE;
769 
770     if (scaled_font->global_cache_frozen) {
771 	CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex);
772 	_cairo_cache_thaw (&cairo_scaled_glyph_page_cache);
773 	CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex);
774 
775 	scaled_font->global_cache_frozen = FALSE;
776     }
777 
778     CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
779 }
780 
781 void
_cairo_scaled_font_reset_cache(cairo_scaled_font_t * scaled_font)782 _cairo_scaled_font_reset_cache (cairo_scaled_font_t *scaled_font)
783 {
784     assert (! scaled_font->cache_frozen);
785 
786     CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex);
787     while (! cairo_list_is_empty (&scaled_font->glyph_pages)) {
788 	_cairo_cache_remove (&cairo_scaled_glyph_page_cache,
789                              &cairo_list_first_entry (&scaled_font->glyph_pages,
790                                                       cairo_scaled_glyph_page_t,
791                                                       link)->cache_entry);
792     }
793     CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex);
794 }
795 
796 cairo_status_t
_cairo_scaled_font_set_metrics(cairo_scaled_font_t * scaled_font,cairo_font_extents_t * fs_metrics)797 _cairo_scaled_font_set_metrics (cairo_scaled_font_t	    *scaled_font,
798 				cairo_font_extents_t	    *fs_metrics)
799 {
800     cairo_status_t status;
801     double  font_scale_x, font_scale_y;
802 
803     scaled_font->fs_extents = *fs_metrics;
804 
805     status = _cairo_matrix_compute_basis_scale_factors (&scaled_font->font_matrix,
806 						  &font_scale_x, &font_scale_y,
807 						  1);
808     if (unlikely (status))
809 	return status;
810 
811     /*
812      * The font responded in unscaled units, scale by the font
813      * matrix scale factors to get to user space
814      */
815 
816     scaled_font->extents.ascent = fs_metrics->ascent * font_scale_y;
817     scaled_font->extents.descent = fs_metrics->descent * font_scale_y;
818     scaled_font->extents.height = fs_metrics->height * font_scale_y;
819     scaled_font->extents.max_x_advance = fs_metrics->max_x_advance * font_scale_x;
820     scaled_font->extents.max_y_advance = fs_metrics->max_y_advance * font_scale_y;
821 
822     return CAIRO_STATUS_SUCCESS;
823 }
824 
825 static void
_cairo_scaled_font_fini_internal(cairo_scaled_font_t * scaled_font)826 _cairo_scaled_font_fini_internal (cairo_scaled_font_t *scaled_font)
827 {
828     scaled_font->finished = TRUE;
829 
830     _cairo_scaled_font_reset_cache (scaled_font);
831     _cairo_hash_table_destroy (scaled_font->glyphs);
832 
833     cairo_font_face_destroy (scaled_font->font_face);
834     cairo_font_face_destroy (scaled_font->original_font_face);
835 
836     CAIRO_MUTEX_FINI (scaled_font->mutex);
837 
838     if (scaled_font->surface_backend != NULL &&
839 	scaled_font->surface_backend->scaled_font_fini != NULL)
840 	scaled_font->surface_backend->scaled_font_fini (scaled_font);
841 
842     if (scaled_font->backend != NULL && scaled_font->backend->fini != NULL)
843 	scaled_font->backend->fini (scaled_font);
844 
845     _cairo_user_data_array_fini (&scaled_font->user_data);
846 }
847 
848 /* XXX: allow multiple backends to share the font */
849 void
_cairo_scaled_font_revoke_ownership(cairo_scaled_font_t * scaled_font)850 _cairo_scaled_font_revoke_ownership (cairo_scaled_font_t *scaled_font)
851 {
852     if (scaled_font->surface_backend == NULL)
853 	return;
854 
855     _cairo_scaled_font_reset_cache (scaled_font);
856 
857     if (scaled_font->surface_backend->scaled_font_fini != NULL)
858 	scaled_font->surface_backend->scaled_font_fini (scaled_font);
859 
860     scaled_font->surface_backend = NULL;
861     scaled_font->surface_private = NULL;
862 }
863 
864 void
_cairo_scaled_font_fini(cairo_scaled_font_t * scaled_font)865 _cairo_scaled_font_fini (cairo_scaled_font_t *scaled_font)
866 {
867     /* Release the lock to avoid the possibility of a recursive
868      * deadlock when the scaled font destroy closure gets called. */
869     CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
870     _cairo_scaled_font_fini_internal (scaled_font);
871     CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
872 }
873 
874 /**
875  * cairo_scaled_font_create:
876  * @font_face: a #cairo_font_face_t
877  * @font_matrix: font space to user space transformation matrix for the
878  *       font. In the simplest case of a N point font, this matrix is
879  *       just a scale by N, but it can also be used to shear the font
880  *       or stretch it unequally along the two axes. See
881  *       cairo_set_font_matrix().
882  * @ctm: user to device transformation matrix with which the font will
883  *       be used.
884  * @options: options to use when getting metrics for the font and
885  *           rendering with it.
886  *
887  * Creates a #cairo_scaled_font_t object from a font face and matrices that
888  * describe the size of the font and the environment in which it will
889  * be used.
890  *
891  * Return value: a newly created #cairo_scaled_font_t. Destroy with
892  *  cairo_scaled_font_destroy()
893  **/
894 cairo_scaled_font_t *
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)895 cairo_scaled_font_create (cairo_font_face_t          *font_face,
896 			  const cairo_matrix_t       *font_matrix,
897 			  const cairo_matrix_t       *ctm,
898 			  const cairo_font_options_t *options)
899 {
900     cairo_status_t status;
901     cairo_scaled_font_map_t *font_map;
902     cairo_font_face_t *original_font_face = font_face;
903     cairo_scaled_font_t key, *old = NULL, *scaled_font = NULL, *dead = NULL;
904     double det;
905 
906     status = font_face->status;
907     if (unlikely (status))
908 	return _cairo_scaled_font_create_in_error (status);
909 
910     det = _cairo_matrix_compute_determinant (font_matrix);
911     if (! ISFINITE (det))
912 	return _cairo_scaled_font_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_MATRIX));
913 
914     det = _cairo_matrix_compute_determinant (ctm);
915     if (! ISFINITE (det))
916 	return _cairo_scaled_font_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_MATRIX));
917 
918     status = cairo_font_options_status ((cairo_font_options_t *) options);
919     if (unlikely (status))
920 	return _cairo_scaled_font_create_in_error (status);
921 
922     /* Note that degenerate ctm or font_matrix *are* allowed.
923      * We want to support a font size of 0. */
924 
925     font_map = _cairo_scaled_font_map_lock ();
926     if (unlikely (font_map == NULL))
927 	return _cairo_scaled_font_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
928 
929     scaled_font = font_map->mru_scaled_font;
930     if (scaled_font != NULL &&
931 	_cairo_scaled_font_matches (scaled_font,
932 	                            font_face, font_matrix, ctm, options))
933     {
934 	assert (scaled_font->hash_entry.hash != ZOMBIE);
935 	assert (! scaled_font->placeholder);
936 
937 	if (likely (scaled_font->status == CAIRO_STATUS_SUCCESS)) {
938 	    /* We increment the reference count manually here, (rather
939 	     * than calling into cairo_scaled_font_reference), since we
940 	     * must modify the reference count while our lock is still
941 	     * held. */
942 	    _cairo_reference_count_inc (&scaled_font->ref_count);
943 	    _cairo_scaled_font_map_unlock ();
944 	    return scaled_font;
945 	}
946 
947 	/* the font has been put into an error status - abandon the cache */
948 	_cairo_hash_table_remove (font_map->hash_table,
949 				  &scaled_font->hash_entry);
950 	scaled_font->hash_entry.hash = ZOMBIE;
951 	dead = scaled_font;
952 	font_map->mru_scaled_font = NULL;
953 
954 	if (font_face->backend->get_implementation != NULL) {
955 	    font_face = font_face->backend->get_implementation (font_face,
956 								font_matrix,
957 								ctm,
958 								options);
959 	    if (unlikely (font_face->status)) {
960 		_cairo_scaled_font_map_unlock ();
961 		cairo_scaled_font_destroy (scaled_font);
962 		return _cairo_scaled_font_create_in_error (font_face->status);
963 	    }
964 	}
965 
966 	_cairo_scaled_font_init_key (&key, font_face,
967 				     font_matrix, ctm, options);
968     }
969     else
970     {
971 	if (font_face->backend->get_implementation != NULL) {
972 	    font_face = font_face->backend->get_implementation (font_face,
973 								font_matrix,
974 								ctm,
975 								options);
976 	    if (unlikely (font_face->status)) {
977 		_cairo_scaled_font_map_unlock ();
978 		return _cairo_scaled_font_create_in_error (font_face->status);
979 	    }
980 	}
981 
982 	_cairo_scaled_font_init_key (&key, font_face,
983 				     font_matrix, ctm, options);
984 
985 	while ((scaled_font = _cairo_hash_table_lookup (font_map->hash_table,
986 							&key.hash_entry)))
987 	{
988 	    if (! scaled_font->placeholder)
989 		break;
990 
991 	    /* If the scaled font is being created (happens for user-font),
992 	     * just wait until it's done, then retry */
993 	    _cairo_scaled_font_placeholder_wait_for_creation_to_finish (scaled_font);
994 	}
995 
996 	/* Return existing scaled_font if it exists in the hash table. */
997 	if (scaled_font != NULL) {
998 	    /* If the original reference count is 0, then this font must have
999 	     * been found in font_map->holdovers, (which means this caching is
1000 	     * actually working). So now we remove it from the holdovers
1001 	     * array, unless we caught the font in the middle of destruction.
1002 	     */
1003 	    if (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count)) {
1004 		if (scaled_font->holdover) {
1005 		    int i;
1006 
1007 		    for (i = 0; i < font_map->num_holdovers; i++) {
1008 			if (font_map->holdovers[i] == scaled_font) {
1009 			    font_map->num_holdovers--;
1010 			    memmove (&font_map->holdovers[i],
1011 				     &font_map->holdovers[i+1],
1012 				     (font_map->num_holdovers - i) * sizeof (cairo_scaled_font_t*));
1013 			    break;
1014 			}
1015 		    }
1016 
1017 		    scaled_font->holdover = FALSE;
1018 		}
1019 
1020 		/* reset any error status */
1021 		scaled_font->status = CAIRO_STATUS_SUCCESS;
1022 	    }
1023 
1024 	    if (likely (scaled_font->status == CAIRO_STATUS_SUCCESS)) {
1025 		/* We increment the reference count manually here, (rather
1026 		 * than calling into cairo_scaled_font_reference), since we
1027 		 * must modify the reference count while our lock is still
1028 		 * held. */
1029 
1030 		old = font_map->mru_scaled_font;
1031 		font_map->mru_scaled_font = scaled_font;
1032 		/* increment reference count for the mru cache */
1033 		_cairo_reference_count_inc (&scaled_font->ref_count);
1034 		/* and increment for the returned reference */
1035 		_cairo_reference_count_inc (&scaled_font->ref_count);
1036 		_cairo_scaled_font_map_unlock ();
1037 
1038 		cairo_scaled_font_destroy (old);
1039 		if (font_face != original_font_face)
1040 		    cairo_font_face_destroy (font_face);
1041 
1042 		return scaled_font;
1043 	    }
1044 
1045 	    /* the font has been put into an error status - abandon the cache */
1046 	    _cairo_hash_table_remove (font_map->hash_table,
1047 				      &scaled_font->hash_entry);
1048 	    scaled_font->hash_entry.hash = ZOMBIE;
1049 	}
1050     }
1051 
1052     /* Otherwise create it and insert it into the hash table. */
1053     status = font_face->backend->scaled_font_create (font_face, font_matrix,
1054 						     ctm, options, &scaled_font);
1055     /* Did we leave the backend in an error state? */
1056     if (unlikely (status)) {
1057 	_cairo_scaled_font_map_unlock ();
1058 	if (font_face != original_font_face)
1059 	    cairo_font_face_destroy (font_face);
1060 
1061 	if (dead != NULL)
1062 	    cairo_scaled_font_destroy (dead);
1063 
1064 	status = _cairo_font_face_set_error (font_face, status);
1065 	return _cairo_scaled_font_create_in_error (status);
1066     }
1067     /* Or did we encounter an error whilst constructing the scaled font? */
1068     if (unlikely (scaled_font->status)) {
1069 	_cairo_scaled_font_map_unlock ();
1070 	if (font_face != original_font_face)
1071 	    cairo_font_face_destroy (font_face);
1072 
1073 	if (dead != NULL)
1074 	    cairo_scaled_font_destroy (dead);
1075 
1076 	return scaled_font;
1077     }
1078 
1079     /* Our caching above is defeated if the backend switches fonts on us -
1080      * e.g. old incarnations of toy-font-face and lazily resolved
1081      * ft-font-faces
1082      */
1083     assert (scaled_font->font_face == font_face);
1084 
1085     scaled_font->original_font_face =
1086 	cairo_font_face_reference (original_font_face);
1087 
1088     status = _cairo_hash_table_insert (font_map->hash_table,
1089 				       &scaled_font->hash_entry);
1090     if (likely (status == CAIRO_STATUS_SUCCESS)) {
1091 	old = font_map->mru_scaled_font;
1092 	font_map->mru_scaled_font = scaled_font;
1093 	_cairo_reference_count_inc (&scaled_font->ref_count);
1094     }
1095 
1096     _cairo_scaled_font_map_unlock ();
1097 
1098     cairo_scaled_font_destroy (old);
1099     if (font_face != original_font_face)
1100 	cairo_font_face_destroy (font_face);
1101 
1102     if (dead != NULL)
1103 	cairo_scaled_font_destroy (dead);
1104 
1105     if (unlikely (status)) {
1106 	/* We can't call _cairo_scaled_font_destroy here since it expects
1107 	 * that the font has already been successfully inserted into the
1108 	 * hash table. */
1109 	_cairo_scaled_font_fini_internal (scaled_font);
1110 	free (scaled_font);
1111 	return _cairo_scaled_font_create_in_error (status);
1112     }
1113 
1114     return scaled_font;
1115 }
1116 slim_hidden_def (cairo_scaled_font_create);
1117 
1118 static cairo_scaled_font_t *_cairo_scaled_font_nil_objects[CAIRO_STATUS_LAST_STATUS + 1];
1119 
1120 /* XXX This should disappear in favour of a common pool of error objects. */
1121 cairo_scaled_font_t *
_cairo_scaled_font_create_in_error(cairo_status_t status)1122 _cairo_scaled_font_create_in_error (cairo_status_t status)
1123 {
1124     cairo_scaled_font_t *scaled_font;
1125 
1126     assert (status != CAIRO_STATUS_SUCCESS);
1127 
1128     if (status == CAIRO_STATUS_NO_MEMORY)
1129 	return (cairo_scaled_font_t *) &_cairo_scaled_font_nil;
1130 
1131     CAIRO_MUTEX_LOCK (_cairo_scaled_font_error_mutex);
1132     scaled_font = _cairo_scaled_font_nil_objects[status];
1133     if (unlikely (scaled_font == NULL)) {
1134 	scaled_font = malloc (sizeof (cairo_scaled_font_t));
1135 	if (unlikely (scaled_font == NULL)) {
1136 	    CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_error_mutex);
1137 	    _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
1138 	    return (cairo_scaled_font_t *) &_cairo_scaled_font_nil;
1139 	}
1140 
1141 	*scaled_font = _cairo_scaled_font_nil;
1142 	scaled_font->status = status;
1143 	_cairo_scaled_font_nil_objects[status] = scaled_font;
1144     }
1145     CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_error_mutex);
1146 
1147     return scaled_font;
1148 }
1149 
1150 void
_cairo_scaled_font_reset_static_data(void)1151 _cairo_scaled_font_reset_static_data (void)
1152 {
1153     int status;
1154 
1155     CAIRO_MUTEX_LOCK (_cairo_scaled_font_error_mutex);
1156     for (status = CAIRO_STATUS_SUCCESS;
1157 	 status <= CAIRO_STATUS_LAST_STATUS;
1158 	 status++)
1159     {
1160 	if (_cairo_scaled_font_nil_objects[status] != NULL) {
1161 	    free (_cairo_scaled_font_nil_objects[status]);
1162 	    _cairo_scaled_font_nil_objects[status] = NULL;
1163 	}
1164     }
1165     CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_error_mutex);
1166 
1167     CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex);
1168     if (cairo_scaled_glyph_page_cache.hash_table != NULL) {
1169 	_cairo_cache_fini (&cairo_scaled_glyph_page_cache);
1170 	cairo_scaled_glyph_page_cache.hash_table = NULL;
1171     }
1172     CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex);
1173 }
1174 
1175 /**
1176  * cairo_scaled_font_reference:
1177  * @scaled_font: a #cairo_scaled_font_t, (may be %NULL in which case
1178  * this function does nothing)
1179  *
1180  * Increases the reference count on @scaled_font by one. This prevents
1181  * @scaled_font from being destroyed until a matching call to
1182  * cairo_scaled_font_destroy() is made.
1183  *
1184  * The number of references to a #cairo_scaled_font_t can be get using
1185  * cairo_scaled_font_get_reference_count().
1186  *
1187  * Returns: the referenced #cairo_scaled_font_t
1188  **/
1189 cairo_scaled_font_t *
cairo_scaled_font_reference(cairo_scaled_font_t * scaled_font)1190 cairo_scaled_font_reference (cairo_scaled_font_t *scaled_font)
1191 {
1192     if (scaled_font == NULL ||
1193 	    CAIRO_REFERENCE_COUNT_IS_INVALID (&scaled_font->ref_count))
1194 	return scaled_font;
1195 
1196     assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count));
1197 
1198     _cairo_reference_count_inc (&scaled_font->ref_count);
1199 
1200     return scaled_font;
1201 }
1202 slim_hidden_def (cairo_scaled_font_reference);
1203 
1204 /**
1205  * cairo_scaled_font_destroy:
1206  * @scaled_font: a #cairo_scaled_font_t
1207  *
1208  * Decreases the reference count on @font by one. If the result
1209  * is zero, then @font and all associated resources are freed.
1210  * See cairo_scaled_font_reference().
1211  **/
1212 void
cairo_scaled_font_destroy(cairo_scaled_font_t * scaled_font)1213 cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font)
1214 {
1215     cairo_scaled_font_t *lru = NULL;
1216     cairo_scaled_font_map_t *font_map;
1217 
1218     assert (CAIRO_MUTEX_IS_UNLOCKED (_cairo_scaled_font_map_mutex));
1219 
1220     if (scaled_font == NULL ||
1221 	    CAIRO_REFERENCE_COUNT_IS_INVALID (&scaled_font->ref_count))
1222 	return;
1223 
1224     assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count));
1225 
1226     if (! _cairo_reference_count_dec_and_test (&scaled_font->ref_count))
1227 	return;
1228 
1229     font_map = _cairo_scaled_font_map_lock ();
1230     assert (font_map != NULL);
1231 
1232     /* Another thread may have resurrected the font whilst we waited */
1233     if (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count)) {
1234 	if (! scaled_font->placeholder &&
1235 	    scaled_font->hash_entry.hash != ZOMBIE)
1236 	{
1237 	    /* Another thread may have already inserted us into the holdovers */
1238 	    if (scaled_font->holdover)
1239 		goto unlock;
1240 
1241 	    /* Rather than immediately destroying this object, we put it into
1242 	     * the font_map->holdovers array in case it will get used again
1243 	     * soon (and is why we must hold the lock over the atomic op on
1244 	     * the reference count). To make room for it, we do actually
1245 	     * destroy the least-recently-used holdover.
1246 	     */
1247 
1248 	    if (font_map->num_holdovers == CAIRO_SCALED_FONT_MAX_HOLDOVERS) {
1249 		lru = font_map->holdovers[0];
1250 		assert (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&lru->ref_count));
1251 
1252 		_cairo_hash_table_remove (font_map->hash_table,
1253 					  &lru->hash_entry);
1254 
1255 		font_map->num_holdovers--;
1256 		memmove (&font_map->holdovers[0],
1257 			 &font_map->holdovers[1],
1258 			 font_map->num_holdovers * sizeof (cairo_scaled_font_t*));
1259 	    }
1260 
1261 	    font_map->holdovers[font_map->num_holdovers++] = scaled_font;
1262 	    scaled_font->holdover = TRUE;
1263 	} else
1264 	    lru = scaled_font;
1265     }
1266 
1267   unlock:
1268     _cairo_scaled_font_map_unlock ();
1269 
1270     /* If we pulled an item from the holdovers array, (while the font
1271      * map lock was held, of course), then there is no way that anyone
1272      * else could have acquired a reference to it. So we can now
1273      * safely call fini on it without any lock held. This is desirable
1274      * as we never want to call into any backend function with a lock
1275      * held. */
1276     if (lru != NULL) {
1277 	_cairo_scaled_font_fini_internal (lru);
1278 	free (lru);
1279     }
1280 }
1281 slim_hidden_def (cairo_scaled_font_destroy);
1282 
1283 /**
1284  * cairo_scaled_font_get_reference_count:
1285  * @scaled_font: a #cairo_scaled_font_t
1286  *
1287  * Returns the current reference count of @scaled_font.
1288  *
1289  * Return value: the current reference count of @scaled_font.  If the
1290  * object is a nil object, 0 will be returned.
1291  *
1292  * Since: 1.4
1293  **/
1294 unsigned int
cairo_scaled_font_get_reference_count(cairo_scaled_font_t * scaled_font)1295 cairo_scaled_font_get_reference_count (cairo_scaled_font_t *scaled_font)
1296 {
1297     if (scaled_font == NULL ||
1298 	    CAIRO_REFERENCE_COUNT_IS_INVALID (&scaled_font->ref_count))
1299 	return 0;
1300 
1301     return CAIRO_REFERENCE_COUNT_GET_VALUE (&scaled_font->ref_count);
1302 }
1303 
1304 /**
1305  * cairo_scaled_font_get_user_data:
1306  * @scaled_font: a #cairo_scaled_font_t
1307  * @key: the address of the #cairo_user_data_key_t the user data was
1308  * attached to
1309  *
1310  * Return user data previously attached to @scaled_font using the
1311  * specified key.  If no user data has been attached with the given
1312  * key this function returns %NULL.
1313  *
1314  * Return value: the user data previously attached or %NULL.
1315  *
1316  * Since: 1.4
1317  **/
1318 void *
cairo_scaled_font_get_user_data(cairo_scaled_font_t * scaled_font,const cairo_user_data_key_t * key)1319 cairo_scaled_font_get_user_data (cairo_scaled_font_t	     *scaled_font,
1320 				 const cairo_user_data_key_t *key)
1321 {
1322     return _cairo_user_data_array_get_data (&scaled_font->user_data,
1323 					    key);
1324 }
1325 slim_hidden_def (cairo_scaled_font_get_user_data);
1326 
1327 /**
1328  * cairo_scaled_font_set_user_data:
1329  * @scaled_font: a #cairo_scaled_font_t
1330  * @key: the address of a #cairo_user_data_key_t to attach the user data to
1331  * @user_data: the user data to attach to the #cairo_scaled_font_t
1332  * @destroy: a #cairo_destroy_func_t which will be called when the
1333  * #cairo_t is destroyed or when new user data is attached using the
1334  * same key.
1335  *
1336  * Attach user data to @scaled_font.  To remove user data from a surface,
1337  * call this function with the key that was used to set it and %NULL
1338  * for @data.
1339  *
1340  * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a
1341  * slot could not be allocated for the user data.
1342  *
1343  * Since: 1.4
1344  **/
1345 cairo_status_t
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)1346 cairo_scaled_font_set_user_data (cairo_scaled_font_t	     *scaled_font,
1347 				 const cairo_user_data_key_t *key,
1348 				 void			     *user_data,
1349 				 cairo_destroy_func_t	      destroy)
1350 {
1351     if (CAIRO_REFERENCE_COUNT_IS_INVALID (&scaled_font->ref_count))
1352 	return scaled_font->status;
1353 
1354     return _cairo_user_data_array_set_data (&scaled_font->user_data,
1355 					    key, user_data, destroy);
1356 }
1357 slim_hidden_def (cairo_scaled_font_set_user_data);
1358 
1359 /* Public font API follows. */
1360 
1361 /**
1362  * cairo_scaled_font_extents:
1363  * @scaled_font: a #cairo_scaled_font_t
1364  * @extents: a #cairo_font_extents_t which to store the retrieved extents.
1365  *
1366  * Gets the metrics for a #cairo_scaled_font_t.
1367  **/
1368 void
cairo_scaled_font_extents(cairo_scaled_font_t * scaled_font,cairo_font_extents_t * extents)1369 cairo_scaled_font_extents (cairo_scaled_font_t  *scaled_font,
1370 			   cairo_font_extents_t *extents)
1371 {
1372     if (scaled_font->status) {
1373 	extents->ascent  = 0.0;
1374 	extents->descent = 0.0;
1375 	extents->height  = 0.0;
1376 	extents->max_x_advance = 0.0;
1377 	extents->max_y_advance = 0.0;
1378 	return;
1379     }
1380 
1381     *extents = scaled_font->extents;
1382 }
1383 slim_hidden_def (cairo_scaled_font_extents);
1384 
1385 /**
1386  * cairo_scaled_font_text_extents:
1387  * @scaled_font: a #cairo_scaled_font_t
1388  * @utf8: a NUL-terminated string of text, encoded in UTF-8
1389  * @extents: a #cairo_text_extents_t which to store the retrieved extents.
1390  *
1391  * Gets the extents for a string of text. The extents describe a
1392  * user-space rectangle that encloses the "inked" portion of the text
1393  * drawn at the origin (0,0) (as it would be drawn by cairo_show_text()
1394  * if the cairo graphics state were set to the same font_face,
1395  * font_matrix, ctm, and font_options as @scaled_font).  Additionally,
1396  * the x_advance and y_advance values indicate the amount by which the
1397  * current point would be advanced by cairo_show_text().
1398  *
1399  * Note that whitespace characters do not directly contribute to the
1400  * size of the rectangle (extents.width and extents.height). They do
1401  * contribute indirectly by changing the position of non-whitespace
1402  * characters. In particular, trailing whitespace characters are
1403  * likely to not affect the size of the rectangle, though they will
1404  * affect the x_advance and y_advance values.
1405  *
1406  * Since: 1.2
1407  **/
1408 void
cairo_scaled_font_text_extents(cairo_scaled_font_t * scaled_font,const char * utf8,cairo_text_extents_t * extents)1409 cairo_scaled_font_text_extents (cairo_scaled_font_t   *scaled_font,
1410 				const char            *utf8,
1411 				cairo_text_extents_t  *extents)
1412 {
1413     cairo_status_t status;
1414     cairo_glyph_t *glyphs = NULL;
1415     int num_glyphs;
1416 
1417     if (scaled_font->status)
1418 	goto ZERO_EXTENTS;
1419 
1420     if (utf8 == NULL)
1421 	goto ZERO_EXTENTS;
1422 
1423     status = cairo_scaled_font_text_to_glyphs (scaled_font, 0., 0.,
1424 					       utf8, -1,
1425 					       &glyphs, &num_glyphs,
1426 					       NULL, NULL,
1427 					       NULL);
1428     if (unlikely (status)) {
1429 	status = _cairo_scaled_font_set_error (scaled_font, status);
1430 	goto ZERO_EXTENTS;
1431     }
1432 
1433     cairo_scaled_font_glyph_extents (scaled_font, glyphs, num_glyphs, extents);
1434     free (glyphs);
1435 
1436     return;
1437 
1438 ZERO_EXTENTS:
1439     extents->x_bearing = 0.0;
1440     extents->y_bearing = 0.0;
1441     extents->width  = 0.0;
1442     extents->height = 0.0;
1443     extents->x_advance = 0.0;
1444     extents->y_advance = 0.0;
1445 }
1446 
1447 /**
1448  * cairo_scaled_font_glyph_extents:
1449  * @scaled_font: a #cairo_scaled_font_t
1450  * @glyphs: an array of glyph IDs with X and Y offsets.
1451  * @num_glyphs: the number of glyphs in the @glyphs array
1452  * @extents: a #cairo_text_extents_t which to store the retrieved extents.
1453  *
1454  * Gets the extents for an array of glyphs. The extents describe a
1455  * user-space rectangle that encloses the "inked" portion of the
1456  * glyphs, (as they would be drawn by cairo_show_glyphs() if the cairo
1457  * graphics state were set to the same font_face, font_matrix, ctm,
1458  * and font_options as @scaled_font).  Additionally, the x_advance and
1459  * y_advance values indicate the amount by which the current point
1460  * would be advanced by cairo_show_glyphs().
1461  *
1462  * Note that whitespace glyphs do not contribute to the size of the
1463  * rectangle (extents.width and extents.height).
1464  **/
1465 void
cairo_scaled_font_glyph_extents(cairo_scaled_font_t * scaled_font,const cairo_glyph_t * glyphs,int num_glyphs,cairo_text_extents_t * extents)1466 cairo_scaled_font_glyph_extents (cairo_scaled_font_t   *scaled_font,
1467 				 const cairo_glyph_t   *glyphs,
1468 				 int                    num_glyphs,
1469 				 cairo_text_extents_t  *extents)
1470 {
1471     cairo_status_t status;
1472     int i;
1473     double min_x = 0.0, min_y = 0.0, max_x = 0.0, max_y = 0.0;
1474     cairo_bool_t visible = FALSE;
1475     cairo_scaled_glyph_t *scaled_glyph = NULL;
1476 
1477     extents->x_bearing = 0.0;
1478     extents->y_bearing = 0.0;
1479     extents->width  = 0.0;
1480     extents->height = 0.0;
1481     extents->x_advance = 0.0;
1482     extents->y_advance = 0.0;
1483 
1484     if (unlikely (scaled_font->status))
1485 	goto ZERO_EXTENTS;
1486 
1487     if (num_glyphs == 0)
1488 	goto ZERO_EXTENTS;
1489 
1490     if (unlikely (num_glyphs < 0)) {
1491 	_cairo_error_throw (CAIRO_STATUS_NEGATIVE_COUNT);
1492 	/* XXX Can't propagate error */
1493 	goto ZERO_EXTENTS;
1494     }
1495 
1496     if (unlikely (glyphs == NULL)) {
1497 	_cairo_error_throw (CAIRO_STATUS_NULL_POINTER);
1498 	/* XXX Can't propagate error */
1499 	goto ZERO_EXTENTS;
1500     }
1501 
1502     _cairo_scaled_font_freeze_cache (scaled_font);
1503 
1504     for (i = 0; i < num_glyphs; i++) {
1505 	double			left, top, right, bottom;
1506 
1507 	status = _cairo_scaled_glyph_lookup (scaled_font,
1508 					     glyphs[i].index,
1509 					     CAIRO_SCALED_GLYPH_INFO_METRICS,
1510 					     &scaled_glyph);
1511 	if (unlikely (status)) {
1512 	    if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
1513 		status = _cairo_scaled_font_set_error (scaled_font, status);
1514 	    }
1515 	    goto UNLOCK;
1516 	}
1517 
1518 	/* "Ink" extents should skip "invisible" glyphs */
1519 	if (scaled_glyph->metrics.width == 0 || scaled_glyph->metrics.height == 0)
1520 	    continue;
1521 
1522 	left = scaled_glyph->metrics.x_bearing + glyphs[i].x;
1523 	right = left + scaled_glyph->metrics.width;
1524 	top = scaled_glyph->metrics.y_bearing + glyphs[i].y;
1525 	bottom = top + scaled_glyph->metrics.height;
1526 
1527 	if (!visible) {
1528 	    visible = TRUE;
1529 	    min_x = left;
1530 	    max_x = right;
1531 	    min_y = top;
1532 	    max_y = bottom;
1533 	} else {
1534 	    if (left < min_x) min_x = left;
1535 	    if (right > max_x) max_x = right;
1536 	    if (top < min_y) min_y = top;
1537 	    if (bottom > max_y) max_y = bottom;
1538 	}
1539     }
1540 
1541     if (visible) {
1542 	extents->x_bearing = min_x - glyphs[0].x;
1543 	extents->y_bearing = min_y - glyphs[0].y;
1544 	extents->width = max_x - min_x;
1545 	extents->height = max_y - min_y;
1546     } else {
1547 	extents->x_bearing = 0.0;
1548 	extents->y_bearing = 0.0;
1549 	extents->width = 0.0;
1550 	extents->height = 0.0;
1551     }
1552 
1553     if (num_glyphs) {
1554         double x0, y0, x1, y1;
1555 
1556 	x0 = glyphs[0].x;
1557 	y0 = glyphs[0].y;
1558 
1559 	/* scaled_glyph contains the glyph for num_glyphs - 1 already. */
1560 	x1 = glyphs[num_glyphs - 1].x + scaled_glyph->metrics.x_advance;
1561 	y1 = glyphs[num_glyphs - 1].y + scaled_glyph->metrics.y_advance;
1562 
1563 	extents->x_advance = x1 - x0;
1564 	extents->y_advance = y1 - y0;
1565     } else {
1566 	extents->x_advance = 0.0;
1567 	extents->y_advance = 0.0;
1568     }
1569 
1570  UNLOCK:
1571     _cairo_scaled_font_thaw_cache (scaled_font);
1572     return;
1573 
1574 ZERO_EXTENTS:
1575     extents->x_bearing = 0.0;
1576     extents->y_bearing = 0.0;
1577     extents->width  = 0.0;
1578     extents->height = 0.0;
1579     extents->x_advance = 0.0;
1580     extents->y_advance = 0.0;
1581 }
1582 slim_hidden_def (cairo_scaled_font_glyph_extents);
1583 
1584 #define GLYPH_LUT_SIZE 64
1585 static cairo_status_t
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)1586 cairo_scaled_font_text_to_glyphs_internal_cached (cairo_scaled_font_t		 *scaled_font,
1587 						    double			  x,
1588 						    double			  y,
1589 						    const char			 *utf8,
1590 						    cairo_glyph_t		 *glyphs,
1591 						    cairo_text_cluster_t	**clusters,
1592 						    int				  num_chars)
1593 {
1594     struct glyph_lut_elt {
1595 	unsigned long index;
1596 	double x_advance;
1597 	double y_advance;
1598     } glyph_lut[GLYPH_LUT_SIZE];
1599     uint32_t glyph_lut_unicode[GLYPH_LUT_SIZE];
1600     cairo_status_t status;
1601     const char *p;
1602     int i;
1603 
1604     for (i = 0; i < GLYPH_LUT_SIZE; i++)
1605 	glyph_lut_unicode[i] = ~0U;
1606 
1607     p = utf8;
1608     for (i = 0; i < num_chars; i++) {
1609 	int idx, num_bytes;
1610 	uint32_t unicode;
1611 	cairo_scaled_glyph_t *scaled_glyph;
1612 	struct glyph_lut_elt *glyph_slot;
1613 
1614 	num_bytes = _cairo_utf8_get_char_validated (p, &unicode);
1615 	p += num_bytes;
1616 
1617 	glyphs[i].x = x;
1618 	glyphs[i].y = y;
1619 
1620 	idx = unicode % ARRAY_LENGTH (glyph_lut);
1621 	glyph_slot = &glyph_lut[idx];
1622 	if (glyph_lut_unicode[idx] == unicode) {
1623 	    glyphs[i].index = glyph_slot->index;
1624 	    x += glyph_slot->x_advance;
1625 	    y += glyph_slot->y_advance;
1626 	} else {
1627 	    unsigned long g;
1628 
1629 	    g = scaled_font->backend->ucs4_to_index (scaled_font, unicode);
1630 	    status = _cairo_scaled_glyph_lookup (scaled_font,
1631 						 g,
1632 						 CAIRO_SCALED_GLYPH_INFO_METRICS,
1633 						 &scaled_glyph);
1634 	    if (unlikely (status))
1635 		return status;
1636 
1637 	    x += scaled_glyph->metrics.x_advance;
1638 	    y += scaled_glyph->metrics.y_advance;
1639 
1640 	    glyph_lut_unicode[idx] = unicode;
1641 	    glyph_slot->index = g;
1642 	    glyph_slot->x_advance = scaled_glyph->metrics.x_advance;
1643 	    glyph_slot->y_advance = scaled_glyph->metrics.y_advance;
1644 
1645 	    glyphs[i].index = g;
1646 	}
1647 
1648 	if (clusters) {
1649 	    (*clusters)[i].num_bytes  = num_bytes;
1650 	    (*clusters)[i].num_glyphs = 1;
1651 	}
1652     }
1653 
1654     return CAIRO_STATUS_SUCCESS;
1655 }
1656 
1657 static cairo_status_t
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)1658 cairo_scaled_font_text_to_glyphs_internal_uncached (cairo_scaled_font_t	 *scaled_font,
1659 						  double		  x,
1660 						  double		  y,
1661 						  const char		 *utf8,
1662 						  cairo_glyph_t		 *glyphs,
1663 						  cairo_text_cluster_t	**clusters,
1664 						  int			  num_chars)
1665 {
1666     const char *p;
1667     int i;
1668 
1669     p = utf8;
1670     for (i = 0; i < num_chars; i++) {
1671 	unsigned long g;
1672 	int num_bytes;
1673 	uint32_t unicode;
1674 	cairo_scaled_glyph_t *scaled_glyph;
1675 	cairo_status_t status;
1676 
1677 	num_bytes = _cairo_utf8_get_char_validated (p, &unicode);
1678 	p += num_bytes;
1679 
1680 	glyphs[i].x = x;
1681 	glyphs[i].y = y;
1682 
1683 	g = scaled_font->backend->ucs4_to_index (scaled_font, unicode);
1684 
1685 	/*
1686 	 * No advance needed for a single character string. So, let's speed up
1687 	 * one-character strings by skipping glyph lookup.
1688 	 */
1689 	if (num_chars > 1) {
1690 	    status = _cairo_scaled_glyph_lookup (scaled_font,
1691 					     g,
1692 					     CAIRO_SCALED_GLYPH_INFO_METRICS,
1693 					     &scaled_glyph);
1694 	    if (unlikely (status))
1695 		return status;
1696 
1697 	    x += scaled_glyph->metrics.x_advance;
1698 	    y += scaled_glyph->metrics.y_advance;
1699 	}
1700 
1701 	glyphs[i].index = g;
1702 
1703 	if (clusters) {
1704 	    (*clusters)[i].num_bytes  = num_bytes;
1705 	    (*clusters)[i].num_glyphs = 1;
1706 	}
1707     }
1708 
1709     return CAIRO_STATUS_SUCCESS;
1710 }
1711 
1712 /**
1713  * cairo_scaled_font_text_to_glyphs:
1714  * @x: X position to place first glyph
1715  * @y: Y position to place first glyph
1716  * @scaled_font: a #cairo_scaled_font_t
1717  * @utf8: a string of text encoded in UTF-8
1718  * @utf8_len: length of @utf8 in bytes, or -1 if it is NUL-terminated
1719  * @glyphs: pointer to array of glyphs to fill
1720  * @num_glyphs: pointer to number of glyphs
1721  * @clusters: pointer to array of cluster mapping information to fill, or %NULL
1722  * @num_clusters: pointer to number of clusters, or %NULL
1723  * @cluster_flags: pointer to location to store cluster flags corresponding to the
1724  *                 output @clusters, or %NULL
1725  *
1726  * Converts UTF-8 text to an array of glyphs, optionally with cluster
1727  * mapping, that can be used to render later using @scaled_font.
1728  *
1729  * If @glyphs initially points to a non-%NULL value, that array is used
1730  * as a glyph buffer, and @num_glyphs should point to the number of glyph
1731  * entries available there.  If the provided glyph array is too short for
1732  * the conversion, a new glyph array is allocated using cairo_glyph_allocate()
1733  * and placed in @glyphs.  Upon return, @num_glyphs always contains the
1734  * number of generated glyphs.  If the value @glyphs points to has changed
1735  * after the call, the user is responsible for freeing the allocated glyph
1736  * array using cairo_glyph_free().  This may happen even if the provided
1737  * array was large enough.
1738  *
1739  * If @clusters is not %NULL, @num_clusters and @cluster_flags should not be %NULL,
1740  * and cluster mapping will be computed.
1741  * The semantics of how cluster array allocation works is similar to the glyph
1742  * array.  That is,
1743  * if @clusters initially points to a non-%NULL value, that array is used
1744  * as a cluster buffer, and @num_clusters should point to the number of cluster
1745  * entries available there.  If the provided cluster array is too short for
1746  * the conversion, a new cluster array is allocated using cairo_text_cluster_allocate()
1747  * and placed in @clusters.  Upon return, @num_clusters always contains the
1748  * number of generated clusters.  If the value @clusters points at has changed
1749  * after the call, the user is responsible for freeing the allocated cluster
1750  * array using cairo_text_cluster_free().  This may happen even if the provided
1751  * array was large enough.
1752  *
1753  * In the simplest case, @glyphs and @clusters can point to %NULL initially
1754  * and a suitable array will be allocated.  In code:
1755  * <informalexample><programlisting>
1756  * cairo_status_t status;
1757  *
1758  * cairo_glyph_t *glyphs = NULL;
1759  * int num_glyphs;
1760  * cairo_text_cluster_t *clusters = NULL;
1761  * int num_clusters;
1762  * cairo_text_cluster_flags_t cluster_flags;
1763  *
1764  * status = cairo_scaled_font_text_to_glyphs (scaled_font,
1765  *                                            x, y,
1766  *                                            utf8, utf8_len,
1767  *                                            &amp;glyphs, &amp;num_glyphs,
1768  *                                            &amp;clusters, &amp;num_clusters, &amp;cluster_flags);
1769  *
1770  * if (status == CAIRO_STATUS_SUCCESS) {
1771  *     cairo_show_text_glyphs (cr,
1772  *                             utf8, utf8_len,
1773  *                             glyphs, num_glyphs,
1774  *                             clusters, num_clusters, cluster_flags);
1775  *
1776  *     cairo_glyph_free (glyphs);
1777  *     cairo_text_cluster_free (clusters);
1778  * }
1779  * </programlisting></informalexample>
1780  *
1781  * If no cluster mapping is needed:
1782  * <informalexample><programlisting>
1783  * cairo_status_t status;
1784  *
1785  * cairo_glyph_t *glyphs = NULL;
1786  * int num_glyphs;
1787  *
1788  * status = cairo_scaled_font_text_to_glyphs (scaled_font,
1789  *                                            x, y,
1790  *                                            utf8, utf8_len,
1791  *                                            &amp;glyphs, &amp;num_glyphs,
1792  *                                            NULL, NULL,
1793  *                                            NULL);
1794  *
1795  * if (status == CAIRO_STATUS_SUCCESS) {
1796  *     cairo_show_glyphs (cr, glyphs, num_glyphs);
1797  *     cairo_glyph_free (glyphs);
1798  * }
1799  * </programlisting></informalexample>
1800  *
1801  * If stack-based glyph and cluster arrays are to be used for small
1802  * arrays:
1803  * <informalexample><programlisting>
1804  * cairo_status_t status;
1805  *
1806  * cairo_glyph_t stack_glyphs[40];
1807  * cairo_glyph_t *glyphs = stack_glyphs;
1808  * int num_glyphs = sizeof (stack_glyphs) / sizeof (stack_glyphs[0]);
1809  * cairo_text_cluster_t stack_clusters[40];
1810  * cairo_text_cluster_t *clusters = stack_clusters;
1811  * int num_clusters = sizeof (stack_clusters) / sizeof (stack_clusters[0]);
1812  * cairo_text_cluster_flags_t cluster_flags;
1813  *
1814  * status = cairo_scaled_font_text_to_glyphs (scaled_font,
1815  *                                            x, y,
1816  *                                            utf8, utf8_len,
1817  *                                            &amp;glyphs, &amp;num_glyphs,
1818  *                                            &amp;clusters, &amp;num_clusters, &amp;cluster_flags);
1819  *
1820  * if (status == CAIRO_STATUS_SUCCESS) {
1821  *     cairo_show_text_glyphs (cr,
1822  *                             utf8, utf8_len,
1823  *                             glyphs, num_glyphs,
1824  *                             clusters, num_clusters, cluster_flags);
1825  *
1826  *     if (glyphs != stack_glyphs)
1827  *         cairo_glyph_free (glyphs);
1828  *     if (clusters != stack_clusters)
1829  *         cairo_text_cluster_free (clusters);
1830  * }
1831  * </programlisting></informalexample>
1832  *
1833  * For details of how @clusters, @num_clusters, and @cluster_flags map input
1834  * UTF-8 text to the output glyphs see cairo_show_text_glyphs().
1835  *
1836  * The output values can be readily passed to cairo_show_text_glyphs()
1837  * cairo_show_glyphs(), or related functions, assuming that the exact
1838  * same @scaled_font is used for the operation.
1839  *
1840  * Return value: %CAIRO_STATUS_SUCCESS upon success, or an error status
1841  * if the input values are wrong or if conversion failed.  If the input
1842  * values are correct but the conversion failed, the error status is also
1843  * set on @scaled_font.
1844  *
1845  * Since: 1.8
1846  **/
1847 #define CACHING_THRESHOLD 16
1848 cairo_status_t
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)1849 cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t   *scaled_font,
1850 				  double		 x,
1851 				  double		 y,
1852 				  const char	        *utf8,
1853 				  int		         utf8_len,
1854 				  cairo_glyph_t	       **glyphs,
1855 				  int		        *num_glyphs,
1856 				  cairo_text_cluster_t **clusters,
1857 				  int		        *num_clusters,
1858 				  cairo_text_cluster_flags_t *cluster_flags)
1859 {
1860     int num_chars = 0;
1861     cairo_status_t status;
1862     cairo_glyph_t *orig_glyphs;
1863     cairo_text_cluster_t *orig_clusters;
1864 
1865     status = scaled_font->status;
1866     if (unlikely (status))
1867 	return status;
1868 
1869     /* A slew of sanity checks */
1870 
1871     /* glyphs and num_glyphs can't be NULL */
1872     if (glyphs     == NULL ||
1873 	num_glyphs == NULL) {
1874 	status = _cairo_error (CAIRO_STATUS_NULL_POINTER);
1875 	goto BAIL;
1876     }
1877 
1878     /* Special case for NULL and -1 */
1879     if (utf8 == NULL && utf8_len == -1)
1880 	utf8_len = 0;
1881 
1882     /* No NULLs for non-NULLs! */
1883     if ((utf8_len && utf8          == NULL) ||
1884 	(clusters && num_clusters  == NULL) ||
1885 	(clusters && cluster_flags == NULL)) {
1886 	status = _cairo_error (CAIRO_STATUS_NULL_POINTER);
1887 	goto BAIL;
1888     }
1889 
1890     /* A -1 for utf8_len means NUL-terminated */
1891     if (utf8_len == -1)
1892 	utf8_len = strlen (utf8);
1893 
1894     /* A NULL *glyphs means no prealloced glyphs array */
1895     if (glyphs && *glyphs == NULL)
1896 	*num_glyphs = 0;
1897 
1898     /* A NULL *clusters means no prealloced clusters array */
1899     if (clusters && *clusters == NULL)
1900 	*num_clusters = 0;
1901 
1902     if (!clusters && num_clusters) {
1903 	num_clusters = NULL;
1904     }
1905 
1906     if (cluster_flags) {
1907 	*cluster_flags = FALSE;
1908     }
1909 
1910     if (!clusters && cluster_flags) {
1911 	cluster_flags = NULL;
1912     }
1913 
1914     /* Apart from that, no negatives */
1915     if (utf8_len < 0 ||
1916 	*num_glyphs < 0 ||
1917 	(num_clusters && *num_clusters < 0)) {
1918 	status = _cairo_error (CAIRO_STATUS_NEGATIVE_COUNT);
1919 	goto BAIL;
1920     }
1921 
1922     if (utf8_len == 0) {
1923 	status = CAIRO_STATUS_SUCCESS;
1924 	goto BAIL;
1925     }
1926 
1927     /* validate input so backend does not have to */
1928     status = _cairo_utf8_to_ucs4 (utf8, utf8_len, NULL, &num_chars);
1929     if (unlikely (status))
1930 	goto BAIL;
1931 
1932     _cairo_scaled_font_freeze_cache (scaled_font);
1933 
1934     orig_glyphs = *glyphs;
1935     orig_clusters = clusters ? *clusters : NULL;
1936 
1937     if (scaled_font->backend->text_to_glyphs) {
1938 	status = scaled_font->backend->text_to_glyphs (scaled_font, x, y,
1939 						       utf8, utf8_len,
1940 						       glyphs, num_glyphs,
1941 						       clusters, num_clusters,
1942 						       cluster_flags);
1943         if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
1944 	    if (status == CAIRO_STATUS_SUCCESS) {
1945 	        /* The checks here are crude; we only should do them in
1946 		 * user-font backend, but they don't hurt here.  This stuff
1947 		 * can be hard to get right. */
1948 
1949 	        if (*num_glyphs < 0) {
1950 		    status = _cairo_error (CAIRO_STATUS_NEGATIVE_COUNT);
1951 		    goto DONE;
1952 		}
1953 		if (num_glyphs && *glyphs == NULL) {
1954 		    status = _cairo_error (CAIRO_STATUS_NULL_POINTER);
1955 		    goto DONE;
1956 		}
1957 
1958 		if (clusters) {
1959 		    if (*num_clusters < 0) {
1960 			status = _cairo_error (CAIRO_STATUS_NEGATIVE_COUNT);
1961 			goto DONE;
1962 		    }
1963 		    if (num_clusters && *clusters == NULL) {
1964 			status = _cairo_error (CAIRO_STATUS_NULL_POINTER);
1965 			goto DONE;
1966 		    }
1967 
1968 		    /* Don't trust the backend, validate clusters! */
1969 		    status =
1970 			_cairo_validate_text_clusters (utf8, utf8_len,
1971 						       *glyphs, *num_glyphs,
1972 						       *clusters, *num_clusters,
1973 						       *cluster_flags);
1974 		}
1975 	    }
1976 
1977             goto DONE;
1978 	}
1979     }
1980 
1981     if (*num_glyphs < num_chars) {
1982 	*glyphs = cairo_glyph_allocate (num_chars);
1983 	if (unlikely (*glyphs == NULL)) {
1984 	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1985 	    goto DONE;
1986 	}
1987     }
1988     *num_glyphs = num_chars;
1989 
1990     if (clusters) {
1991 	if (*num_clusters < num_chars) {
1992 	    *clusters = cairo_text_cluster_allocate (num_chars);
1993 	    if (unlikely (*clusters == NULL)) {
1994 		status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1995 		goto DONE;
1996 	    }
1997 	}
1998 	*num_clusters = num_chars;
1999     }
2000 
2001     if (num_chars > CACHING_THRESHOLD)
2002 	status = cairo_scaled_font_text_to_glyphs_internal_cached (scaled_font,
2003 								     x, y,
2004 								     utf8,
2005 								     *glyphs,
2006 								     clusters,
2007 								     num_chars);
2008     else
2009 	status = cairo_scaled_font_text_to_glyphs_internal_uncached (scaled_font,
2010 								   x, y,
2011 								   utf8,
2012 								   *glyphs,
2013 								   clusters,
2014 								   num_chars);
2015 
2016  DONE: /* error that should be logged on scaled_font happened */
2017     _cairo_scaled_font_thaw_cache (scaled_font);
2018 
2019     if (unlikely (status)) {
2020 	*num_glyphs = 0;
2021 	if (*glyphs != orig_glyphs) {
2022 	    cairo_glyph_free (*glyphs);
2023 	    *glyphs = orig_glyphs;
2024 	}
2025 
2026 	if (clusters) {
2027 	    *num_clusters = 0;
2028 	    if (*clusters != orig_clusters) {
2029 		cairo_text_cluster_free (*clusters);
2030 		*clusters = orig_clusters;
2031 	    }
2032 	}
2033     }
2034 
2035     return _cairo_scaled_font_set_error (scaled_font, status);
2036 
2037  BAIL: /* error with input arguments */
2038 
2039     if (num_glyphs)
2040 	*num_glyphs = 0;
2041 
2042     if (num_clusters)
2043 	*num_clusters = 0;
2044 
2045     return status;
2046 }
2047 slim_hidden_def (cairo_scaled_font_text_to_glyphs);
2048 
2049 static inline cairo_bool_t
_range_contains_glyph(const cairo_box_t * extents,cairo_fixed_t left,cairo_fixed_t top,cairo_fixed_t right,cairo_fixed_t bottom)2050 _range_contains_glyph (const cairo_box_t *extents,
2051 		       cairo_fixed_t left,
2052 		       cairo_fixed_t top,
2053 		       cairo_fixed_t right,
2054 		       cairo_fixed_t bottom)
2055 {
2056     return right > extents->p1.x &&
2057 	   left < extents->p2.x &&
2058 	   bottom > extents->p1.y &&
2059 	   top < extents->p2.y;
2060 }
2061 
2062 /*
2063  * Compute a device-space bounding box for the glyphs.
2064  */
2065 cairo_status_t
_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)2066 _cairo_scaled_font_glyph_device_extents (cairo_scaled_font_t	 *scaled_font,
2067 					 const cairo_glyph_t	 *glyphs,
2068 					 int                      num_glyphs,
2069 					 cairo_rectangle_int_t   *extents,
2070 					 cairo_bool_t *overlap_out)
2071 {
2072     cairo_status_t status = CAIRO_STATUS_SUCCESS;
2073     cairo_box_t box = { { INT_MAX, INT_MAX }, { INT_MIN, INT_MIN }};
2074     cairo_scaled_glyph_t *glyph_cache[64];
2075     cairo_bool_t overlap = overlap_out ? FALSE : TRUE;
2076     cairo_round_glyph_positions_t round_glyph_positions = _cairo_font_options_get_round_glyph_positions (&scaled_font->options);
2077     int i;
2078 
2079     if (unlikely (scaled_font->status))
2080 	return scaled_font->status;
2081 
2082     _cairo_scaled_font_freeze_cache (scaled_font);
2083 
2084     memset (glyph_cache, 0, sizeof (glyph_cache));
2085 
2086     for (i = 0; i < num_glyphs; i++) {
2087 	cairo_scaled_glyph_t	*scaled_glyph;
2088 	cairo_fixed_t x, y, x1, y1, x2, y2;
2089 	int cache_index = glyphs[i].index % ARRAY_LENGTH (glyph_cache);
2090 
2091 	scaled_glyph = glyph_cache[cache_index];
2092 	if (scaled_glyph == NULL ||
2093 	    _cairo_scaled_glyph_index (scaled_glyph) != glyphs[i].index)
2094 	{
2095 	    status = _cairo_scaled_glyph_lookup (scaled_font,
2096 						 glyphs[i].index,
2097 						 CAIRO_SCALED_GLYPH_INFO_METRICS,
2098 						 &scaled_glyph);
2099 	    if (unlikely (status))
2100 		break;
2101 
2102 	    glyph_cache[cache_index] = scaled_glyph;
2103 	}
2104 
2105 	if (round_glyph_positions == CAIRO_ROUND_GLYPH_POS_ON)
2106 	    x = _cairo_fixed_from_int (_cairo_lround (glyphs[i].x));
2107 	else
2108 	    x = _cairo_fixed_from_double (glyphs[i].x);
2109 	x1 = x + scaled_glyph->bbox.p1.x;
2110 	x2 = x + scaled_glyph->bbox.p2.x;
2111 
2112 	if (round_glyph_positions == CAIRO_ROUND_GLYPH_POS_ON)
2113 	    y = _cairo_fixed_from_int (_cairo_lround (glyphs[i].y));
2114 	else
2115 	    y = _cairo_fixed_from_double (glyphs[i].y);
2116 	y1 = y + scaled_glyph->bbox.p1.y;
2117 	y2 = y + scaled_glyph->bbox.p2.y;
2118 
2119 	if (overlap == FALSE)
2120 	    overlap = _range_contains_glyph (&box, x1, y1, x2, y2);
2121 
2122 	if (x1 < box.p1.x) box.p1.x = x1;
2123 	if (x2 > box.p2.x) box.p2.x = x2;
2124 	if (y1 < box.p1.y) box.p1.y = y1;
2125 	if (y2 > box.p2.y) box.p2.y = y2;
2126     }
2127 
2128     _cairo_scaled_font_thaw_cache (scaled_font);
2129     if (unlikely (status))
2130 	return _cairo_scaled_font_set_error (scaled_font, status);
2131 
2132     if (box.p1.x < box.p2.x) {
2133 	_cairo_box_round_to_rectangle (&box, extents);
2134     } else {
2135 	extents->x = extents->y = 0;
2136 	extents->width = extents->height = 0;
2137     }
2138 
2139     if (overlap_out != NULL)
2140 	*overlap_out = overlap;
2141 
2142     return CAIRO_STATUS_SUCCESS;
2143 }
2144 
2145 void
_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)2146 _cairo_scaled_font_glyph_approximate_extents (cairo_scaled_font_t	 *scaled_font,
2147 					      const cairo_glyph_t	 *glyphs,
2148 					      int                      num_glyphs,
2149 					      cairo_rectangle_int_t   *extents)
2150 {
2151     double x0 = HUGE_VAL, x1 = -HUGE_VAL;
2152     double y0 = HUGE_VAL, y1 = -HUGE_VAL;
2153     int i;
2154 
2155     for (i = 0; i < num_glyphs; i++) {
2156 	double g;
2157 
2158 	g = glyphs[i].x;
2159 	if (g < x0) x0 = g;
2160 	if (g > x1) x1 = g;
2161 
2162 	g = glyphs[i].y;
2163 	if (g < y0) y0 = g;
2164 	if (g > y1) y1 = g;
2165     }
2166 
2167     if (x0 <= x1 && y0 <= y1) {
2168 	extents->x = floor (x0 - scaled_font->extents.max_x_advance);
2169 	extents->width = ceil (x1 + scaled_font->extents.max_x_advance);
2170 	extents->width -= extents->x;
2171 
2172 	extents->y = floor (y0 - scaled_font->extents.ascent);
2173 	extents->height = ceil (y1 + scaled_font->extents.descent);
2174 	extents->height -= extents->y;
2175     } else {
2176 	extents->x = extents->y = 0;
2177 	extents->width = extents->height = 0;
2178     }
2179 }
2180 
2181 cairo_status_t
_cairo_scaled_font_show_glyphs(cairo_scaled_font_t * scaled_font,cairo_operator_t op,const cairo_pattern_t * pattern,cairo_surface_t * surface,int source_x,int source_y,int dest_x,int dest_y,unsigned int width,unsigned int height,cairo_glyph_t * glyphs,int num_glyphs,cairo_region_t * clip_region)2182 _cairo_scaled_font_show_glyphs (cairo_scaled_font_t	*scaled_font,
2183 				cairo_operator_t	 op,
2184 				const cairo_pattern_t	*pattern,
2185 				cairo_surface_t		*surface,
2186 				int			 source_x,
2187 				int			 source_y,
2188 				int			 dest_x,
2189 				int			 dest_y,
2190 				unsigned int		 width,
2191 				unsigned int		 height,
2192 				cairo_glyph_t		*glyphs,
2193 				int			 num_glyphs,
2194 				cairo_region_t		*clip_region)
2195 {
2196     cairo_status_t status;
2197     cairo_surface_t *mask = NULL;
2198     cairo_format_t mask_format = CAIRO_FORMAT_A1; /* shut gcc up */
2199     cairo_surface_pattern_t mask_pattern;
2200     int i;
2201 
2202     /* These operators aren't interpreted the same way by the backends;
2203      * they are implemented in terms of other operators in cairo-gstate.c
2204      */
2205     assert (op != CAIRO_OPERATOR_SOURCE && op != CAIRO_OPERATOR_CLEAR);
2206 
2207     if (scaled_font->status)
2208 	return scaled_font->status;
2209 
2210     if (!num_glyphs)
2211 	return CAIRO_STATUS_SUCCESS;
2212 
2213     if (scaled_font->backend->show_glyphs != NULL) {
2214 	int remaining_glyphs = num_glyphs;
2215 	status = scaled_font->backend->show_glyphs (scaled_font,
2216 						    op, pattern,
2217 						    surface,
2218 						    source_x, source_y,
2219 						    dest_x, dest_y,
2220 						    width, height,
2221 						    glyphs, num_glyphs,
2222 						    clip_region,
2223 						    &remaining_glyphs);
2224 	glyphs += num_glyphs - remaining_glyphs;
2225 	num_glyphs = remaining_glyphs;
2226 	if (remaining_glyphs == 0)
2227 	    status = CAIRO_STATUS_SUCCESS;
2228 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
2229 	    return _cairo_scaled_font_set_error (scaled_font, status);
2230     }
2231 
2232     /* Font display routine either does not exist or failed. */
2233 
2234     _cairo_scaled_font_freeze_cache (scaled_font);
2235 
2236     for (i = 0; i < num_glyphs; i++) {
2237 	int x, y;
2238 	cairo_image_surface_t *glyph_surface;
2239 	cairo_scaled_glyph_t *scaled_glyph;
2240 
2241 	status = _cairo_scaled_glyph_lookup (scaled_font,
2242 					     glyphs[i].index,
2243 					     CAIRO_SCALED_GLYPH_INFO_SURFACE,
2244 					     &scaled_glyph);
2245 
2246 	if (unlikely (status))
2247 	    goto CLEANUP_MASK;
2248 
2249 	glyph_surface = scaled_glyph->surface;
2250 
2251 	/* To start, create the mask using the format from the first
2252 	 * glyph. Later we'll deal with different formats. */
2253 	if (mask == NULL) {
2254 	    mask_format = glyph_surface->format;
2255 	    mask = cairo_image_surface_create (mask_format, width, height);
2256 	    status = mask->status;
2257 	    if (unlikely (status))
2258 		goto CLEANUP_MASK;
2259 	}
2260 
2261 	/* If we have glyphs of different formats, we "upgrade" the mask
2262 	 * to the wider of the formats. */
2263 	if (glyph_surface->format != mask_format &&
2264 	    _cairo_format_bits_per_pixel (mask_format) <
2265 	    _cairo_format_bits_per_pixel (glyph_surface->format) )
2266 	{
2267 	    cairo_surface_t *new_mask;
2268 
2269 	    switch (glyph_surface->format) {
2270 	    case CAIRO_FORMAT_ARGB32:
2271 	    case CAIRO_FORMAT_A8:
2272 	    case CAIRO_FORMAT_A1:
2273 		mask_format = glyph_surface->format;
2274 		break;
2275 	    case CAIRO_FORMAT_RGB16_565:
2276 	    case CAIRO_FORMAT_RGB24:
2277 	    case CAIRO_FORMAT_INVALID:
2278 	    default:
2279 		ASSERT_NOT_REACHED;
2280 		mask_format = CAIRO_FORMAT_ARGB32;
2281 		break;
2282 	    }
2283 
2284 	    new_mask = cairo_image_surface_create (mask_format, width, height);
2285 	    status = new_mask->status;
2286 	    if (unlikely (status)) {
2287 		cairo_surface_destroy (new_mask);
2288 		goto CLEANUP_MASK;
2289 	    }
2290 
2291 	    _cairo_pattern_init_for_surface (&mask_pattern, mask);
2292 	    /* Note that we only upgrade masks, i.e. A1 -> A8 -> ARGB32, so there is
2293 	     * never any component alpha here.
2294 	     */
2295 	    status = _cairo_surface_composite (CAIRO_OPERATOR_ADD,
2296 					       &_cairo_pattern_white.base,
2297 					       &mask_pattern.base,
2298 					       new_mask,
2299 					       0, 0,
2300 					       0, 0,
2301 					       0, 0,
2302 					       width, height,
2303 					       NULL);
2304 
2305 	    _cairo_pattern_fini (&mask_pattern.base);
2306 
2307 	    if (unlikely (status)) {
2308 		cairo_surface_destroy (new_mask);
2309 		goto CLEANUP_MASK;
2310 	    }
2311 
2312 	    cairo_surface_destroy (mask);
2313 	    mask = new_mask;
2314 	}
2315 
2316 	if (glyph_surface->width && glyph_surface->height) {
2317 	    cairo_surface_pattern_t glyph_pattern;
2318 
2319 	    /* round glyph locations to the nearest pixel */
2320 	    /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
2321 	    x = _cairo_lround (glyphs[i].x -
2322 			       glyph_surface->base.device_transform.x0);
2323 	    y = _cairo_lround (glyphs[i].y -
2324 			       glyph_surface->base.device_transform.y0);
2325 
2326 	    _cairo_pattern_init_for_surface (&glyph_pattern,
2327 					     &glyph_surface->base);
2328 	    if (mask_format == CAIRO_FORMAT_ARGB32)
2329 		glyph_pattern.base.has_component_alpha = TRUE;
2330 
2331 	    status = _cairo_surface_composite (CAIRO_OPERATOR_ADD,
2332 					       &_cairo_pattern_white.base,
2333 					       &glyph_pattern.base,
2334 					       mask,
2335 					       0, 0,
2336 					       0, 0,
2337 					       x - dest_x, y - dest_y,
2338 					       glyph_surface->width,
2339 					       glyph_surface->height,
2340 					       NULL);
2341 
2342 	    _cairo_pattern_fini (&glyph_pattern.base);
2343 
2344 	    if (unlikely (status))
2345 		goto CLEANUP_MASK;
2346 	}
2347     }
2348 
2349     _cairo_pattern_init_for_surface (&mask_pattern, mask);
2350     if (mask_format == CAIRO_FORMAT_ARGB32)
2351 	mask_pattern.base.has_component_alpha = TRUE;
2352 
2353     status = _cairo_surface_composite (op, pattern, &mask_pattern.base,
2354 				       surface,
2355 				       source_x, source_y,
2356 				       0,        0,
2357 				       dest_x,   dest_y,
2358 				       width,    height,
2359 				       clip_region);
2360 
2361     _cairo_pattern_fini (&mask_pattern.base);
2362 
2363 CLEANUP_MASK:
2364     _cairo_scaled_font_thaw_cache (scaled_font);
2365 
2366     if (mask != NULL)
2367 	cairo_surface_destroy (mask);
2368     return _cairo_scaled_font_set_error (scaled_font, status);
2369 }
2370 
2371 /* Add a single-device-unit rectangle to a path. */
2372 static cairo_status_t
_add_unit_rectangle_to_path(cairo_path_fixed_t * path,cairo_fixed_t x,cairo_fixed_t y)2373 _add_unit_rectangle_to_path (cairo_path_fixed_t *path,
2374 			     cairo_fixed_t x,
2375 			     cairo_fixed_t y)
2376 {
2377     cairo_status_t status;
2378 
2379     status = _cairo_path_fixed_move_to (path, x, y);
2380     if (unlikely (status))
2381 	return status;
2382 
2383     status = _cairo_path_fixed_rel_line_to (path,
2384 					    _cairo_fixed_from_int (1),
2385 					    _cairo_fixed_from_int (0));
2386     if (unlikely (status))
2387 	return status;
2388 
2389     status = _cairo_path_fixed_rel_line_to (path,
2390 					    _cairo_fixed_from_int (0),
2391 					    _cairo_fixed_from_int (1));
2392     if (unlikely (status))
2393 	return status;
2394 
2395     status = _cairo_path_fixed_rel_line_to (path,
2396 					    _cairo_fixed_from_int (-1),
2397 					    _cairo_fixed_from_int (0));
2398     if (unlikely (status))
2399 	return status;
2400 
2401     return _cairo_path_fixed_close_path (path);
2402 }
2403 
2404 /**
2405  * _trace_mask_to_path:
2406  * @bitmap: An alpha mask (either %CAIRO_FORMAT_A1 or %CAIRO_FORMAT_A8)
2407  * @path: An initialized path to hold the result
2408  *
2409  * Given a mask surface, (an alpha image), fill out the provided path
2410  * so that when filled it would result in something that approximates
2411  * the mask.
2412  *
2413  * Note: The current tracing code here is extremely primitive. It
2414  * operates only on an A1 surface, (converting an A8 surface to A1 if
2415  * necessary), and performs the tracing by drawing a little square
2416  * around each pixel that is on in the mask. We do not pretend that
2417  * this is a high-quality result. But we are leaving it up to someone
2418  * who cares enough about getting a better result to implement
2419  * something more sophisticated.
2420  **/
2421 static cairo_status_t
_trace_mask_to_path(cairo_image_surface_t * mask,cairo_path_fixed_t * path,double tx,double ty)2422 _trace_mask_to_path (cairo_image_surface_t *mask,
2423 		     cairo_path_fixed_t *path,
2424 		     double tx, double ty)
2425 {
2426     const uint8_t *row;
2427     int rows, cols, bytes_per_row;
2428     int x, y, bit;
2429     double xoff, yoff;
2430     cairo_fixed_t x0, y0;
2431     cairo_fixed_t px, py;
2432     cairo_status_t status;
2433 
2434     mask = _cairo_image_surface_coerce_to_format (mask, CAIRO_FORMAT_A1);
2435     status = mask->base.status;
2436     if (unlikely (status))
2437 	return status;
2438 
2439     cairo_surface_get_device_offset (&mask->base, &xoff, &yoff);
2440     x0 = _cairo_fixed_from_double (tx - xoff);
2441     y0 = _cairo_fixed_from_double (ty - yoff);
2442 
2443     bytes_per_row = (mask->width + 7) / 8;
2444     row = mask->data;
2445     for (y = 0, rows = mask->height; rows--; row += mask->stride, y++) {
2446 	const uint8_t *byte_ptr = row;
2447 	x = 0;
2448 	py = _cairo_fixed_from_int (y);
2449 	for (cols = bytes_per_row; cols--; ) {
2450 	    uint8_t byte = *byte_ptr++;
2451 	    if (byte == 0) {
2452 		x += 8;
2453 		continue;
2454 	    }
2455 
2456 	    byte = CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (byte);
2457 	    for (bit = 1 << 7; bit && x < mask->width; bit >>= 1, x++) {
2458 		if (byte & bit) {
2459 		    px = _cairo_fixed_from_int (x);
2460 		    status = _add_unit_rectangle_to_path (path,
2461 							  px + x0,
2462 							  py + y0);
2463 		    if (unlikely (status))
2464 			goto BAIL;
2465 		}
2466 	    }
2467 	}
2468     }
2469 
2470 BAIL:
2471     cairo_surface_destroy (&mask->base);
2472 
2473     return status;
2474 }
2475 
2476 cairo_status_t
_cairo_scaled_font_glyph_path(cairo_scaled_font_t * scaled_font,const cairo_glyph_t * glyphs,int num_glyphs,cairo_path_fixed_t * path)2477 _cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font,
2478 			       const cairo_glyph_t *glyphs,
2479 			       int		    num_glyphs,
2480 			       cairo_path_fixed_t  *path)
2481 {
2482     cairo_status_t status;
2483     int	i;
2484 
2485     status = scaled_font->status;
2486     if (unlikely (status))
2487 	return status;
2488 
2489     _cairo_scaled_font_freeze_cache (scaled_font);
2490     for (i = 0; i < num_glyphs; i++) {
2491 	cairo_scaled_glyph_t *scaled_glyph;
2492 
2493 	status = _cairo_scaled_glyph_lookup (scaled_font,
2494 					     glyphs[i].index,
2495 					     CAIRO_SCALED_GLYPH_INFO_PATH,
2496 					     &scaled_glyph);
2497 	if (status == CAIRO_STATUS_SUCCESS) {
2498 	    status = _cairo_path_fixed_append (path,
2499 					       scaled_glyph->path, CAIRO_DIRECTION_FORWARD,
2500 					       _cairo_fixed_from_double (glyphs[i].x),
2501 					       _cairo_fixed_from_double (glyphs[i].y));
2502 
2503 	} else if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
2504 	    /* If the font is incapable of providing a path, then we'll
2505 	     * have to trace our own from a surface.
2506 	     */
2507 	    status = _cairo_scaled_glyph_lookup (scaled_font,
2508 						 glyphs[i].index,
2509 						 CAIRO_SCALED_GLYPH_INFO_SURFACE,
2510 						 &scaled_glyph);
2511 	    if (unlikely (status))
2512 		goto BAIL;
2513 
2514 	    status = _trace_mask_to_path (scaled_glyph->surface, path,
2515 					  glyphs[i].x, glyphs[i].y);
2516 	}
2517 
2518 	if (unlikely (status))
2519 	    goto BAIL;
2520     }
2521   BAIL:
2522     _cairo_scaled_font_thaw_cache (scaled_font);
2523 
2524     return _cairo_scaled_font_set_error (scaled_font, status);
2525 }
2526 
2527 /**
2528  * _cairo_scaled_glyph_set_metrics:
2529  * @scaled_glyph: a #cairo_scaled_glyph_t
2530  * @scaled_font: a #cairo_scaled_font_t
2531  * @fs_metrics: a #cairo_text_extents_t in font space
2532  *
2533  * _cairo_scaled_glyph_set_metrics() stores user space metrics
2534  * for the specified glyph given font space metrics. It is
2535  * called by the font backend when initializing a glyph with
2536  * %CAIRO_SCALED_GLYPH_INFO_METRICS.
2537  **/
2538 void
_cairo_scaled_glyph_set_metrics(cairo_scaled_glyph_t * scaled_glyph,cairo_scaled_font_t * scaled_font,cairo_text_extents_t * fs_metrics)2539 _cairo_scaled_glyph_set_metrics (cairo_scaled_glyph_t *scaled_glyph,
2540 				 cairo_scaled_font_t *scaled_font,
2541 				 cairo_text_extents_t *fs_metrics)
2542 {
2543     cairo_bool_t first = TRUE;
2544     double hm, wm;
2545     double min_user_x = 0.0, max_user_x = 0.0, min_user_y = 0.0, max_user_y = 0.0;
2546     double min_device_x = 0.0, max_device_x = 0.0, min_device_y = 0.0, max_device_y = 0.0;
2547     double device_x_advance, device_y_advance;
2548 
2549     scaled_glyph->fs_metrics = *fs_metrics;
2550 
2551     for (hm = 0.0; hm <= 1.0; hm += 1.0)
2552 	for (wm = 0.0; wm <= 1.0; wm += 1.0) {
2553 	    double x, y;
2554 
2555 	    /* Transform this corner to user space */
2556 	    x = fs_metrics->x_bearing + fs_metrics->width * wm;
2557 	    y = fs_metrics->y_bearing + fs_metrics->height * hm;
2558 	    cairo_matrix_transform_point (&scaled_font->font_matrix,
2559 					  &x, &y);
2560 	    if (first) {
2561 		min_user_x = max_user_x = x;
2562 		min_user_y = max_user_y = y;
2563 	    } else {
2564 		if (x < min_user_x) min_user_x = x;
2565 		if (x > max_user_x) max_user_x = x;
2566 		if (y < min_user_y) min_user_y = y;
2567 		if (y > max_user_y) max_user_y = y;
2568 	    }
2569 
2570 	    /* Transform this corner to device space from glyph origin */
2571 	    x = fs_metrics->x_bearing + fs_metrics->width * wm;
2572 	    y = fs_metrics->y_bearing + fs_metrics->height * hm;
2573 	    cairo_matrix_transform_distance (&scaled_font->scale,
2574 					     &x, &y);
2575 
2576 	    if (first) {
2577 		min_device_x = max_device_x = x;
2578 		min_device_y = max_device_y = y;
2579 	    } else {
2580 		if (x < min_device_x) min_device_x = x;
2581 		if (x > max_device_x) max_device_x = x;
2582 		if (y < min_device_y) min_device_y = y;
2583 		if (y > max_device_y) max_device_y = y;
2584 	    }
2585 	    first = FALSE;
2586 	}
2587     scaled_glyph->metrics.x_bearing = min_user_x;
2588     scaled_glyph->metrics.y_bearing = min_user_y;
2589     scaled_glyph->metrics.width = max_user_x - min_user_x;
2590     scaled_glyph->metrics.height = max_user_y - min_user_y;
2591 
2592     scaled_glyph->metrics.x_advance = fs_metrics->x_advance;
2593     scaled_glyph->metrics.y_advance = fs_metrics->y_advance;
2594     cairo_matrix_transform_distance (&scaled_font->font_matrix,
2595 				     &scaled_glyph->metrics.x_advance,
2596 				     &scaled_glyph->metrics.y_advance);
2597 
2598     device_x_advance = fs_metrics->x_advance;
2599     device_y_advance = fs_metrics->y_advance;
2600     cairo_matrix_transform_distance (&scaled_font->scale,
2601 				     &device_x_advance,
2602 				     &device_y_advance);
2603 
2604     scaled_glyph->bbox.p1.x = _cairo_fixed_from_double (min_device_x);
2605     scaled_glyph->bbox.p1.y = _cairo_fixed_from_double (min_device_y);
2606     scaled_glyph->bbox.p2.x = _cairo_fixed_from_double (max_device_x);
2607     scaled_glyph->bbox.p2.y = _cairo_fixed_from_double (max_device_y);
2608 
2609     scaled_glyph->x_advance = _cairo_lround (device_x_advance);
2610     scaled_glyph->y_advance = _cairo_lround (device_y_advance);
2611 
2612     scaled_glyph->has_info |= CAIRO_SCALED_GLYPH_INFO_METRICS;
2613 }
2614 
2615 void
_cairo_scaled_glyph_set_surface(cairo_scaled_glyph_t * scaled_glyph,cairo_scaled_font_t * scaled_font,cairo_image_surface_t * surface)2616 _cairo_scaled_glyph_set_surface (cairo_scaled_glyph_t *scaled_glyph,
2617 				 cairo_scaled_font_t *scaled_font,
2618 				 cairo_image_surface_t *surface)
2619 {
2620     if (scaled_glyph->surface != NULL)
2621 	cairo_surface_destroy (&scaled_glyph->surface->base);
2622 
2623     /* sanity check the backend glyph contents */
2624     _cairo_debug_check_image_surface_is_defined (&surface->base);
2625     scaled_glyph->surface = surface;
2626 
2627     if (surface != NULL)
2628 	scaled_glyph->has_info |= CAIRO_SCALED_GLYPH_INFO_SURFACE;
2629     else
2630 	scaled_glyph->has_info &= ~CAIRO_SCALED_GLYPH_INFO_SURFACE;
2631 }
2632 
2633 void
_cairo_scaled_glyph_set_path(cairo_scaled_glyph_t * scaled_glyph,cairo_scaled_font_t * scaled_font,cairo_path_fixed_t * path)2634 _cairo_scaled_glyph_set_path (cairo_scaled_glyph_t *scaled_glyph,
2635 			      cairo_scaled_font_t *scaled_font,
2636 			      cairo_path_fixed_t *path)
2637 {
2638     if (scaled_glyph->path != NULL)
2639 	_cairo_path_fixed_destroy (scaled_glyph->path);
2640 
2641     scaled_glyph->path = path;
2642 
2643     if (path != NULL)
2644 	scaled_glyph->has_info |= CAIRO_SCALED_GLYPH_INFO_PATH;
2645     else
2646 	scaled_glyph->has_info &= ~CAIRO_SCALED_GLYPH_INFO_PATH;
2647 }
2648 
2649 void
_cairo_scaled_glyph_set_recording_surface(cairo_scaled_glyph_t * scaled_glyph,cairo_scaled_font_t * scaled_font,cairo_surface_t * recording_surface)2650 _cairo_scaled_glyph_set_recording_surface (cairo_scaled_glyph_t *scaled_glyph,
2651 					   cairo_scaled_font_t *scaled_font,
2652 					   cairo_surface_t *recording_surface)
2653 {
2654     if (scaled_glyph->recording_surface != NULL) {
2655 	cairo_surface_finish (scaled_glyph->recording_surface);
2656 	cairo_surface_destroy (scaled_glyph->recording_surface);
2657     }
2658 
2659     scaled_glyph->recording_surface = recording_surface;
2660 
2661     if (recording_surface != NULL)
2662 	scaled_glyph->has_info |= CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE;
2663     else
2664 	scaled_glyph->has_info &= ~CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE;
2665 }
2666 
2667 static cairo_bool_t
_cairo_scaled_glyph_page_can_remove(const void * closure)2668 _cairo_scaled_glyph_page_can_remove (const void *closure)
2669 {
2670     const cairo_scaled_glyph_page_t *page = closure;
2671     const cairo_scaled_font_t *scaled_font;
2672 
2673     scaled_font = (cairo_scaled_font_t *) page->cache_entry.hash;
2674     return scaled_font->cache_frozen == 0;
2675 }
2676 
2677 static cairo_status_t
_cairo_scaled_font_allocate_glyph(cairo_scaled_font_t * scaled_font,cairo_scaled_glyph_t ** scaled_glyph)2678 _cairo_scaled_font_allocate_glyph (cairo_scaled_font_t *scaled_font,
2679 				   cairo_scaled_glyph_t **scaled_glyph)
2680 {
2681     cairo_scaled_glyph_page_t *page;
2682     cairo_status_t status;
2683 
2684     /* only the first page in the list may contain available slots */
2685     if (! cairo_list_is_empty (&scaled_font->glyph_pages)) {
2686         page = cairo_list_last_entry (&scaled_font->glyph_pages,
2687                                       cairo_scaled_glyph_page_t,
2688                                       link);
2689         if (page->num_glyphs < CAIRO_SCALED_GLYPH_PAGE_SIZE) {
2690             *scaled_glyph = &page->glyphs[page->num_glyphs++];
2691             return CAIRO_STATUS_SUCCESS;
2692         }
2693     }
2694 
2695     page = malloc (sizeof (cairo_scaled_glyph_page_t));
2696     if (unlikely (page == NULL))
2697 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2698 
2699     page->cache_entry.hash = (uintptr_t) scaled_font;
2700     page->cache_entry.size = 1; /* XXX occupancy weighting? */
2701     page->num_glyphs = 0;
2702 
2703     CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex);
2704     if (scaled_font->global_cache_frozen == FALSE) {
2705 	if (unlikely (cairo_scaled_glyph_page_cache.hash_table == NULL)) {
2706 	    status = _cairo_cache_init (&cairo_scaled_glyph_page_cache,
2707 					NULL,
2708 					_cairo_scaled_glyph_page_can_remove,
2709 					_cairo_scaled_glyph_page_destroy,
2710 					MAX_GLYPH_PAGES_CACHED);
2711 	    if (unlikely (status)) {
2712 		CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex);
2713 		free (page);
2714 		return status;
2715 	    }
2716 	}
2717 
2718 	_cairo_cache_freeze (&cairo_scaled_glyph_page_cache);
2719 	scaled_font->global_cache_frozen = TRUE;
2720     }
2721 
2722     status = _cairo_cache_insert (&cairo_scaled_glyph_page_cache,
2723 				  &page->cache_entry);
2724     CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex);
2725     if (unlikely (status)) {
2726 	free (page);
2727 	return status;
2728     }
2729 
2730     cairo_list_add_tail (&page->link, &scaled_font->glyph_pages);
2731 
2732     *scaled_glyph = &page->glyphs[page->num_glyphs++];
2733     return CAIRO_STATUS_SUCCESS;
2734 }
2735 
2736 static void
_cairo_scaled_font_free_last_glyph(cairo_scaled_font_t * scaled_font,cairo_scaled_glyph_t * scaled_glyph)2737 _cairo_scaled_font_free_last_glyph (cairo_scaled_font_t *scaled_font,
2738 			           cairo_scaled_glyph_t *scaled_glyph)
2739 {
2740     cairo_scaled_glyph_page_t *page;
2741 
2742     assert (! cairo_list_is_empty (&scaled_font->glyph_pages));
2743     page = cairo_list_last_entry (&scaled_font->glyph_pages,
2744                                   cairo_scaled_glyph_page_t,
2745                                   link);
2746     assert (scaled_glyph == &page->glyphs[page->num_glyphs-1]);
2747 
2748     _cairo_scaled_glyph_fini (scaled_font, scaled_glyph);
2749 
2750     if (--page->num_glyphs == 0) {
2751 	_cairo_cache_remove (&cairo_scaled_glyph_page_cache,
2752 		             &page->cache_entry);
2753     }
2754 }
2755 
2756 /**
2757  * _cairo_scaled_glyph_lookup:
2758  * @scaled_font: a #cairo_scaled_font_t
2759  * @index: the glyph to create
2760  * @info: a #cairo_scaled_glyph_info_t marking which portions of
2761  * the glyph should be filled in.
2762  * @scaled_glyph_ret: a #cairo_scaled_glyph_t where the glyph
2763  * is returned.
2764  *
2765  * If the desired info is not available, (for example, when trying to
2766  * get INFO_PATH with a bitmapped font), this function will return
2767  * %CAIRO_INT_STATUS_UNSUPPORTED.
2768  *
2769  * Note: This function must be called with the scaled font frozen, and it must
2770  * remain frozen for as long as the @scaled_glyph_ret is alive. (If the scaled
2771  * font was not frozen, then there is no guarantee that the glyph would not be
2772  * evicted before you tried to access it.) See
2773  * _cairo_scaled_font_freeze_cache() and _cairo_scaled_font_thaw_cache().
2774  *
2775  * Returns: a glyph with the requested portions filled in. Glyph
2776  * lookup is cached and glyph will be automatically freed along
2777  * with the scaled_font so no explicit free is required.
2778  * @info can be one or more of:
2779  *  %CAIRO_SCALED_GLYPH_INFO_METRICS - glyph metrics and bounding box
2780  *  %CAIRO_SCALED_GLYPH_INFO_SURFACE - surface holding glyph image
2781  *  %CAIRO_SCALED_GLYPH_INFO_PATH - path holding glyph outline in device space
2782  **/
2783 cairo_int_status_t
_cairo_scaled_glyph_lookup(cairo_scaled_font_t * scaled_font,unsigned long index,cairo_scaled_glyph_info_t info,cairo_scaled_glyph_t ** scaled_glyph_ret)2784 _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font,
2785 			    unsigned long index,
2786 			    cairo_scaled_glyph_info_t info,
2787 			    cairo_scaled_glyph_t **scaled_glyph_ret)
2788 {
2789     cairo_status_t		 status = CAIRO_STATUS_SUCCESS;
2790     cairo_scaled_glyph_t	*scaled_glyph;
2791     cairo_scaled_glyph_info_t	 need_info;
2792 
2793     *scaled_glyph_ret = NULL;
2794 
2795     if (unlikely (scaled_font->status))
2796 	return scaled_font->status;
2797 
2798     if (CAIRO_INJECT_FAULT ())
2799 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2800 
2801     /*
2802      * Check cache for glyph
2803      */
2804     scaled_glyph = _cairo_hash_table_lookup (scaled_font->glyphs,
2805 					     (cairo_hash_entry_t *) &index);
2806     if (scaled_glyph == NULL) {
2807 	status = _cairo_scaled_font_allocate_glyph (scaled_font, &scaled_glyph);
2808 	if (unlikely (status))
2809 	    goto err;
2810 
2811 	memset (scaled_glyph, 0, sizeof (cairo_scaled_glyph_t));
2812 	_cairo_scaled_glyph_set_index (scaled_glyph, index);
2813 
2814 	/* ask backend to initialize metrics and shape fields */
2815 	status =
2816 	    scaled_font->backend->scaled_glyph_init (scaled_font,
2817 						     scaled_glyph,
2818 						     info | CAIRO_SCALED_GLYPH_INFO_METRICS);
2819 	if (unlikely (status)) {
2820 	    _cairo_scaled_font_free_last_glyph (scaled_font, scaled_glyph);
2821 	    goto err;
2822 	}
2823 
2824 	status = _cairo_hash_table_insert (scaled_font->glyphs,
2825 					   &scaled_glyph->hash_entry);
2826 	if (unlikely (status)) {
2827 	    _cairo_scaled_font_free_last_glyph (scaled_font, scaled_glyph);
2828 	    goto err;
2829 	}
2830     }
2831 
2832     /*
2833      * Check and see if the glyph, as provided,
2834      * already has the requested data and amend it if not
2835      */
2836     need_info = info & ~scaled_glyph->has_info;
2837     if (need_info) {
2838 	status = scaled_font->backend->scaled_glyph_init (scaled_font,
2839 							  scaled_glyph,
2840 							  need_info);
2841 	if (unlikely (status))
2842 	    goto err;
2843 
2844 	/* Don't trust the scaled_glyph_init() return value, the font
2845 	 * backend may not even know about some of the info.  For example,
2846 	 * no backend other than the user-fonts knows about recording-surface
2847 	 * glyph info. */
2848 	if (info & ~scaled_glyph->has_info)
2849 	    return CAIRO_INT_STATUS_UNSUPPORTED;
2850     }
2851 
2852     *scaled_glyph_ret = scaled_glyph;
2853     return CAIRO_STATUS_SUCCESS;
2854 
2855 err:
2856     /* It's not an error for the backend to not support the info we want. */
2857     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
2858 	status = _cairo_scaled_font_set_error (scaled_font, status);
2859     return status;
2860 }
2861 
2862 double
_cairo_scaled_font_get_max_scale(cairo_scaled_font_t * scaled_font)2863 _cairo_scaled_font_get_max_scale (cairo_scaled_font_t *scaled_font)
2864 {
2865     return scaled_font->max_scale;
2866 }
2867 
2868 
2869 /**
2870  * cairo_scaled_font_get_font_face:
2871  * @scaled_font: a #cairo_scaled_font_t
2872  *
2873  * Gets the font face that this scaled font uses.  This is the
2874  * font face passed to cairo_scaled_font_create().
2875  *
2876  * Return value: The #cairo_font_face_t with which @scaled_font was
2877  * created.
2878  *
2879  * Since: 1.2
2880  **/
2881 cairo_font_face_t *
cairo_scaled_font_get_font_face(cairo_scaled_font_t * scaled_font)2882 cairo_scaled_font_get_font_face (cairo_scaled_font_t *scaled_font)
2883 {
2884     if (scaled_font->status)
2885 	return (cairo_font_face_t*) &_cairo_font_face_nil;
2886 
2887     if (scaled_font->original_font_face != NULL)
2888 	return scaled_font->original_font_face;
2889 
2890     return scaled_font->font_face;
2891 }
2892 slim_hidden_def (cairo_scaled_font_get_font_face);
2893 
2894 /**
2895  * cairo_scaled_font_get_font_matrix:
2896  * @scaled_font: a #cairo_scaled_font_t
2897  * @font_matrix: return value for the matrix
2898  *
2899  * Stores the font matrix with which @scaled_font was created into
2900  * @matrix.
2901  *
2902  * Since: 1.2
2903  **/
2904 void
cairo_scaled_font_get_font_matrix(cairo_scaled_font_t * scaled_font,cairo_matrix_t * font_matrix)2905 cairo_scaled_font_get_font_matrix (cairo_scaled_font_t	*scaled_font,
2906 				   cairo_matrix_t	*font_matrix)
2907 {
2908     if (scaled_font->status) {
2909 	cairo_matrix_init_identity (font_matrix);
2910 	return;
2911     }
2912 
2913     *font_matrix = scaled_font->font_matrix;
2914 }
2915 slim_hidden_def (cairo_scaled_font_get_font_matrix);
2916 
2917 /**
2918  * cairo_scaled_font_get_ctm:
2919  * @scaled_font: a #cairo_scaled_font_t
2920  * @ctm: return value for the CTM
2921  *
2922  * Stores the CTM with which @scaled_font was created into @ctm.
2923  * Note that the translation offsets (x0, y0) of the CTM are ignored
2924  * by cairo_scaled_font_create().  So, the matrix this
2925  * function returns always has 0,0 as x0,y0.
2926  *
2927  * Since: 1.2
2928  **/
2929 void
cairo_scaled_font_get_ctm(cairo_scaled_font_t * scaled_font,cairo_matrix_t * ctm)2930 cairo_scaled_font_get_ctm (cairo_scaled_font_t	*scaled_font,
2931 			   cairo_matrix_t	*ctm)
2932 {
2933     if (scaled_font->status) {
2934 	cairo_matrix_init_identity (ctm);
2935 	return;
2936     }
2937 
2938     *ctm = scaled_font->ctm;
2939 }
2940 slim_hidden_def (cairo_scaled_font_get_ctm);
2941 
2942 /**
2943  * cairo_scaled_font_get_scale_matrix:
2944  * @scaled_font: a #cairo_scaled_font_t
2945  * @scale_matrix: return value for the matrix
2946  *
2947  * Stores the scale matrix of @scaled_font into @matrix.
2948  * The scale matrix is product of the font matrix and the ctm
2949  * associated with the scaled font, and hence is the matrix mapping from
2950  * font space to device space.
2951  *
2952  * Since: 1.8
2953  **/
2954 void
cairo_scaled_font_get_scale_matrix(cairo_scaled_font_t * scaled_font,cairo_matrix_t * scale_matrix)2955 cairo_scaled_font_get_scale_matrix (cairo_scaled_font_t	*scaled_font,
2956 				    cairo_matrix_t	*scale_matrix)
2957 {
2958     if (scaled_font->status) {
2959 	cairo_matrix_init_identity (scale_matrix);
2960 	return;
2961     }
2962 
2963     *scale_matrix = scaled_font->scale;
2964 }
2965 
2966 /**
2967  * cairo_scaled_font_get_font_options:
2968  * @scaled_font: a #cairo_scaled_font_t
2969  * @options: return value for the font options
2970  *
2971  * Stores the font options with which @scaled_font was created into
2972  * @options.
2973  *
2974  * Since: 1.2
2975  **/
2976 void
cairo_scaled_font_get_font_options(cairo_scaled_font_t * scaled_font,cairo_font_options_t * options)2977 cairo_scaled_font_get_font_options (cairo_scaled_font_t		*scaled_font,
2978 				    cairo_font_options_t	*options)
2979 {
2980     if (cairo_font_options_status (options))
2981 	return;
2982 
2983     if (scaled_font->status) {
2984 	_cairo_font_options_init_default (options);
2985 	return;
2986     }
2987 
2988     _cairo_font_options_init_copy (options, &scaled_font->options);
2989 }
2990 slim_hidden_def (cairo_scaled_font_get_font_options);
2991 
2992 /**
2993  * cairo_scaled_font_get_hint_metrics:
2994  * @scaled_font: a #cairo_scaled_font_t
2995  *
2996  * Mozilla extension since the required malloc/free to use
2997  * cairo_scaled_font_get_font_options() above is too slow.
2998  **/
2999 cairo_public cairo_hint_metrics_t
cairo_scaled_font_get_hint_metrics(cairo_scaled_font_t * scaled_font)3000 cairo_scaled_font_get_hint_metrics (cairo_scaled_font_t		*scaled_font)
3001 {
3002     cairo_font_options_t options;
3003     if (scaled_font->status) {
3004 	_cairo_font_options_init_default (&options);
3005     } else {
3006 	_cairo_font_options_init_copy (&options, &scaled_font->options);
3007     }
3008     return options.hint_metrics;
3009 }
3010 slim_hidden_def (cairo_scaled_font_get_hint_metrics);
3011