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 * &glyphs, &num_glyphs,
1870 * &clusters, &num_clusters, &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 * &glyphs, &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 * &glyphs, &num_glyphs,
1920 * &clusters, &num_clusters, &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