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