1 /* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
3 * Copyright © 2005 Keith Packard
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.
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
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/
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.
28 * The Original Code is the cairo graphics library.
30 * The Initial Developer of the Original Code is Keith Packard
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>
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"
49 #define TOLERANCE 0.00001
51 #if _XOPEN_SOURCE >= 600 || defined (_ISOC99_SOURCE)
52 #define ISFINITE(x) isfinite (x)
54 #define ISFINITE(x) ((x) * (x) >= 0.) /* check for NaNs */
58 * SECTION:cairo-scaled-font
59 * @Title: cairo_scaled_font_t
60 * @Short_Description: Font face at particular size and options
61 * @See_Also: #cairo_font_face_t, #cairo_matrix_t, #cairo_font_options_t
63 * #cairo_scaled_font_t represents a realization of a font face at a particular
64 * size and transformation and a certain set of font options.
68 _cairo_scaled_font_compute_hash (cairo_scaled_font_t *scaled_font);
72 * We maintain a global pool of glyphs split between all active fonts. This
73 * allows a heavily used individual font to cache more glyphs than we could
74 * manage if we used per-font glyph caches, but at the same time maintains
75 * fairness across all fonts and provides a cap on the maximum number of
78 * The glyphs are allocated in pages, which are capped in the global pool.
79 * Using pages means we can reduce the frequency at which we have to probe the
80 * global pool and ameliorates the memory allocation pressure.
83 /* XXX: This number is arbitrary---we've never done any measurement of this. */
84 #define MAX_GLYPH_PAGES_CACHED 512
85 static cairo_cache_t cairo_scaled_glyph_page_cache;
87 #define CAIRO_SCALED_GLYPH_PAGE_SIZE 32
88 struct _cairo_scaled_glyph_page {
89 cairo_cache_entry_t cache_entry;
93 unsigned int num_glyphs;
94 cairo_scaled_glyph_t glyphs[CAIRO_SCALED_GLYPH_PAGE_SIZE];
100 * To store rasterizations of glyphs, we use an image surface and the
101 * device offset to represent the glyph origin.
103 * A device_transform converts from device space (a conceptual space) to
104 * surface space. For simple cases of translation only, it's called a
105 * device_offset and is public API (cairo_surface_[gs]et_device_offset()).
106 * A possibly better name for those functions could have been
107 * cairo_surface_[gs]et_origin(). So, that's what they do: they set where
108 * the device-space origin (0,0) is in the surface. If the origin is inside
109 * the surface, device_offset values are positive. It may look like this:
112 * (-x,-y) <-- negative numbers
116 * |......(0,0) <---|-- device-space origin
123 * (0,0) <-- surface-space origin
127 * |......(x,y) <--|-- device_offset
133 * In other words: device_offset is the coordinates of the device-space
134 * origin relative to the top-left of the surface.
136 * We use device offsets in a couple of places:
138 * - Public API: To let toolkits like Gtk+ give user a surface that
139 * only represents part of the final destination (say, the expose
140 * area), but has the same device space as the destination. In these
141 * cases device_offset is typically negative. Example:
148 * | | | <--|-- expose area
152 * In this case, the user of cairo API can set the device_space on
153 * the expose area to (-x,-y) to move the device space origin to that
154 * of the application window, such that drawing in the expose area
155 * surface and painting it in the application window has the same
156 * effect as drawing in the application window directly. Gtk+ has
157 * been using this feature.
159 * - Glyph surfaces: In most font rendering systems, glyph surfaces
160 * have an origin at (0,0) and a bounding box that is typically
161 * represented as (x_bearing,y_bearing,width,height). Depending on
162 * which way y progresses in the system, y_bearing may typically be
163 * negative (for systems similar to cairo, with origin at top left),
164 * or be positive (in systems like PDF with origin at bottom left).
165 * No matter which is the case, it is important to note that
166 * (x_bearing,y_bearing) is the coordinates of top-left of the glyph
167 * relative to the glyph origin. That is, for example:
169 * Scaled-glyph space:
171 * (x_bearing,y_bearing) <-- negative numbers
175 * |......(0,0) <---|-- glyph origin
179 * (width+x_bearing,height+y_bearing)
181 * Note the similarity of the origin to the device space. That is
182 * exactly how we use the device_offset to represent scaled glyphs:
183 * to use the device-space origin as the glyph origin.
185 * Now compare the scaled-glyph space to device-space and surface-space
186 * and convince yourself that:
188 * (x_bearing,y_bearing) = (-x,-y) = - device_offset
190 * That's right. If you are not convinced yet, contrast the definition
193 * "(x_bearing,y_bearing) is the coordinates of top-left of the
194 * glyph relative to the glyph origin."
196 * "In other words: device_offset is the coordinates of the
197 * device-space origin relative to the top-left of the surface."
199 * and note that glyph origin = device-space origin.
203 _cairo_scaled_font_fini_internal (cairo_scaled_font_t *scaled_font);
206 _cairo_scaled_glyph_fini (cairo_scaled_font_t *scaled_font,
207 cairo_scaled_glyph_t *scaled_glyph)
209 while (! cairo_list_is_empty (&scaled_glyph->dev_privates)) {
210 cairo_scaled_glyph_private_t *private =
211 cairo_list_first_entry (&scaled_glyph->dev_privates,
212 cairo_scaled_glyph_private_t,
214 private->destroy (private, scaled_glyph, scaled_font);
217 _cairo_image_scaled_glyph_fini (scaled_font, scaled_glyph);
219 if (scaled_glyph->surface != NULL)
220 cairo_surface_destroy (&scaled_glyph->surface->base);
222 if (scaled_glyph->path != NULL)
223 _cairo_path_fixed_destroy (scaled_glyph->path);
225 if (scaled_glyph->recording_surface != NULL) {
226 cairo_surface_finish (scaled_glyph->recording_surface);
227 cairo_surface_destroy (scaled_glyph->recording_surface);
232 static const cairo_scaled_font_t _cairo_scaled_font_nil = {
233 { ZOMBIE }, /* hash_entry */
234 CAIRO_STATUS_NO_MEMORY, /* status */
235 CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
236 { 0, 0, 0, NULL }, /* user_data */
237 NULL, /* original_font_face */
238 NULL, /* font_face */
239 { 1., 0., 0., 1., 0, 0}, /* font_matrix */
240 { 1., 0., 0., 1., 0, 0}, /* ctm */
241 { CAIRO_ANTIALIAS_DEFAULT, /* options */
242 CAIRO_SUBPIXEL_ORDER_DEFAULT,
243 CAIRO_HINT_STYLE_DEFAULT,
244 CAIRO_HINT_METRICS_DEFAULT} ,
245 FALSE, /* placeholder */
246 FALSE, /* holdover */
248 { 1., 0., 0., 1., 0, 0}, /* scale */
249 { 1., 0., 0., 1., 0, 0}, /* scale_inverse */
251 { 0., 0., 0., 0., 0. }, /* extents */
252 { 0., 0., 0., 0., 0. }, /* fs_extents */
253 CAIRO_MUTEX_NIL_INITIALIZER,/* mutex */
255 { NULL, NULL }, /* pages */
256 FALSE, /* cache_frozen */
257 FALSE, /* global_cache_frozen */
258 { NULL, NULL }, /* privates */
263 * _cairo_scaled_font_set_error:
264 * @scaled_font: a scaled_font
265 * @status: a status value indicating an error
267 * Atomically sets scaled_font->status to @status and calls _cairo_error;
268 * Does nothing if status is %CAIRO_STATUS_SUCCESS.
270 * All assignments of an error status to scaled_font->status should happen
271 * through _cairo_scaled_font_set_error(). Note that due to the nature of
272 * the atomic operation, it is not safe to call this function on the nil
275 * The purpose of this function is to allow the user to set a
276 * breakpoint in _cairo_error() to generate a stack trace for when the
277 * user causes cairo to detect an error.
279 * Return value: the error status.
282 _cairo_scaled_font_set_error (cairo_scaled_font_t *scaled_font,
283 cairo_status_t status)
285 if (status == CAIRO_STATUS_SUCCESS)
288 /* Don't overwrite an existing error. This preserves the first
289 * error, which is the most significant. */
290 _cairo_status_set_error (&scaled_font->status, status);
292 return _cairo_error (status);
296 * cairo_scaled_font_get_type:
297 * @scaled_font: a #cairo_scaled_font_t
299 * This function returns the type of the backend used to create
300 * a scaled font. See #cairo_font_type_t for available types.
301 * However, this function never returns %CAIRO_FONT_TYPE_TOY.
303 * Return value: The type of @scaled_font.
308 cairo_scaled_font_get_type (cairo_scaled_font_t *scaled_font)
310 if (CAIRO_REFERENCE_COUNT_IS_INVALID (&scaled_font->ref_count))
311 return CAIRO_FONT_TYPE_TOY;
313 return scaled_font->backend->type;
317 * cairo_scaled_font_status:
318 * @scaled_font: a #cairo_scaled_font_t
320 * Checks whether an error has previously occurred for this
323 * Return value: %CAIRO_STATUS_SUCCESS or another error such as
324 * %CAIRO_STATUS_NO_MEMORY.
329 cairo_scaled_font_status (cairo_scaled_font_t *scaled_font)
331 return scaled_font->status;
333 slim_hidden_def (cairo_scaled_font_status);
335 /* Here we keep a unique mapping from
336 * font_face/matrix/ctm/font_options => #cairo_scaled_font_t.
338 * Here are the things that we want to map:
340 * a) All otherwise referenced #cairo_scaled_font_t's
341 * b) Some number of not otherwise referenced #cairo_scaled_font_t's
343 * The implementation uses a hash table which covers (a)
344 * completely. Then, for (b) we have an array of otherwise
345 * unreferenced fonts (holdovers) which are expired in
346 * least-recently-used order.
348 * The cairo_scaled_font_create() code gets to treat this like a regular
349 * hash table. All of the magic for the little holdover cache is in
350 * cairo_scaled_font_reference() and cairo_scaled_font_destroy().
353 /* This defines the size of the holdover array ... that is, the number
354 * of scaled fonts we keep around even when not otherwise referenced
356 #define CAIRO_SCALED_FONT_MAX_HOLDOVERS 256
358 typedef struct _cairo_scaled_font_map {
359 cairo_scaled_font_t *mru_scaled_font;
360 cairo_hash_table_t *hash_table;
361 cairo_scaled_font_t *holdovers[CAIRO_SCALED_FONT_MAX_HOLDOVERS];
363 } cairo_scaled_font_map_t;
365 static cairo_scaled_font_map_t *cairo_scaled_font_map;
368 _cairo_scaled_font_keys_equal (const void *abstract_key_a, const void *abstract_key_b);
370 static cairo_scaled_font_map_t *
371 _cairo_scaled_font_map_lock (void)
373 CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
375 if (cairo_scaled_font_map == NULL) {
376 cairo_scaled_font_map = malloc (sizeof (cairo_scaled_font_map_t));
377 if (unlikely (cairo_scaled_font_map == NULL))
378 goto CLEANUP_MUTEX_LOCK;
380 cairo_scaled_font_map->mru_scaled_font = NULL;
381 cairo_scaled_font_map->hash_table =
382 _cairo_hash_table_create (_cairo_scaled_font_keys_equal);
384 if (unlikely (cairo_scaled_font_map->hash_table == NULL))
385 goto CLEANUP_SCALED_FONT_MAP;
387 cairo_scaled_font_map->num_holdovers = 0;
390 return cairo_scaled_font_map;
392 CLEANUP_SCALED_FONT_MAP:
393 free (cairo_scaled_font_map);
394 cairo_scaled_font_map = NULL;
396 CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
397 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
402 _cairo_scaled_font_map_unlock (void)
404 CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
408 _cairo_scaled_font_map_destroy (void)
410 cairo_scaled_font_map_t *font_map;
411 cairo_scaled_font_t *scaled_font;
413 CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
415 font_map = cairo_scaled_font_map;
416 if (unlikely (font_map == NULL)) {
417 goto CLEANUP_MUTEX_LOCK;
420 scaled_font = font_map->mru_scaled_font;
421 if (scaled_font != NULL) {
422 CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
423 cairo_scaled_font_destroy (scaled_font);
424 CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
427 /* remove scaled_fonts starting from the end so that font_map->holdovers
428 * is always in a consistent state when we release the mutex. */
429 while (font_map->num_holdovers) {
430 scaled_font = font_map->holdovers[font_map->num_holdovers-1];
431 assert (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count));
432 _cairo_hash_table_remove (font_map->hash_table,
433 &scaled_font->hash_entry);
435 font_map->num_holdovers--;
437 /* This releases the font_map lock to avoid the possibility of a
438 * recursive deadlock when the scaled font destroy closure gets
441 _cairo_scaled_font_fini (scaled_font);
446 _cairo_hash_table_destroy (font_map->hash_table);
448 free (cairo_scaled_font_map);
449 cairo_scaled_font_map = NULL;
452 CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
456 _cairo_scaled_glyph_page_destroy (cairo_scaled_font_t *scaled_font,
457 cairo_scaled_glyph_page_t *page)
461 assert (!scaled_font->cache_frozen);
462 assert (!scaled_font->global_cache_frozen);
464 for (n = 0; n < page->num_glyphs; n++) {
465 _cairo_hash_table_remove (scaled_font->glyphs,
466 &page->glyphs[n].hash_entry);
467 _cairo_scaled_glyph_fini (scaled_font, &page->glyphs[n]);
470 cairo_list_del (&page->link);
475 _cairo_scaled_glyph_page_pluck (void *closure)
477 cairo_scaled_glyph_page_t *page = closure;
478 cairo_scaled_font_t *scaled_font;
480 assert (! cairo_list_is_empty (&page->link));
482 scaled_font = (cairo_scaled_font_t *) page->cache_entry.hash;
484 CAIRO_MUTEX_LOCK (scaled_font->mutex);
485 _cairo_scaled_glyph_page_destroy (scaled_font, page);
486 CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
489 /* If a scaled font wants to unlock the font map while still being
490 * created (needed for user-fonts), we need to take extra care not
491 * ending up with multiple identical scaled fonts being created.
493 * What we do is, we create a fake identical scaled font, and mark
494 * it as placeholder, lock its mutex, and insert that in the fontmap
495 * hash table. This makes other code trying to create an identical
496 * scaled font to just wait and retry.
498 * The reason we have to create a fake scaled font instead of just using
499 * scaled_font is for lifecycle management: we need to (or rather,
500 * other code needs to) reference the scaled_font in the hash table.
501 * We can't do that on the input scaled_font as it may be freed by
502 * font backend upon error.
506 _cairo_scaled_font_register_placeholder_and_unlock_font_map (cairo_scaled_font_t *scaled_font)
508 cairo_status_t status;
509 cairo_scaled_font_t *placeholder_scaled_font;
511 assert (CAIRO_MUTEX_IS_LOCKED (_cairo_scaled_font_map_mutex));
513 status = scaled_font->status;
514 if (unlikely (status))
517 placeholder_scaled_font = malloc (sizeof (cairo_scaled_font_t));
518 if (unlikely (placeholder_scaled_font == NULL))
519 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
521 /* full initialization is wasteful, but who cares... */
522 status = _cairo_scaled_font_init (placeholder_scaled_font,
523 scaled_font->font_face,
524 &scaled_font->font_matrix,
526 &scaled_font->options,
528 if (unlikely (status))
529 goto FREE_PLACEHOLDER;
531 placeholder_scaled_font->placeholder = TRUE;
533 placeholder_scaled_font->hash_entry.hash
534 = _cairo_scaled_font_compute_hash (placeholder_scaled_font);
535 status = _cairo_hash_table_insert (cairo_scaled_font_map->hash_table,
536 &placeholder_scaled_font->hash_entry);
537 if (unlikely (status))
538 goto FINI_PLACEHOLDER;
540 CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
541 CAIRO_MUTEX_LOCK (placeholder_scaled_font->mutex);
543 return CAIRO_STATUS_SUCCESS;
546 _cairo_scaled_font_fini_internal (placeholder_scaled_font);
548 free (placeholder_scaled_font);
550 return _cairo_scaled_font_set_error (scaled_font, status);
554 _cairo_scaled_font_unregister_placeholder_and_lock_font_map (cairo_scaled_font_t *scaled_font)
556 cairo_scaled_font_t *placeholder_scaled_font;
558 CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
560 /* temporary hash value to match the placeholder */
561 scaled_font->hash_entry.hash
562 = _cairo_scaled_font_compute_hash (scaled_font);
563 placeholder_scaled_font =
564 _cairo_hash_table_lookup (cairo_scaled_font_map->hash_table,
565 &scaled_font->hash_entry);
566 assert (placeholder_scaled_font != NULL);
567 assert (placeholder_scaled_font->placeholder);
568 assert (CAIRO_MUTEX_IS_LOCKED (placeholder_scaled_font->mutex));
570 _cairo_hash_table_remove (cairo_scaled_font_map->hash_table,
571 &placeholder_scaled_font->hash_entry);
573 CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
575 CAIRO_MUTEX_UNLOCK (placeholder_scaled_font->mutex);
576 cairo_scaled_font_destroy (placeholder_scaled_font);
578 CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
582 _cairo_scaled_font_placeholder_wait_for_creation_to_finish (cairo_scaled_font_t *placeholder_scaled_font)
584 /* reference the place holder so it doesn't go away */
585 cairo_scaled_font_reference (placeholder_scaled_font);
587 /* now unlock the fontmap mutex so creation has a chance to finish */
588 CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
590 /* wait on placeholder mutex until we are awaken */
591 CAIRO_MUTEX_LOCK (placeholder_scaled_font->mutex);
593 /* ok, creation done. just clean up and back out */
594 CAIRO_MUTEX_UNLOCK (placeholder_scaled_font->mutex);
595 cairo_scaled_font_destroy (placeholder_scaled_font);
597 CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
600 /* Fowler / Noll / Vo (FNV) Hash (http://www.isthe.com/chongo/tech/comp/fnv/)
602 * Not necessarily better than a lot of other hashes, but should be OK, and
603 * well tested with binary data.
606 #define FNV_32_PRIME ((uint32_t)0x01000193)
607 #define FNV1_32_INIT ((uint32_t)0x811c9dc5)
610 _hash_matrix_fnv (const cairo_matrix_t *matrix,
613 const uint8_t *buffer = (const uint8_t *) matrix;
614 int len = sizeof (cairo_matrix_t);
616 hval *= FNV_32_PRIME;
624 _hash_mix_bits (uint32_t hash)
635 _cairo_scaled_font_compute_hash (cairo_scaled_font_t *scaled_font)
637 uint32_t hash = FNV1_32_INIT;
639 /* We do a bytewise hash on the font matrices */
640 hash = _hash_matrix_fnv (&scaled_font->font_matrix, hash);
641 hash = _hash_matrix_fnv (&scaled_font->ctm, hash);
642 hash = _hash_mix_bits (hash);
644 hash ^= (unsigned long) scaled_font->original_font_face;
645 hash ^= cairo_font_options_hash (&scaled_font->options);
647 /* final mixing of bits */
648 hash = _hash_mix_bits (hash);
649 assert (hash != ZOMBIE);
655 _cairo_scaled_font_init_key (cairo_scaled_font_t *scaled_font,
656 cairo_font_face_t *font_face,
657 const cairo_matrix_t *font_matrix,
658 const cairo_matrix_t *ctm,
659 const cairo_font_options_t *options)
661 scaled_font->status = CAIRO_STATUS_SUCCESS;
662 scaled_font->placeholder = FALSE;
663 scaled_font->font_face = font_face;
664 scaled_font->original_font_face = font_face;
665 scaled_font->font_matrix = *font_matrix;
666 scaled_font->ctm = *ctm;
667 /* ignore translation values in the ctm */
668 scaled_font->ctm.x0 = 0.;
669 scaled_font->ctm.y0 = 0.;
670 _cairo_font_options_init_copy (&scaled_font->options, options);
672 scaled_font->hash_entry.hash =
673 _cairo_scaled_font_compute_hash (scaled_font);
677 _cairo_scaled_font_keys_equal (const void *abstract_key_a,
678 const void *abstract_key_b)
680 const cairo_scaled_font_t *key_a = abstract_key_a;
681 const cairo_scaled_font_t *key_b = abstract_key_b;
683 return key_a->original_font_face == key_b->original_font_face &&
684 memcmp ((unsigned char *)(&key_a->font_matrix.xx),
685 (unsigned char *)(&key_b->font_matrix.xx),
686 sizeof(cairo_matrix_t)) == 0 &&
687 memcmp ((unsigned char *)(&key_a->ctm.xx),
688 (unsigned char *)(&key_b->ctm.xx),
689 sizeof(cairo_matrix_t)) == 0 &&
690 cairo_font_options_equal (&key_a->options, &key_b->options);
694 _cairo_scaled_font_matches (const cairo_scaled_font_t *scaled_font,
695 const cairo_font_face_t *font_face,
696 const cairo_matrix_t *font_matrix,
697 const cairo_matrix_t *ctm,
698 const cairo_font_options_t *options)
700 return scaled_font->original_font_face == font_face &&
701 memcmp ((unsigned char *)(&scaled_font->font_matrix.xx),
702 (unsigned char *)(&font_matrix->xx),
703 sizeof(cairo_matrix_t)) == 0 &&
704 memcmp ((unsigned char *)(&scaled_font->ctm.xx),
705 (unsigned char *)(&ctm->xx),
706 sizeof(cairo_matrix_t)) == 0 &&
707 cairo_font_options_equal (&scaled_font->options, options);
711 * Basic #cairo_scaled_font_t object management
715 _cairo_scaled_font_init (cairo_scaled_font_t *scaled_font,
716 cairo_font_face_t *font_face,
717 const cairo_matrix_t *font_matrix,
718 const cairo_matrix_t *ctm,
719 const cairo_font_options_t *options,
720 const cairo_scaled_font_backend_t *backend)
722 cairo_status_t status;
724 status = cairo_font_options_status ((cairo_font_options_t *) options);
725 if (unlikely (status))
728 scaled_font->status = CAIRO_STATUS_SUCCESS;
729 scaled_font->placeholder = FALSE;
730 scaled_font->font_face = font_face;
731 scaled_font->original_font_face = font_face;
732 scaled_font->font_matrix = *font_matrix;
733 scaled_font->ctm = *ctm;
734 /* ignore translation values in the ctm */
735 scaled_font->ctm.x0 = 0.;
736 scaled_font->ctm.y0 = 0.;
737 _cairo_font_options_init_copy (&scaled_font->options, options);
739 cairo_matrix_multiply (&scaled_font->scale,
740 &scaled_font->font_matrix,
743 scaled_font->max_scale = MAX (fabs (scaled_font->scale.xx) + fabs (scaled_font->scale.xy),
744 fabs (scaled_font->scale.yx) + fabs (scaled_font->scale.yy));
745 scaled_font->scale_inverse = scaled_font->scale;
746 status = cairo_matrix_invert (&scaled_font->scale_inverse);
747 if (unlikely (status)) {
748 /* If the font scale matrix is rank 0, just using an all-zero inverse matrix
749 * makes everything work correctly. This make font size 0 work without
750 * producing an error.
752 * FIXME: If the scale is rank 1, we still go into error mode. But then
753 * again, that's what we do everywhere in cairo.
755 * Also, the check for == 0. below may be too harsh...
757 if (_cairo_matrix_is_scale_0 (&scaled_font->scale)) {
758 cairo_matrix_init (&scaled_font->scale_inverse,
760 -scaled_font->scale.x0,
761 -scaled_font->scale.y0);
766 scaled_font->glyphs = _cairo_hash_table_create (NULL);
767 if (unlikely (scaled_font->glyphs == NULL))
768 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
770 cairo_list_init (&scaled_font->glyph_pages);
771 scaled_font->cache_frozen = FALSE;
772 scaled_font->global_cache_frozen = FALSE;
774 scaled_font->holdover = FALSE;
775 scaled_font->finished = FALSE;
777 CAIRO_REFERENCE_COUNT_INIT (&scaled_font->ref_count, 1);
779 _cairo_user_data_array_init (&scaled_font->user_data);
781 cairo_font_face_reference (font_face);
782 scaled_font->original_font_face = NULL;
784 CAIRO_MUTEX_INIT (scaled_font->mutex);
786 cairo_list_init (&scaled_font->dev_privates);
788 scaled_font->backend = backend;
789 cairo_list_init (&scaled_font->link);
791 return CAIRO_STATUS_SUCCESS;
795 _cairo_scaled_font_freeze_cache (cairo_scaled_font_t *scaled_font)
797 /* ensure we do not modify an error object */
798 assert (scaled_font->status == CAIRO_STATUS_SUCCESS);
800 CAIRO_MUTEX_LOCK (scaled_font->mutex);
801 scaled_font->cache_frozen = TRUE;
805 _cairo_scaled_font_thaw_cache (cairo_scaled_font_t *scaled_font)
807 assert (scaled_font->cache_frozen);
809 if (scaled_font->global_cache_frozen) {
810 CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex);
811 _cairo_cache_thaw (&cairo_scaled_glyph_page_cache);
812 CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex);
813 scaled_font->global_cache_frozen = FALSE;
816 scaled_font->cache_frozen = FALSE;
817 CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
821 _cairo_scaled_font_reset_cache (cairo_scaled_font_t *scaled_font)
823 CAIRO_MUTEX_LOCK (scaled_font->mutex);
824 assert (! scaled_font->cache_frozen);
825 assert (! scaled_font->global_cache_frozen);
826 CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex);
827 while (! cairo_list_is_empty (&scaled_font->glyph_pages)) {
828 cairo_scaled_glyph_page_t *page =
829 cairo_list_first_entry (&scaled_font->glyph_pages,
830 cairo_scaled_glyph_page_t,
833 cairo_scaled_glyph_page_cache.size -= page->cache_entry.size;
834 _cairo_hash_table_remove (cairo_scaled_glyph_page_cache.hash_table,
835 (cairo_hash_entry_t *) &page->cache_entry);
837 _cairo_scaled_glyph_page_destroy (scaled_font, page);
839 CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex);
840 CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
844 _cairo_scaled_font_set_metrics (cairo_scaled_font_t *scaled_font,
845 cairo_font_extents_t *fs_metrics)
847 cairo_status_t status;
848 double font_scale_x, font_scale_y;
850 scaled_font->fs_extents = *fs_metrics;
852 status = _cairo_matrix_compute_basis_scale_factors (&scaled_font->font_matrix,
853 &font_scale_x, &font_scale_y,
855 if (unlikely (status))
859 * The font responded in unscaled units, scale by the font
860 * matrix scale factors to get to user space
863 scaled_font->extents.ascent = fs_metrics->ascent * font_scale_y;
864 scaled_font->extents.descent = fs_metrics->descent * font_scale_y;
865 scaled_font->extents.height = fs_metrics->height * font_scale_y;
866 scaled_font->extents.max_x_advance = fs_metrics->max_x_advance * font_scale_x;
867 scaled_font->extents.max_y_advance = fs_metrics->max_y_advance * font_scale_y;
869 return CAIRO_STATUS_SUCCESS;
873 _cairo_scaled_font_fini_internal (cairo_scaled_font_t *scaled_font)
875 assert (! scaled_font->cache_frozen);
876 assert (! scaled_font->global_cache_frozen);
877 scaled_font->finished = TRUE;
879 _cairo_scaled_font_reset_cache (scaled_font);
880 _cairo_hash_table_destroy (scaled_font->glyphs);
882 cairo_font_face_destroy (scaled_font->font_face);
883 cairo_font_face_destroy (scaled_font->original_font_face);
885 CAIRO_MUTEX_FINI (scaled_font->mutex);
887 while (! cairo_list_is_empty (&scaled_font->dev_privates)) {
888 cairo_scaled_font_private_t *private =
889 cairo_list_first_entry (&scaled_font->dev_privates,
890 cairo_scaled_font_private_t,
892 private->destroy (private, scaled_font);
895 if (scaled_font->backend != NULL && scaled_font->backend->fini != NULL)
896 scaled_font->backend->fini (scaled_font);
898 _cairo_user_data_array_fini (&scaled_font->user_data);
902 _cairo_scaled_font_fini (cairo_scaled_font_t *scaled_font)
904 /* Release the lock to avoid the possibility of a recursive
905 * deadlock when the scaled font destroy closure gets called. */
906 CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
907 _cairo_scaled_font_fini_internal (scaled_font);
908 CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
912 _cairo_scaled_font_attach_private (cairo_scaled_font_t *scaled_font,
913 cairo_scaled_font_private_t *private,
915 void (*destroy) (cairo_scaled_font_private_t *,
916 cairo_scaled_font_t *))
919 private->destroy = destroy;
920 cairo_list_add (&private->link, &scaled_font->dev_privates);
923 cairo_scaled_font_private_t *
924 _cairo_scaled_font_find_private (cairo_scaled_font_t *scaled_font,
927 cairo_scaled_font_private_t *priv;
929 cairo_list_foreach_entry (priv, cairo_scaled_font_private_t,
930 &scaled_font->dev_privates, link)
932 if (priv->key == key) {
933 if (priv->link.prev != &scaled_font->dev_privates)
934 cairo_list_move (&priv->link, &scaled_font->dev_privates);
943 _cairo_scaled_glyph_attach_private (cairo_scaled_glyph_t *scaled_glyph,
944 cairo_scaled_glyph_private_t *private,
946 void (*destroy) (cairo_scaled_glyph_private_t *,
947 cairo_scaled_glyph_t *,
948 cairo_scaled_font_t *))
951 private->destroy = destroy;
952 cairo_list_add (&private->link, &scaled_glyph->dev_privates);
955 cairo_scaled_glyph_private_t *
956 _cairo_scaled_glyph_find_private (cairo_scaled_glyph_t *scaled_glyph,
959 cairo_scaled_glyph_private_t *priv;
961 cairo_list_foreach_entry (priv, cairo_scaled_glyph_private_t,
962 &scaled_glyph->dev_privates, link)
964 if (priv->key == key) {
965 if (priv->link.prev != &scaled_glyph->dev_privates)
966 cairo_list_move (&priv->link, &scaled_glyph->dev_privates);
975 * cairo_scaled_font_create:
976 * @font_face: a #cairo_font_face_t
977 * @font_matrix: font space to user space transformation matrix for the
978 * font. In the simplest case of a N point font, this matrix is
979 * just a scale by N, but it can also be used to shear the font
980 * or stretch it unequally along the two axes. See
981 * cairo_set_font_matrix().
982 * @ctm: user to device transformation matrix with which the font will
984 * @options: options to use when getting metrics for the font and
987 * Creates a #cairo_scaled_font_t object from a font face and matrices that
988 * describe the size of the font and the environment in which it will
991 * Return value: a newly created #cairo_scaled_font_t. Destroy with
992 * cairo_scaled_font_destroy()
996 cairo_scaled_font_t *
997 cairo_scaled_font_create (cairo_font_face_t *font_face,
998 const cairo_matrix_t *font_matrix,
999 const cairo_matrix_t *ctm,
1000 const cairo_font_options_t *options)
1002 cairo_status_t status;
1003 cairo_scaled_font_map_t *font_map;
1004 cairo_font_face_t *original_font_face = font_face;
1005 cairo_scaled_font_t key, *old = NULL, *scaled_font = NULL, *dead = NULL;
1008 status = font_face->status;
1009 if (unlikely (status))
1010 return _cairo_scaled_font_create_in_error (status);
1012 det = _cairo_matrix_compute_determinant (font_matrix);
1013 if (! ISFINITE (det))
1014 return _cairo_scaled_font_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_MATRIX));
1016 det = _cairo_matrix_compute_determinant (ctm);
1017 if (! ISFINITE (det))
1018 return _cairo_scaled_font_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_MATRIX));
1020 status = cairo_font_options_status ((cairo_font_options_t *) options);
1021 if (unlikely (status))
1022 return _cairo_scaled_font_create_in_error (status);
1024 /* Note that degenerate ctm or font_matrix *are* allowed.
1025 * We want to support a font size of 0. */
1027 font_map = _cairo_scaled_font_map_lock ();
1028 if (unlikely (font_map == NULL))
1029 return _cairo_scaled_font_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1031 scaled_font = font_map->mru_scaled_font;
1032 if (scaled_font != NULL &&
1033 _cairo_scaled_font_matches (scaled_font,
1034 font_face, font_matrix, ctm, options))
1036 assert (scaled_font->hash_entry.hash != ZOMBIE);
1037 assert (! scaled_font->placeholder);
1039 if (likely (scaled_font->status == CAIRO_STATUS_SUCCESS)) {
1040 /* We increment the reference count manually here, (rather
1041 * than calling into cairo_scaled_font_reference), since we
1042 * must modify the reference count while our lock is still
1044 _cairo_reference_count_inc (&scaled_font->ref_count);
1045 _cairo_scaled_font_map_unlock ();
1049 /* the font has been put into an error status - abandon the cache */
1050 _cairo_hash_table_remove (font_map->hash_table,
1051 &scaled_font->hash_entry);
1052 scaled_font->hash_entry.hash = ZOMBIE;
1054 font_map->mru_scaled_font = NULL;
1057 _cairo_scaled_font_init_key (&key, font_face, font_matrix, ctm, options);
1059 while ((scaled_font = _cairo_hash_table_lookup (font_map->hash_table,
1062 if (! scaled_font->placeholder)
1065 /* If the scaled font is being created (happens for user-font),
1066 * just wait until it's done, then retry */
1067 _cairo_scaled_font_placeholder_wait_for_creation_to_finish (scaled_font);
1070 if (scaled_font != NULL) {
1071 /* If the original reference count is 0, then this font must have
1072 * been found in font_map->holdovers, (which means this caching is
1073 * actually working). So now we remove it from the holdovers
1074 * array, unless we caught the font in the middle of destruction.
1076 if (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count)) {
1077 if (scaled_font->holdover) {
1080 for (i = 0; i < font_map->num_holdovers; i++) {
1081 if (font_map->holdovers[i] == scaled_font) {
1082 font_map->num_holdovers--;
1083 memmove (&font_map->holdovers[i],
1084 &font_map->holdovers[i+1],
1085 (font_map->num_holdovers - i) * sizeof (cairo_scaled_font_t*));
1090 scaled_font->holdover = FALSE;
1093 /* reset any error status */
1094 scaled_font->status = CAIRO_STATUS_SUCCESS;
1097 if (likely (scaled_font->status == CAIRO_STATUS_SUCCESS)) {
1098 /* We increment the reference count manually here, (rather
1099 * than calling into cairo_scaled_font_reference), since we
1100 * must modify the reference count while our lock is still
1103 old = font_map->mru_scaled_font;
1104 font_map->mru_scaled_font = scaled_font;
1105 /* increment reference count for the mru cache */
1106 _cairo_reference_count_inc (&scaled_font->ref_count);
1107 /* and increment for the returned reference */
1108 _cairo_reference_count_inc (&scaled_font->ref_count);
1109 _cairo_scaled_font_map_unlock ();
1111 cairo_scaled_font_destroy (old);
1112 if (font_face != original_font_face)
1113 cairo_font_face_destroy (font_face);
1118 /* the font has been put into an error status - abandon the cache */
1119 _cairo_hash_table_remove (font_map->hash_table,
1120 &scaled_font->hash_entry);
1121 scaled_font->hash_entry.hash = ZOMBIE;
1125 /* Otherwise create it and insert it into the hash table. */
1126 if (font_face->backend->get_implementation != NULL) {
1127 font_face = font_face->backend->get_implementation (font_face,
1131 if (unlikely (font_face->status)) {
1132 _cairo_scaled_font_map_unlock ();
1133 return _cairo_scaled_font_create_in_error (font_face->status);
1137 status = font_face->backend->scaled_font_create (font_face, font_matrix,
1138 ctm, options, &scaled_font);
1139 /* Did we leave the backend in an error state? */
1140 if (unlikely (status)) {
1141 _cairo_scaled_font_map_unlock ();
1142 if (font_face != original_font_face)
1143 cairo_font_face_destroy (font_face);
1146 cairo_scaled_font_destroy (dead);
1148 status = _cairo_font_face_set_error (font_face, status);
1149 return _cairo_scaled_font_create_in_error (status);
1151 /* Or did we encounter an error whilst constructing the scaled font? */
1152 if (unlikely (scaled_font->status)) {
1153 _cairo_scaled_font_map_unlock ();
1154 if (font_face != original_font_face)
1155 cairo_font_face_destroy (font_face);
1158 cairo_scaled_font_destroy (dead);
1163 /* Our caching above is defeated if the backend switches fonts on us -
1164 * e.g. old incarnations of toy-font-face and lazily resolved
1167 assert (scaled_font->font_face == font_face);
1168 assert (! scaled_font->cache_frozen);
1169 assert (! scaled_font->global_cache_frozen);
1171 scaled_font->original_font_face =
1172 cairo_font_face_reference (original_font_face);
1174 scaled_font->hash_entry.hash = _cairo_scaled_font_compute_hash(scaled_font);
1176 status = _cairo_hash_table_insert (font_map->hash_table,
1177 &scaled_font->hash_entry);
1178 if (likely (status == CAIRO_STATUS_SUCCESS)) {
1179 old = font_map->mru_scaled_font;
1180 font_map->mru_scaled_font = scaled_font;
1181 _cairo_reference_count_inc (&scaled_font->ref_count);
1184 _cairo_scaled_font_map_unlock ();
1186 cairo_scaled_font_destroy (old);
1187 if (font_face != original_font_face)
1188 cairo_font_face_destroy (font_face);
1191 cairo_scaled_font_destroy (dead);
1193 if (unlikely (status)) {
1194 /* We can't call _cairo_scaled_font_destroy here since it expects
1195 * that the font has already been successfully inserted into the
1197 _cairo_scaled_font_fini_internal (scaled_font);
1199 return _cairo_scaled_font_create_in_error (status);
1204 slim_hidden_def (cairo_scaled_font_create);
1206 static cairo_scaled_font_t *_cairo_scaled_font_nil_objects[CAIRO_STATUS_LAST_STATUS + 1];
1208 /* XXX This should disappear in favour of a common pool of error objects. */
1209 cairo_scaled_font_t *
1210 _cairo_scaled_font_create_in_error (cairo_status_t status)
1212 cairo_scaled_font_t *scaled_font;
1214 assert (status != CAIRO_STATUS_SUCCESS);
1216 if (status == CAIRO_STATUS_NO_MEMORY)
1217 return (cairo_scaled_font_t *) &_cairo_scaled_font_nil;
1219 CAIRO_MUTEX_LOCK (_cairo_scaled_font_error_mutex);
1220 scaled_font = _cairo_scaled_font_nil_objects[status];
1221 if (unlikely (scaled_font == NULL)) {
1222 scaled_font = malloc (sizeof (cairo_scaled_font_t));
1223 if (unlikely (scaled_font == NULL)) {
1224 CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_error_mutex);
1225 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
1226 return (cairo_scaled_font_t *) &_cairo_scaled_font_nil;
1229 *scaled_font = _cairo_scaled_font_nil;
1230 scaled_font->status = status;
1231 _cairo_scaled_font_nil_objects[status] = scaled_font;
1233 CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_error_mutex);
1239 _cairo_scaled_font_reset_static_data (void)
1243 CAIRO_MUTEX_LOCK (_cairo_scaled_font_error_mutex);
1244 for (status = CAIRO_STATUS_SUCCESS;
1245 status <= CAIRO_STATUS_LAST_STATUS;
1248 free (_cairo_scaled_font_nil_objects[status]);
1249 _cairo_scaled_font_nil_objects[status] = NULL;
1251 CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_error_mutex);
1253 CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex);
1254 if (cairo_scaled_glyph_page_cache.hash_table != NULL) {
1255 _cairo_cache_fini (&cairo_scaled_glyph_page_cache);
1256 cairo_scaled_glyph_page_cache.hash_table = NULL;
1258 CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex);
1262 * cairo_scaled_font_reference:
1263 * @scaled_font: a #cairo_scaled_font_t, (may be %NULL in which case
1264 * this function does nothing)
1266 * Increases the reference count on @scaled_font by one. This prevents
1267 * @scaled_font from being destroyed until a matching call to
1268 * cairo_scaled_font_destroy() is made.
1270 * The number of references to a #cairo_scaled_font_t can be get using
1271 * cairo_scaled_font_get_reference_count().
1273 * Returns: the referenced #cairo_scaled_font_t
1277 cairo_scaled_font_t *
1278 cairo_scaled_font_reference (cairo_scaled_font_t *scaled_font)
1280 if (scaled_font == NULL ||
1281 CAIRO_REFERENCE_COUNT_IS_INVALID (&scaled_font->ref_count))
1284 assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count));
1286 _cairo_reference_count_inc (&scaled_font->ref_count);
1290 slim_hidden_def (cairo_scaled_font_reference);
1293 * cairo_scaled_font_destroy:
1294 * @scaled_font: a #cairo_scaled_font_t
1296 * Decreases the reference count on @font by one. If the result
1297 * is zero, then @font and all associated resources are freed.
1298 * See cairo_scaled_font_reference().
1303 cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font)
1305 cairo_scaled_font_t *lru = NULL;
1306 cairo_scaled_font_map_t *font_map;
1308 assert (CAIRO_MUTEX_IS_UNLOCKED (_cairo_scaled_font_map_mutex));
1310 if (scaled_font == NULL ||
1311 CAIRO_REFERENCE_COUNT_IS_INVALID (&scaled_font->ref_count))
1314 assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count));
1316 if (! _cairo_reference_count_dec_and_test (&scaled_font->ref_count))
1319 assert (! scaled_font->cache_frozen);
1320 assert (! scaled_font->global_cache_frozen);
1322 font_map = _cairo_scaled_font_map_lock ();
1323 assert (font_map != NULL);
1325 /* Another thread may have resurrected the font whilst we waited */
1326 if (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count)) {
1327 if (! scaled_font->placeholder &&
1328 scaled_font->hash_entry.hash != ZOMBIE)
1330 /* Another thread may have already inserted us into the holdovers */
1331 if (scaled_font->holdover)
1334 /* Rather than immediately destroying this object, we put it into
1335 * the font_map->holdovers array in case it will get used again
1336 * soon (and is why we must hold the lock over the atomic op on
1337 * the reference count). To make room for it, we do actually
1338 * destroy the least-recently-used holdover.
1341 if (font_map->num_holdovers == CAIRO_SCALED_FONT_MAX_HOLDOVERS) {
1342 lru = font_map->holdovers[0];
1343 assert (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&lru->ref_count));
1345 _cairo_hash_table_remove (font_map->hash_table,
1348 font_map->num_holdovers--;
1349 memmove (&font_map->holdovers[0],
1350 &font_map->holdovers[1],
1351 font_map->num_holdovers * sizeof (cairo_scaled_font_t*));
1354 font_map->holdovers[font_map->num_holdovers++] = scaled_font;
1355 scaled_font->holdover = TRUE;
1361 _cairo_scaled_font_map_unlock ();
1363 /* If we pulled an item from the holdovers array, (while the font
1364 * map lock was held, of course), then there is no way that anyone
1365 * else could have acquired a reference to it. So we can now
1366 * safely call fini on it without any lock held. This is desirable
1367 * as we never want to call into any backend function with a lock
1370 _cairo_scaled_font_fini_internal (lru);
1374 slim_hidden_def (cairo_scaled_font_destroy);
1377 * cairo_scaled_font_get_reference_count:
1378 * @scaled_font: a #cairo_scaled_font_t
1380 * Returns the current reference count of @scaled_font.
1382 * Return value: the current reference count of @scaled_font. If the
1383 * object is a nil object, 0 will be returned.
1388 cairo_scaled_font_get_reference_count (cairo_scaled_font_t *scaled_font)
1390 if (scaled_font == NULL ||
1391 CAIRO_REFERENCE_COUNT_IS_INVALID (&scaled_font->ref_count))
1394 return CAIRO_REFERENCE_COUNT_GET_VALUE (&scaled_font->ref_count);
1398 * cairo_scaled_font_get_user_data:
1399 * @scaled_font: a #cairo_scaled_font_t
1400 * @key: the address of the #cairo_user_data_key_t the user data was
1403 * Return user data previously attached to @scaled_font using the
1404 * specified key. If no user data has been attached with the given
1405 * key this function returns %NULL.
1407 * Return value: the user data previously attached or %NULL.
1412 cairo_scaled_font_get_user_data (cairo_scaled_font_t *scaled_font,
1413 const cairo_user_data_key_t *key)
1415 return _cairo_user_data_array_get_data (&scaled_font->user_data,
1418 slim_hidden_def (cairo_scaled_font_get_user_data);
1421 * cairo_scaled_font_set_user_data:
1422 * @scaled_font: a #cairo_scaled_font_t
1423 * @key: the address of a #cairo_user_data_key_t to attach the user data to
1424 * @user_data: the user data to attach to the #cairo_scaled_font_t
1425 * @destroy: a #cairo_destroy_func_t which will be called when the
1426 * #cairo_t is destroyed or when new user data is attached using the
1429 * Attach user data to @scaled_font. To remove user data from a surface,
1430 * call this function with the key that was used to set it and %NULL
1433 * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a
1434 * slot could not be allocated for the user data.
1439 cairo_scaled_font_set_user_data (cairo_scaled_font_t *scaled_font,
1440 const cairo_user_data_key_t *key,
1442 cairo_destroy_func_t destroy)
1444 if (CAIRO_REFERENCE_COUNT_IS_INVALID (&scaled_font->ref_count))
1445 return scaled_font->status;
1447 return _cairo_user_data_array_set_data (&scaled_font->user_data,
1448 key, user_data, destroy);
1450 slim_hidden_def (cairo_scaled_font_set_user_data);
1452 /* Public font API follows. */
1455 * cairo_scaled_font_extents:
1456 * @scaled_font: a #cairo_scaled_font_t
1457 * @extents: a #cairo_font_extents_t which to store the retrieved extents.
1459 * Gets the metrics for a #cairo_scaled_font_t.
1464 cairo_scaled_font_extents (cairo_scaled_font_t *scaled_font,
1465 cairo_font_extents_t *extents)
1467 if (scaled_font->status) {
1468 extents->ascent = 0.0;
1469 extents->descent = 0.0;
1470 extents->height = 0.0;
1471 extents->max_x_advance = 0.0;
1472 extents->max_y_advance = 0.0;
1476 *extents = scaled_font->extents;
1478 slim_hidden_def (cairo_scaled_font_extents);
1481 * cairo_scaled_font_text_extents:
1482 * @scaled_font: a #cairo_scaled_font_t
1483 * @utf8: a NUL-terminated string of text, encoded in UTF-8
1484 * @extents: a #cairo_text_extents_t which to store the retrieved extents.
1486 * Gets the extents for a string of text. The extents describe a
1487 * user-space rectangle that encloses the "inked" portion of the text
1488 * drawn at the origin (0,0) (as it would be drawn by cairo_show_text()
1489 * if the cairo graphics state were set to the same font_face,
1490 * font_matrix, ctm, and font_options as @scaled_font). Additionally,
1491 * the x_advance and y_advance values indicate the amount by which the
1492 * current point would be advanced by cairo_show_text().
1494 * Note that whitespace characters do not directly contribute to the
1495 * size of the rectangle (extents.width and extents.height). They do
1496 * contribute indirectly by changing the position of non-whitespace
1497 * characters. In particular, trailing whitespace characters are
1498 * likely to not affect the size of the rectangle, though they will
1499 * affect the x_advance and y_advance values.
1504 cairo_scaled_font_text_extents (cairo_scaled_font_t *scaled_font,
1506 cairo_text_extents_t *extents)
1508 cairo_status_t status;
1509 cairo_glyph_t *glyphs = NULL;
1512 if (scaled_font->status)
1518 status = cairo_scaled_font_text_to_glyphs (scaled_font, 0., 0.,
1520 &glyphs, &num_glyphs,
1523 if (unlikely (status)) {
1524 status = _cairo_scaled_font_set_error (scaled_font, status);
1528 cairo_scaled_font_glyph_extents (scaled_font, glyphs, num_glyphs, extents);
1534 extents->x_bearing = 0.0;
1535 extents->y_bearing = 0.0;
1536 extents->width = 0.0;
1537 extents->height = 0.0;
1538 extents->x_advance = 0.0;
1539 extents->y_advance = 0.0;
1543 * cairo_scaled_font_glyph_extents:
1544 * @scaled_font: a #cairo_scaled_font_t
1545 * @glyphs: an array of glyph IDs with X and Y offsets.
1546 * @num_glyphs: the number of glyphs in the @glyphs array
1547 * @extents: a #cairo_text_extents_t which to store the retrieved extents.
1549 * Gets the extents for an array of glyphs. The extents describe a
1550 * user-space rectangle that encloses the "inked" portion of the
1551 * glyphs, (as they would be drawn by cairo_show_glyphs() if the cairo
1552 * graphics state were set to the same font_face, font_matrix, ctm,
1553 * and font_options as @scaled_font). Additionally, the x_advance and
1554 * y_advance values indicate the amount by which the current point
1555 * would be advanced by cairo_show_glyphs().
1557 * Note that whitespace glyphs do not contribute to the size of the
1558 * rectangle (extents.width and extents.height).
1563 cairo_scaled_font_glyph_extents (cairo_scaled_font_t *scaled_font,
1564 const cairo_glyph_t *glyphs,
1566 cairo_text_extents_t *extents)
1568 cairo_status_t status;
1570 double min_x = 0.0, min_y = 0.0, max_x = 0.0, max_y = 0.0;
1571 cairo_bool_t visible = FALSE;
1572 cairo_scaled_glyph_t *scaled_glyph = NULL;
1574 extents->x_bearing = 0.0;
1575 extents->y_bearing = 0.0;
1576 extents->width = 0.0;
1577 extents->height = 0.0;
1578 extents->x_advance = 0.0;
1579 extents->y_advance = 0.0;
1581 if (unlikely (scaled_font->status))
1584 if (num_glyphs == 0)
1587 if (unlikely (num_glyphs < 0)) {
1588 _cairo_error_throw (CAIRO_STATUS_NEGATIVE_COUNT);
1589 /* XXX Can't propagate error */
1593 if (unlikely (glyphs == NULL)) {
1594 _cairo_error_throw (CAIRO_STATUS_NULL_POINTER);
1595 /* XXX Can't propagate error */
1599 _cairo_scaled_font_freeze_cache (scaled_font);
1601 for (i = 0; i < num_glyphs; i++) {
1602 double left, top, right, bottom;
1604 status = _cairo_scaled_glyph_lookup (scaled_font,
1606 CAIRO_SCALED_GLYPH_INFO_METRICS,
1608 if (unlikely (status)) {
1609 status = _cairo_scaled_font_set_error (scaled_font, status);
1613 /* "Ink" extents should skip "invisible" glyphs */
1614 if (scaled_glyph->metrics.width == 0 || scaled_glyph->metrics.height == 0)
1617 left = scaled_glyph->metrics.x_bearing + glyphs[i].x;
1618 right = left + scaled_glyph->metrics.width;
1619 top = scaled_glyph->metrics.y_bearing + glyphs[i].y;
1620 bottom = top + scaled_glyph->metrics.height;
1629 if (left < min_x) min_x = left;
1630 if (right > max_x) max_x = right;
1631 if (top < min_y) min_y = top;
1632 if (bottom > max_y) max_y = bottom;
1637 extents->x_bearing = min_x - glyphs[0].x;
1638 extents->y_bearing = min_y - glyphs[0].y;
1639 extents->width = max_x - min_x;
1640 extents->height = max_y - min_y;
1642 extents->x_bearing = 0.0;
1643 extents->y_bearing = 0.0;
1644 extents->width = 0.0;
1645 extents->height = 0.0;
1648 double x0, y0, x1, y1;
1653 /* scaled_glyph contains the glyph for num_glyphs - 1 already. */
1654 x1 = glyphs[num_glyphs - 1].x + scaled_glyph->metrics.x_advance;
1655 y1 = glyphs[num_glyphs - 1].y + scaled_glyph->metrics.y_advance;
1657 extents->x_advance = x1 - x0;
1658 extents->y_advance = y1 - y0;
1661 _cairo_scaled_font_thaw_cache (scaled_font);
1665 extents->x_bearing = 0.0;
1666 extents->y_bearing = 0.0;
1667 extents->width = 0.0;
1668 extents->height = 0.0;
1669 extents->x_advance = 0.0;
1670 extents->y_advance = 0.0;
1672 slim_hidden_def (cairo_scaled_font_glyph_extents);
1674 #define GLYPH_LUT_SIZE 64
1675 static cairo_status_t
1676 cairo_scaled_font_text_to_glyphs_internal_cached (cairo_scaled_font_t *scaled_font,
1680 cairo_glyph_t *glyphs,
1681 cairo_text_cluster_t **clusters,
1684 struct glyph_lut_elt {
1685 unsigned long index;
1688 } glyph_lut[GLYPH_LUT_SIZE];
1689 uint32_t glyph_lut_unicode[GLYPH_LUT_SIZE];
1690 cairo_status_t status;
1694 for (i = 0; i < GLYPH_LUT_SIZE; i++)
1695 glyph_lut_unicode[i] = ~0U;
1698 for (i = 0; i < num_chars; i++) {
1701 cairo_scaled_glyph_t *scaled_glyph;
1702 struct glyph_lut_elt *glyph_slot;
1704 num_bytes = _cairo_utf8_get_char_validated (p, &unicode);
1710 idx = unicode % ARRAY_LENGTH (glyph_lut);
1711 glyph_slot = &glyph_lut[idx];
1712 if (glyph_lut_unicode[idx] == unicode) {
1713 glyphs[i].index = glyph_slot->index;
1714 x += glyph_slot->x_advance;
1715 y += glyph_slot->y_advance;
1719 g = scaled_font->backend->ucs4_to_index (scaled_font, unicode);
1720 status = _cairo_scaled_glyph_lookup (scaled_font,
1722 CAIRO_SCALED_GLYPH_INFO_METRICS,
1724 if (unlikely (status))
1727 x += scaled_glyph->metrics.x_advance;
1728 y += scaled_glyph->metrics.y_advance;
1730 glyph_lut_unicode[idx] = unicode;
1731 glyph_slot->index = g;
1732 glyph_slot->x_advance = scaled_glyph->metrics.x_advance;
1733 glyph_slot->y_advance = scaled_glyph->metrics.y_advance;
1735 glyphs[i].index = g;
1739 (*clusters)[i].num_bytes = num_bytes;
1740 (*clusters)[i].num_glyphs = 1;
1744 return CAIRO_STATUS_SUCCESS;
1747 static cairo_status_t
1748 cairo_scaled_font_text_to_glyphs_internal_uncached (cairo_scaled_font_t *scaled_font,
1752 cairo_glyph_t *glyphs,
1753 cairo_text_cluster_t **clusters,
1760 for (i = 0; i < num_chars; i++) {
1764 cairo_scaled_glyph_t *scaled_glyph;
1765 cairo_status_t status;
1767 num_bytes = _cairo_utf8_get_char_validated (p, &unicode);
1773 g = scaled_font->backend->ucs4_to_index (scaled_font, unicode);
1776 * No advance needed for a single character string. So, let's speed up
1777 * one-character strings by skipping glyph lookup.
1779 if (num_chars > 1) {
1780 status = _cairo_scaled_glyph_lookup (scaled_font,
1782 CAIRO_SCALED_GLYPH_INFO_METRICS,
1784 if (unlikely (status))
1787 x += scaled_glyph->metrics.x_advance;
1788 y += scaled_glyph->metrics.y_advance;
1791 glyphs[i].index = g;
1794 (*clusters)[i].num_bytes = num_bytes;
1795 (*clusters)[i].num_glyphs = 1;
1799 return CAIRO_STATUS_SUCCESS;
1803 * cairo_scaled_font_text_to_glyphs:
1804 * @x: X position to place first glyph
1805 * @y: Y position to place first glyph
1806 * @scaled_font: a #cairo_scaled_font_t
1807 * @utf8: a string of text encoded in UTF-8
1808 * @utf8_len: length of @utf8 in bytes, or -1 if it is NUL-terminated
1809 * @glyphs: pointer to array of glyphs to fill
1810 * @num_glyphs: pointer to number of glyphs
1811 * @clusters: pointer to array of cluster mapping information to fill, or %NULL
1812 * @num_clusters: pointer to number of clusters, or %NULL
1813 * @cluster_flags: pointer to location to store cluster flags corresponding to the
1814 * output @clusters, or %NULL
1816 * Converts UTF-8 text to an array of glyphs, optionally with cluster
1817 * mapping, that can be used to render later using @scaled_font.
1819 * If @glyphs initially points to a non-%NULL value, that array is used
1820 * as a glyph buffer, and @num_glyphs should point to the number of glyph
1821 * entries available there. If the provided glyph array is too short for
1822 * the conversion, a new glyph array is allocated using cairo_glyph_allocate()
1823 * and placed in @glyphs. Upon return, @num_glyphs always contains the
1824 * number of generated glyphs. If the value @glyphs points to has changed
1825 * after the call, the user is responsible for freeing the allocated glyph
1826 * array using cairo_glyph_free(). This may happen even if the provided
1827 * array was large enough.
1829 * If @clusters is not %NULL, @num_clusters and @cluster_flags should not be %NULL,
1830 * and cluster mapping will be computed.
1831 * The semantics of how cluster array allocation works is similar to the glyph
1833 * if @clusters initially points to a non-%NULL value, that array is used
1834 * as a cluster buffer, and @num_clusters should point to the number of cluster
1835 * entries available there. If the provided cluster array is too short for
1836 * the conversion, a new cluster array is allocated using cairo_text_cluster_allocate()
1837 * and placed in @clusters. Upon return, @num_clusters always contains the
1838 * number of generated clusters. If the value @clusters points at has changed
1839 * after the call, the user is responsible for freeing the allocated cluster
1840 * array using cairo_text_cluster_free(). This may happen even if the provided
1841 * array was large enough.
1843 * In the simplest case, @glyphs and @clusters can point to %NULL initially
1844 * and a suitable array will be allocated. In code:
1845 * <informalexample><programlisting>
1846 * cairo_status_t status;
1848 * cairo_glyph_t *glyphs = NULL;
1850 * cairo_text_cluster_t *clusters = NULL;
1852 * cairo_text_cluster_flags_t cluster_flags;
1854 * status = cairo_scaled_font_text_to_glyphs (scaled_font,
1857 * &glyphs, &num_glyphs,
1858 * &clusters, &num_clusters, &cluster_flags);
1860 * if (status == CAIRO_STATUS_SUCCESS) {
1861 * cairo_show_text_glyphs (cr,
1863 * glyphs, num_glyphs,
1864 * clusters, num_clusters, cluster_flags);
1866 * cairo_glyph_free (glyphs);
1867 * cairo_text_cluster_free (clusters);
1869 * </programlisting></informalexample>
1871 * If no cluster mapping is needed:
1872 * <informalexample><programlisting>
1873 * cairo_status_t status;
1875 * cairo_glyph_t *glyphs = NULL;
1878 * status = cairo_scaled_font_text_to_glyphs (scaled_font,
1881 * &glyphs, &num_glyphs,
1885 * if (status == CAIRO_STATUS_SUCCESS) {
1886 * cairo_show_glyphs (cr, glyphs, num_glyphs);
1887 * cairo_glyph_free (glyphs);
1889 * </programlisting></informalexample>
1891 * If stack-based glyph and cluster arrays are to be used for small
1893 * <informalexample><programlisting>
1894 * cairo_status_t status;
1896 * cairo_glyph_t stack_glyphs[40];
1897 * cairo_glyph_t *glyphs = stack_glyphs;
1898 * int num_glyphs = sizeof (stack_glyphs) / sizeof (stack_glyphs[0]);
1899 * cairo_text_cluster_t stack_clusters[40];
1900 * cairo_text_cluster_t *clusters = stack_clusters;
1901 * int num_clusters = sizeof (stack_clusters) / sizeof (stack_clusters[0]);
1902 * cairo_text_cluster_flags_t cluster_flags;
1904 * status = cairo_scaled_font_text_to_glyphs (scaled_font,
1907 * &glyphs, &num_glyphs,
1908 * &clusters, &num_clusters, &cluster_flags);
1910 * if (status == CAIRO_STATUS_SUCCESS) {
1911 * cairo_show_text_glyphs (cr,
1913 * glyphs, num_glyphs,
1914 * clusters, num_clusters, cluster_flags);
1916 * if (glyphs != stack_glyphs)
1917 * cairo_glyph_free (glyphs);
1918 * if (clusters != stack_clusters)
1919 * cairo_text_cluster_free (clusters);
1921 * </programlisting></informalexample>
1923 * For details of how @clusters, @num_clusters, and @cluster_flags map input
1924 * UTF-8 text to the output glyphs see cairo_show_text_glyphs().
1926 * The output values can be readily passed to cairo_show_text_glyphs()
1927 * cairo_show_glyphs(), or related functions, assuming that the exact
1928 * same @scaled_font is used for the operation.
1930 * Return value: %CAIRO_STATUS_SUCCESS upon success, or an error status
1931 * if the input values are wrong or if conversion failed. If the input
1932 * values are correct but the conversion failed, the error status is also
1933 * set on @scaled_font.
1937 #define CACHING_THRESHOLD 16
1939 cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font,
1944 cairo_glyph_t **glyphs,
1946 cairo_text_cluster_t **clusters,
1948 cairo_text_cluster_flags_t *cluster_flags)
1951 cairo_int_status_t status;
1952 cairo_glyph_t *orig_glyphs;
1953 cairo_text_cluster_t *orig_clusters;
1955 status = scaled_font->status;
1956 if (unlikely (status))
1959 /* A slew of sanity checks */
1961 /* glyphs and num_glyphs can't be NULL */
1962 if (glyphs == NULL ||
1963 num_glyphs == NULL) {
1964 status = _cairo_error (CAIRO_STATUS_NULL_POINTER);
1968 /* Special case for NULL and -1 */
1969 if (utf8 == NULL && utf8_len == -1)
1972 /* No NULLs for non-NULLs! */
1973 if ((utf8_len && utf8 == NULL) ||
1974 (clusters && num_clusters == NULL) ||
1975 (clusters && cluster_flags == NULL)) {
1976 status = _cairo_error (CAIRO_STATUS_NULL_POINTER);
1980 /* A -1 for utf8_len means NUL-terminated */
1982 utf8_len = strlen (utf8);
1984 /* A NULL *glyphs means no prealloced glyphs array */
1985 if (glyphs && *glyphs == NULL)
1988 /* A NULL *clusters means no prealloced clusters array */
1989 if (clusters && *clusters == NULL)
1992 if (!clusters && num_clusters) {
1993 num_clusters = NULL;
1996 if (cluster_flags) {
1997 *cluster_flags = FALSE;
2000 if (!clusters && cluster_flags) {
2001 cluster_flags = NULL;
2004 /* Apart from that, no negatives */
2007 (num_clusters && *num_clusters < 0)) {
2008 status = _cairo_error (CAIRO_STATUS_NEGATIVE_COUNT);
2012 if (utf8_len == 0) {
2013 status = CAIRO_STATUS_SUCCESS;
2017 /* validate input so backend does not have to */
2018 status = _cairo_utf8_to_ucs4 (utf8, utf8_len, NULL, &num_chars);
2019 if (unlikely (status))
2022 _cairo_scaled_font_freeze_cache (scaled_font);
2024 orig_glyphs = *glyphs;
2025 orig_clusters = clusters ? *clusters : NULL;
2027 if (scaled_font->backend->text_to_glyphs) {
2028 status = scaled_font->backend->text_to_glyphs (scaled_font, x, y,
2031 clusters, num_clusters,
2033 if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
2034 if (status == CAIRO_INT_STATUS_SUCCESS) {
2035 /* The checks here are crude; we only should do them in
2036 * user-font backend, but they don't hurt here. This stuff
2037 * can be hard to get right. */
2039 if (*num_glyphs < 0) {
2040 status = _cairo_error (CAIRO_STATUS_NEGATIVE_COUNT);
2043 if (num_glyphs && *glyphs == NULL) {
2044 status = _cairo_error (CAIRO_STATUS_NULL_POINTER);
2049 if (*num_clusters < 0) {
2050 status = _cairo_error (CAIRO_STATUS_NEGATIVE_COUNT);
2053 if (num_clusters && *clusters == NULL) {
2054 status = _cairo_error (CAIRO_STATUS_NULL_POINTER);
2058 /* Don't trust the backend, validate clusters! */
2060 _cairo_validate_text_clusters (utf8, utf8_len,
2061 *glyphs, *num_glyphs,
2062 *clusters, *num_clusters,
2071 if (*num_glyphs < num_chars) {
2072 *glyphs = cairo_glyph_allocate (num_chars);
2073 if (unlikely (*glyphs == NULL)) {
2074 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
2078 *num_glyphs = num_chars;
2081 if (*num_clusters < num_chars) {
2082 *clusters = cairo_text_cluster_allocate (num_chars);
2083 if (unlikely (*clusters == NULL)) {
2084 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
2088 *num_clusters = num_chars;
2091 if (num_chars > CACHING_THRESHOLD)
2092 status = cairo_scaled_font_text_to_glyphs_internal_cached (scaled_font,
2099 status = cairo_scaled_font_text_to_glyphs_internal_uncached (scaled_font,
2106 DONE: /* error that should be logged on scaled_font happened */
2107 _cairo_scaled_font_thaw_cache (scaled_font);
2109 if (unlikely (status)) {
2111 if (*glyphs != orig_glyphs) {
2112 cairo_glyph_free (*glyphs);
2113 *glyphs = orig_glyphs;
2118 if (*clusters != orig_clusters) {
2119 cairo_text_cluster_free (*clusters);
2120 *clusters = orig_clusters;
2125 return _cairo_scaled_font_set_error (scaled_font, status);
2127 BAIL: /* error with input arguments */
2137 slim_hidden_def (cairo_scaled_font_text_to_glyphs);
2139 /* XXX: Shoot me - cairo has two basic ways of rendring text in API.
2140 * The first way is cairo_show_text() and the second way is
2141 * cairo_show_glyphs().
2143 * For the first method, each glyph location is advanced by x_advance
2144 * and y_advance computed from glyph metrics. For the second method,
2145 * app is responsible for supplying the glyph location. This gives us
2146 * opportunity to check whether the computed x_advance and _y_advance
2147 * is equala/larger than supplied glyphs difference for each adjacent
2148 * glyphs. The rational is that if the spacing between glyphs is at
2149 * least larger than computed x_advance/y_advance, there should be no
2150 * overlapping in text portion of the text images.
2152 static inline cairo_bool_t
2153 _glyph_is_next_to_glyph (cairo_glyph_t *prev,
2154 cairo_glyph_t *current,
2158 return current->x - prev->x >= x_advance - TOLERANCE &&
2159 current->y - prev->y >= y_advance - TOLERANCE;
2162 static inline cairo_bool_t
2163 _range_contains_glyph (const cairo_box_t *extents,
2166 cairo_fixed_t right,
2167 cairo_fixed_t bottom)
2169 if (left == right || top == bottom)
2172 return right > extents->p1.x &&
2173 left < extents->p2.x &&
2174 bottom > extents->p1.y &&
2175 top < extents->p2.y;
2178 static cairo_status_t
2179 _cairo_scaled_font_single_glyph_device_extents (cairo_scaled_font_t *scaled_font,
2180 const cairo_glyph_t *glyph,
2181 cairo_rectangle_int_t *extents)
2183 cairo_scaled_glyph_t *scaled_glyph;
2184 cairo_status_t status;
2186 _cairo_scaled_font_freeze_cache (scaled_font);
2187 status = _cairo_scaled_glyph_lookup (scaled_font,
2189 CAIRO_SCALED_GLYPH_INFO_METRICS,
2191 if (likely (status == CAIRO_STATUS_SUCCESS)) {
2192 cairo_bool_t round_xy = _cairo_font_options_get_round_glyph_positions (&scaled_font->options) == CAIRO_ROUND_GLYPH_POS_ON;
2197 v = _cairo_fixed_from_int (_cairo_lround (glyph->x));
2199 v = _cairo_fixed_from_double (glyph->x);
2200 box.p1.x = v + scaled_glyph->bbox.p1.x;
2201 box.p2.x = v + scaled_glyph->bbox.p2.x;
2204 v = _cairo_fixed_from_int (_cairo_lround (glyph->y));
2206 v = _cairo_fixed_from_double (glyph->y);
2207 box.p1.y = v + scaled_glyph->bbox.p1.y;
2208 box.p2.y = v + scaled_glyph->bbox.p2.y;
2210 _cairo_box_round_to_rectangle (&box, extents);
2212 _cairo_scaled_font_thaw_cache (scaled_font);
2217 * Compute a device-space bounding box for the glyphs.
2220 _cairo_scaled_font_glyph_device_extents (cairo_scaled_font_t *scaled_font,
2221 const cairo_glyph_t *glyphs,
2223 cairo_rectangle_int_t *extents,
2224 cairo_bool_t *overlap_out)
2226 cairo_status_t status = CAIRO_STATUS_SUCCESS;
2227 cairo_box_t box = { { INT_MAX, INT_MAX }, { INT_MIN, INT_MIN }};
2228 cairo_scaled_glyph_t *glyph_cache[64];
2229 cairo_bool_t overlap = overlap_out ? FALSE : TRUE;
2230 cairo_scaled_glyph_t *prev_scaled_glyph = NULL;
2231 cairo_round_glyph_positions_t round_glyph_positions = _cairo_font_options_get_round_glyph_positions (&scaled_font->options);
2233 cairo_bool_t is_next = FALSE;
2235 if (unlikely (scaled_font->status))
2236 return scaled_font->status;
2238 if (num_glyphs == 1) {
2240 *overlap_out = FALSE;
2241 return _cairo_scaled_font_single_glyph_device_extents (scaled_font,
2246 _cairo_scaled_font_freeze_cache (scaled_font);
2248 memset (glyph_cache, 0, sizeof (glyph_cache));
2250 for (i = 0; i < num_glyphs; i++) {
2251 cairo_scaled_glyph_t *scaled_glyph;
2252 cairo_fixed_t x, y, x1, y1, x2, y2;
2253 int cache_index = glyphs[i].index % ARRAY_LENGTH (glyph_cache);
2255 scaled_glyph = glyph_cache[cache_index];
2256 if (scaled_glyph == NULL ||
2257 _cairo_scaled_glyph_index (scaled_glyph) != glyphs[i].index)
2259 status = _cairo_scaled_glyph_lookup (scaled_font,
2261 CAIRO_SCALED_GLYPH_INFO_METRICS,
2263 if (unlikely (status))
2266 glyph_cache[cache_index] = scaled_glyph;
2269 if (round_glyph_positions == CAIRO_ROUND_GLYPH_POS_ON)
2270 x = _cairo_fixed_from_int (_cairo_lround (glyphs[i].x));
2272 x = _cairo_fixed_from_double (glyphs[i].x);
2273 x1 = x + scaled_glyph->bbox.p1.x;
2274 x2 = x + scaled_glyph->bbox.p2.x;
2276 if (round_glyph_positions == CAIRO_ROUND_GLYPH_POS_ON)
2277 y = _cairo_fixed_from_int (_cairo_lround (glyphs[i].y));
2279 y = _cairo_fixed_from_double (glyphs[i].y);
2280 y1 = y + scaled_glyph->bbox.p1.y;
2281 y2 = y + scaled_glyph->bbox.p2.y;
2283 if (prev_scaled_glyph != NULL && overlap == FALSE) {
2284 is_next = _glyph_is_next_to_glyph ((cairo_glyph_t *)&glyphs[i-1],
2285 (cairo_glyph_t *)&glyphs[i],
2286 prev_scaled_glyph->metrics.x_advance,
2287 prev_scaled_glyph->metrics.y_advance);
2289 if (is_next == FALSE)
2290 overlap = _range_contains_glyph (&box, x1, y1, x2, y2);
2293 if (x1 < box.p1.x) box.p1.x = x1;
2294 if (x2 > box.p2.x) box.p2.x = x2;
2295 if (y1 < box.p1.y) box.p1.y = y1;
2296 if (y2 > box.p2.y) box.p2.y = y2;
2298 prev_scaled_glyph = scaled_glyph;
2301 _cairo_scaled_font_thaw_cache (scaled_font);
2302 if (unlikely (status))
2303 return _cairo_scaled_font_set_error (scaled_font, status);
2305 if (box.p1.x < box.p2.x) {
2306 _cairo_box_round_to_rectangle (&box, extents);
2308 extents->x = extents->y = 0;
2309 extents->width = extents->height = 0;
2312 if (overlap_out != NULL)
2313 *overlap_out = overlap;
2315 return CAIRO_STATUS_SUCCESS;
2319 _cairo_scaled_font_glyph_approximate_extents (cairo_scaled_font_t *scaled_font,
2320 const cairo_glyph_t *glyphs,
2322 cairo_rectangle_int_t *extents)
2324 double x0, x1, y0, y1, pad;
2327 /* If any of the factors are suspect (i.e. the font is broken), bail */
2328 if (scaled_font->fs_extents.max_x_advance == 0 ||
2329 scaled_font->fs_extents.height == 0 ||
2330 scaled_font->max_scale == 0)
2335 assert (num_glyphs);
2337 x0 = x1 = glyphs[0].x;
2338 y0 = y1 = glyphs[0].y;
2339 for (i = 1; i < num_glyphs; i++) {
2351 pad = MAX(scaled_font->fs_extents.max_x_advance,
2352 scaled_font->fs_extents.height);
2353 pad *= scaled_font->max_scale;
2355 extents->x = floor (x0 - pad);
2356 extents->width = ceil (x1 + pad) - extents->x;
2357 extents->y = floor (y0 - pad);
2358 extents->height = ceil (y1 + pad) - extents->y;
2365 _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
2366 cairo_operator_t op,
2367 const cairo_pattern_t *pattern,
2368 cairo_surface_t *surface,
2374 unsigned int height,
2375 cairo_glyph_t *glyphs,
2377 cairo_region_t *clip_region)
2379 cairo_int_status_t status;
2380 cairo_surface_t *mask = NULL;
2381 cairo_format_t mask_format = CAIRO_FORMAT_A1; /* shut gcc up */
2382 cairo_surface_pattern_t mask_pattern;
2385 /* These operators aren't interpreted the same way by the backends;
2386 * they are implemented in terms of other operators in cairo-gstate.c
2388 assert (op != CAIRO_OPERATOR_SOURCE && op != CAIRO_OPERATOR_CLEAR);
2390 if (scaled_font->status)
2391 return scaled_font->status;
2394 return CAIRO_STATUS_SUCCESS;
2396 if (scaled_font->backend->show_glyphs != NULL) {
2397 int remaining_glyphs = num_glyphs;
2398 status = scaled_font->backend->show_glyphs (scaled_font,
2407 glyphs += num_glyphs - remaining_glyphs;
2408 num_glyphs = remaining_glyphs;
2409 if (remaining_glyphs == 0)
2410 status = CAIRO_INT_STATUS_SUCCESS;
2411 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
2412 return _cairo_scaled_font_set_error (scaled_font, status);
2415 /* Font display routine either does not exist or failed. */
2417 _cairo_scaled_font_freeze_cache (scaled_font);
2419 for (i = 0; i < num_glyphs; i++) {
2421 cairo_image_surface_t *glyph_surface;
2422 cairo_scaled_glyph_t *scaled_glyph;
2424 status = _cairo_scaled_glyph_lookup (scaled_font,
2426 CAIRO_SCALED_GLYPH_INFO_SURFACE,
2429 if (unlikely (status))
2432 glyph_surface = scaled_glyph->surface;
2434 /* To start, create the mask using the format from the first
2435 * glyph. Later we'll deal with different formats. */
2437 mask_format = glyph_surface->format;
2438 mask = cairo_image_surface_create (mask_format, width, height);
2439 status = mask->status;
2440 if (unlikely (status))
2444 /* If we have glyphs of different formats, we "upgrade" the mask
2445 * to the wider of the formats. */
2446 if (glyph_surface->format != mask_format &&
2447 _cairo_format_bits_per_pixel (mask_format) <
2448 _cairo_format_bits_per_pixel (glyph_surface->format) )
2450 cairo_surface_t *new_mask;
2452 switch (glyph_surface->format) {
2453 case CAIRO_FORMAT_ARGB32:
2454 case CAIRO_FORMAT_A8:
2455 case CAIRO_FORMAT_A1:
2456 mask_format = glyph_surface->format;
2458 case CAIRO_FORMAT_RGB16_565:
2459 case CAIRO_FORMAT_RGB24:
2460 case CAIRO_FORMAT_RGB30:
2461 case CAIRO_FORMAT_INVALID:
2464 mask_format = CAIRO_FORMAT_ARGB32;
2468 new_mask = cairo_image_surface_create (mask_format, width, height);
2469 status = new_mask->status;
2470 if (unlikely (status)) {
2471 cairo_surface_destroy (new_mask);
2475 _cairo_pattern_init_for_surface (&mask_pattern, mask);
2476 /* Note that we only upgrade masks, i.e. A1 -> A8 -> ARGB32, so there is
2477 * never any component alpha here.
2479 status = _cairo_surface_composite (CAIRO_OPERATOR_ADD,
2480 &_cairo_pattern_white.base,
2489 _cairo_pattern_fini (&mask_pattern.base);
2491 if (unlikely (status)) {
2492 cairo_surface_destroy (new_mask);
2496 cairo_surface_destroy (mask);
2500 if (glyph_surface->width && glyph_surface->height) {
2501 cairo_surface_pattern_t glyph_pattern;
2503 /* round glyph locations to the nearest pixel */
2504 /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
2505 x = _cairo_lround (glyphs[i].x -
2506 glyph_surface->base.device_transform.x0);
2507 y = _cairo_lround (glyphs[i].y -
2508 glyph_surface->base.device_transform.y0);
2510 _cairo_pattern_init_for_surface (&glyph_pattern,
2511 &glyph_surface->base);
2512 if (mask_format == CAIRO_FORMAT_ARGB32)
2513 glyph_pattern.base.has_component_alpha = TRUE;
2515 status = _cairo_surface_composite (CAIRO_OPERATOR_ADD,
2516 &_cairo_pattern_white.base,
2517 &glyph_pattern.base,
2521 x - dest_x, y - dest_y,
2522 glyph_surface->width,
2523 glyph_surface->height,
2526 _cairo_pattern_fini (&glyph_pattern.base);
2528 if (unlikely (status))
2533 _cairo_pattern_init_for_surface (&mask_pattern, mask);
2534 if (mask_format == CAIRO_FORMAT_ARGB32)
2535 mask_pattern.base.has_component_alpha = TRUE;
2537 status = _cairo_surface_composite (op, pattern, &mask_pattern.base,
2545 _cairo_pattern_fini (&mask_pattern.base);
2548 _cairo_scaled_font_thaw_cache (scaled_font);
2551 cairo_surface_destroy (mask);
2552 return _cairo_scaled_font_set_error (scaled_font, status);
2556 /* Add a single-device-unit rectangle to a path. */
2557 static cairo_status_t
2558 _add_unit_rectangle_to_path (cairo_path_fixed_t *path,
2562 cairo_status_t status;
2564 status = _cairo_path_fixed_move_to (path, x, y);
2565 if (unlikely (status))
2568 status = _cairo_path_fixed_rel_line_to (path,
2569 _cairo_fixed_from_int (1),
2570 _cairo_fixed_from_int (0));
2571 if (unlikely (status))
2574 status = _cairo_path_fixed_rel_line_to (path,
2575 _cairo_fixed_from_int (0),
2576 _cairo_fixed_from_int (1));
2577 if (unlikely (status))
2580 status = _cairo_path_fixed_rel_line_to (path,
2581 _cairo_fixed_from_int (-1),
2582 _cairo_fixed_from_int (0));
2583 if (unlikely (status))
2586 return _cairo_path_fixed_close_path (path);
2590 * _trace_mask_to_path:
2591 * @bitmap: An alpha mask (either %CAIRO_FORMAT_A1 or %CAIRO_FORMAT_A8)
2592 * @path: An initialized path to hold the result
2594 * Given a mask surface, (an alpha image), fill out the provided path
2595 * so that when filled it would result in something that approximates
2598 * Note: The current tracing code here is extremely primitive. It
2599 * operates only on an A1 surface, (converting an A8 surface to A1 if
2600 * necessary), and performs the tracing by drawing a little square
2601 * around each pixel that is on in the mask. We do not pretend that
2602 * this is a high-quality result. But we are leaving it up to someone
2603 * who cares enough about getting a better result to implement
2604 * something more sophisticated.
2606 static cairo_status_t
2607 _trace_mask_to_path (cairo_image_surface_t *mask,
2608 cairo_path_fixed_t *path,
2609 double tx, double ty)
2612 int rows, cols, bytes_per_row;
2615 cairo_fixed_t x0, y0;
2616 cairo_fixed_t px, py;
2617 cairo_status_t status;
2619 mask = _cairo_image_surface_coerce_to_format (mask, CAIRO_FORMAT_A1);
2620 status = mask->base.status;
2621 if (unlikely (status)) {
2622 cairo_surface_destroy (&mask->base);
2626 cairo_surface_get_device_offset (&mask->base, &xoff, &yoff);
2627 x0 = _cairo_fixed_from_double (tx - xoff);
2628 y0 = _cairo_fixed_from_double (ty - yoff);
2630 bytes_per_row = (mask->width + 7) / 8;
2632 for (y = 0, rows = mask->height; rows--; row += mask->stride, y++) {
2633 const uint8_t *byte_ptr = row;
2635 py = _cairo_fixed_from_int (y);
2636 for (cols = bytes_per_row; cols--; ) {
2637 uint8_t byte = *byte_ptr++;
2643 byte = CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (byte);
2644 for (bit = 1 << 7; bit && x < mask->width; bit >>= 1, x++) {
2646 px = _cairo_fixed_from_int (x);
2647 status = _add_unit_rectangle_to_path (path,
2650 if (unlikely (status))
2658 cairo_surface_destroy (&mask->base);
2664 _cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font,
2665 const cairo_glyph_t *glyphs,
2667 cairo_path_fixed_t *path)
2669 cairo_int_status_t status;
2672 status = scaled_font->status;
2673 if (unlikely (status))
2676 _cairo_scaled_font_freeze_cache (scaled_font);
2677 for (i = 0; i < num_glyphs; i++) {
2678 cairo_scaled_glyph_t *scaled_glyph;
2680 status = _cairo_scaled_glyph_lookup (scaled_font,
2682 CAIRO_SCALED_GLYPH_INFO_PATH,
2684 if (status == CAIRO_INT_STATUS_SUCCESS) {
2685 status = _cairo_path_fixed_append (path,
2687 _cairo_fixed_from_double (glyphs[i].x),
2688 _cairo_fixed_from_double (glyphs[i].y));
2690 } else if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
2691 /* If the font is incapable of providing a path, then we'll
2692 * have to trace our own from a surface.
2694 status = _cairo_scaled_glyph_lookup (scaled_font,
2696 CAIRO_SCALED_GLYPH_INFO_SURFACE,
2698 if (unlikely (status))
2701 status = _trace_mask_to_path (scaled_glyph->surface, path,
2702 glyphs[i].x, glyphs[i].y);
2705 if (unlikely (status))
2709 _cairo_scaled_font_thaw_cache (scaled_font);
2711 return _cairo_scaled_font_set_error (scaled_font, status);
2715 * _cairo_scaled_glyph_set_metrics:
2716 * @scaled_glyph: a #cairo_scaled_glyph_t
2717 * @scaled_font: a #cairo_scaled_font_t
2718 * @fs_metrics: a #cairo_text_extents_t in font space
2720 * _cairo_scaled_glyph_set_metrics() stores user space metrics
2721 * for the specified glyph given font space metrics. It is
2722 * called by the font backend when initializing a glyph with
2723 * %CAIRO_SCALED_GLYPH_INFO_METRICS.
2726 _cairo_scaled_glyph_set_metrics (cairo_scaled_glyph_t *scaled_glyph,
2727 cairo_scaled_font_t *scaled_font,
2728 cairo_text_extents_t *fs_metrics)
2730 cairo_bool_t first = TRUE;
2732 double min_user_x = 0.0, max_user_x = 0.0, min_user_y = 0.0, max_user_y = 0.0;
2733 double min_device_x = 0.0, max_device_x = 0.0, min_device_y = 0.0, max_device_y = 0.0;
2734 double device_x_advance, device_y_advance;
2736 scaled_glyph->fs_metrics = *fs_metrics;
2738 for (hm = 0.0; hm <= 1.0; hm += 1.0)
2739 for (wm = 0.0; wm <= 1.0; wm += 1.0) {
2742 /* Transform this corner to user space */
2743 x = fs_metrics->x_bearing + fs_metrics->width * wm;
2744 y = fs_metrics->y_bearing + fs_metrics->height * hm;
2745 cairo_matrix_transform_point (&scaled_font->font_matrix,
2748 min_user_x = max_user_x = x;
2749 min_user_y = max_user_y = y;
2751 if (x < min_user_x) min_user_x = x;
2752 if (x > max_user_x) max_user_x = x;
2753 if (y < min_user_y) min_user_y = y;
2754 if (y > max_user_y) max_user_y = y;
2757 /* Transform this corner to device space from glyph origin */
2758 x = fs_metrics->x_bearing + fs_metrics->width * wm;
2759 y = fs_metrics->y_bearing + fs_metrics->height * hm;
2760 cairo_matrix_transform_distance (&scaled_font->scale,
2764 min_device_x = max_device_x = x;
2765 min_device_y = max_device_y = y;
2767 if (x < min_device_x) min_device_x = x;
2768 if (x > max_device_x) max_device_x = x;
2769 if (y < min_device_y) min_device_y = y;
2770 if (y > max_device_y) max_device_y = y;
2774 scaled_glyph->metrics.x_bearing = min_user_x;
2775 scaled_glyph->metrics.y_bearing = min_user_y;
2776 scaled_glyph->metrics.width = max_user_x - min_user_x;
2777 scaled_glyph->metrics.height = max_user_y - min_user_y;
2779 scaled_glyph->metrics.x_advance = fs_metrics->x_advance;
2780 scaled_glyph->metrics.y_advance = fs_metrics->y_advance;
2781 cairo_matrix_transform_distance (&scaled_font->font_matrix,
2782 &scaled_glyph->metrics.x_advance,
2783 &scaled_glyph->metrics.y_advance);
2785 device_x_advance = fs_metrics->x_advance;
2786 device_y_advance = fs_metrics->y_advance;
2787 cairo_matrix_transform_distance (&scaled_font->scale,
2791 scaled_glyph->bbox.p1.x = _cairo_fixed_from_double (min_device_x);
2792 scaled_glyph->bbox.p1.y = _cairo_fixed_from_double (min_device_y);
2793 scaled_glyph->bbox.p2.x = _cairo_fixed_from_double (max_device_x);
2794 scaled_glyph->bbox.p2.y = _cairo_fixed_from_double (max_device_y);
2796 scaled_glyph->x_advance = _cairo_lround (device_x_advance);
2797 scaled_glyph->y_advance = _cairo_lround (device_y_advance);
2799 scaled_glyph->has_info |= CAIRO_SCALED_GLYPH_INFO_METRICS;
2803 _cairo_scaled_glyph_set_surface (cairo_scaled_glyph_t *scaled_glyph,
2804 cairo_scaled_font_t *scaled_font,
2805 cairo_image_surface_t *surface)
2807 if (scaled_glyph->surface != NULL)
2808 cairo_surface_destroy (&scaled_glyph->surface->base);
2810 /* sanity check the backend glyph contents */
2811 _cairo_debug_check_image_surface_is_defined (&surface->base);
2812 scaled_glyph->surface = surface;
2814 if (surface != NULL)
2815 scaled_glyph->has_info |= CAIRO_SCALED_GLYPH_INFO_SURFACE;
2817 scaled_glyph->has_info &= ~CAIRO_SCALED_GLYPH_INFO_SURFACE;
2821 _cairo_scaled_glyph_set_path (cairo_scaled_glyph_t *scaled_glyph,
2822 cairo_scaled_font_t *scaled_font,
2823 cairo_path_fixed_t *path)
2825 if (scaled_glyph->path != NULL)
2826 _cairo_path_fixed_destroy (scaled_glyph->path);
2828 scaled_glyph->path = path;
2831 scaled_glyph->has_info |= CAIRO_SCALED_GLYPH_INFO_PATH;
2833 scaled_glyph->has_info &= ~CAIRO_SCALED_GLYPH_INFO_PATH;
2837 _cairo_scaled_glyph_set_recording_surface (cairo_scaled_glyph_t *scaled_glyph,
2838 cairo_scaled_font_t *scaled_font,
2839 cairo_surface_t *recording_surface)
2841 if (scaled_glyph->recording_surface != NULL) {
2842 cairo_surface_finish (scaled_glyph->recording_surface);
2843 cairo_surface_destroy (scaled_glyph->recording_surface);
2846 scaled_glyph->recording_surface = recording_surface;
2848 if (recording_surface != NULL)
2849 scaled_glyph->has_info |= CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE;
2851 scaled_glyph->has_info &= ~CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE;
2855 _cairo_scaled_glyph_page_can_remove (const void *closure)
2857 const cairo_scaled_glyph_page_t *page = closure;
2858 const cairo_scaled_font_t *scaled_font;
2860 scaled_font = (cairo_scaled_font_t *) page->cache_entry.hash;
2861 return scaled_font->cache_frozen == 0;
2864 static cairo_status_t
2865 _cairo_scaled_font_allocate_glyph (cairo_scaled_font_t *scaled_font,
2866 cairo_scaled_glyph_t **scaled_glyph)
2868 cairo_scaled_glyph_page_t *page;
2869 cairo_status_t status;
2871 assert (scaled_font->cache_frozen);
2873 /* only the first page in the list may contain available slots */
2874 if (! cairo_list_is_empty (&scaled_font->glyph_pages)) {
2875 page = cairo_list_last_entry (&scaled_font->glyph_pages,
2876 cairo_scaled_glyph_page_t,
2878 if (page->num_glyphs < CAIRO_SCALED_GLYPH_PAGE_SIZE) {
2879 *scaled_glyph = &page->glyphs[page->num_glyphs++];
2880 return CAIRO_STATUS_SUCCESS;
2884 page = malloc (sizeof (cairo_scaled_glyph_page_t));
2885 if (unlikely (page == NULL))
2886 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2888 page->cache_entry.hash = (unsigned long) scaled_font;
2889 page->cache_entry.size = 1; /* XXX occupancy weighting? */
2890 page->num_glyphs = 0;
2892 CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex);
2893 if (scaled_font->global_cache_frozen == FALSE) {
2894 if (unlikely (cairo_scaled_glyph_page_cache.hash_table == NULL)) {
2895 status = _cairo_cache_init (&cairo_scaled_glyph_page_cache,
2897 _cairo_scaled_glyph_page_can_remove,
2898 _cairo_scaled_glyph_page_pluck,
2899 MAX_GLYPH_PAGES_CACHED);
2900 if (unlikely (status)) {
2901 CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex);
2907 _cairo_cache_freeze (&cairo_scaled_glyph_page_cache);
2908 scaled_font->global_cache_frozen = TRUE;
2911 status = _cairo_cache_insert (&cairo_scaled_glyph_page_cache,
2912 &page->cache_entry);
2913 CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex);
2914 if (unlikely (status)) {
2919 cairo_list_add_tail (&page->link, &scaled_font->glyph_pages);
2921 *scaled_glyph = &page->glyphs[page->num_glyphs++];
2922 return CAIRO_STATUS_SUCCESS;
2926 _cairo_scaled_font_free_last_glyph (cairo_scaled_font_t *scaled_font,
2927 cairo_scaled_glyph_t *scaled_glyph)
2929 cairo_scaled_glyph_page_t *page;
2931 assert (! cairo_list_is_empty (&scaled_font->glyph_pages));
2932 page = cairo_list_last_entry (&scaled_font->glyph_pages,
2933 cairo_scaled_glyph_page_t,
2935 assert (scaled_glyph == &page->glyphs[page->num_glyphs-1]);
2937 _cairo_scaled_glyph_fini (scaled_font, scaled_glyph);
2939 if (--page->num_glyphs == 0) {
2940 CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex);
2941 /* Temporarily disconnect callback to avoid recursive locking */
2942 cairo_scaled_glyph_page_cache.entry_destroy = NULL;
2943 _cairo_cache_remove (&cairo_scaled_glyph_page_cache,
2944 &page->cache_entry);
2945 _cairo_scaled_glyph_page_destroy (scaled_font, page);
2946 cairo_scaled_glyph_page_cache.entry_destroy = _cairo_scaled_glyph_page_pluck;
2947 CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex);
2952 * _cairo_scaled_glyph_lookup:
2953 * @scaled_font: a #cairo_scaled_font_t
2954 * @index: the glyph to create
2955 * @info: a #cairo_scaled_glyph_info_t marking which portions of
2956 * the glyph should be filled in.
2957 * @scaled_glyph_ret: a #cairo_scaled_glyph_t where the glyph
2960 * If the desired info is not available, (for example, when trying to
2961 * get INFO_PATH with a bitmapped font), this function will return
2962 * %CAIRO_INT_STATUS_UNSUPPORTED.
2964 * Note: This function must be called with the scaled font frozen, and it must
2965 * remain frozen for as long as the @scaled_glyph_ret is alive. (If the scaled
2966 * font was not frozen, then there is no guarantee that the glyph would not be
2967 * evicted before you tried to access it.) See
2968 * _cairo_scaled_font_freeze_cache() and _cairo_scaled_font_thaw_cache().
2970 * Returns: a glyph with the requested portions filled in. Glyph
2971 * lookup is cached and glyph will be automatically freed along
2972 * with the scaled_font so no explicit free is required.
2973 * @info can be one or more of:
2974 * %CAIRO_SCALED_GLYPH_INFO_METRICS - glyph metrics and bounding box
2975 * %CAIRO_SCALED_GLYPH_INFO_SURFACE - surface holding glyph image
2976 * %CAIRO_SCALED_GLYPH_INFO_PATH - path holding glyph outline in device space
2979 _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font,
2980 unsigned long index,
2981 cairo_scaled_glyph_info_t info,
2982 cairo_scaled_glyph_t **scaled_glyph_ret)
2984 cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
2985 cairo_scaled_glyph_t *scaled_glyph;
2986 cairo_scaled_glyph_info_t need_info;
2988 *scaled_glyph_ret = NULL;
2990 if (unlikely (scaled_font->status))
2991 return scaled_font->status;
2993 assert (CAIRO_MUTEX_IS_LOCKED(scaled_font->mutex));
2994 assert (scaled_font->cache_frozen);
2996 if (CAIRO_INJECT_FAULT ())
2997 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
3000 * Check cache for glyph
3002 scaled_glyph = _cairo_hash_table_lookup (scaled_font->glyphs,
3003 (cairo_hash_entry_t *) &index);
3004 if (scaled_glyph == NULL) {
3005 status = _cairo_scaled_font_allocate_glyph (scaled_font, &scaled_glyph);
3006 if (unlikely (status))
3009 memset (scaled_glyph, 0, sizeof (cairo_scaled_glyph_t));
3010 _cairo_scaled_glyph_set_index (scaled_glyph, index);
3011 cairo_list_init (&scaled_glyph->dev_privates);
3013 /* ask backend to initialize metrics and shape fields */
3015 scaled_font->backend->scaled_glyph_init (scaled_font,
3017 info | CAIRO_SCALED_GLYPH_INFO_METRICS);
3018 if (unlikely (status)) {
3019 _cairo_scaled_font_free_last_glyph (scaled_font, scaled_glyph);
3023 status = _cairo_hash_table_insert (scaled_font->glyphs,
3024 &scaled_glyph->hash_entry);
3025 if (unlikely (status)) {
3026 _cairo_scaled_font_free_last_glyph (scaled_font, scaled_glyph);
3032 * Check and see if the glyph, as provided,
3033 * already has the requested data and amend it if not
3035 need_info = info & ~scaled_glyph->has_info;
3037 status = scaled_font->backend->scaled_glyph_init (scaled_font,
3040 if (unlikely (status))
3043 /* Don't trust the scaled_glyph_init() return value, the font
3044 * backend may not even know about some of the info. For example,
3045 * no backend other than the user-fonts knows about recording-surface
3047 if (info & ~scaled_glyph->has_info)
3048 return CAIRO_INT_STATUS_UNSUPPORTED;
3051 *scaled_glyph_ret = scaled_glyph;
3052 return CAIRO_STATUS_SUCCESS;
3055 /* It's not an error for the backend to not support the info we want. */
3056 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
3057 status = _cairo_scaled_font_set_error (scaled_font, status);
3062 _cairo_scaled_font_get_max_scale (cairo_scaled_font_t *scaled_font)
3064 return scaled_font->max_scale;
3069 * cairo_scaled_font_get_font_face:
3070 * @scaled_font: a #cairo_scaled_font_t
3072 * Gets the font face that this scaled font uses. This might be the
3073 * font face passed to cairo_scaled_font_create(), but this does not
3074 * hold true for all possible cases.
3076 * Return value: The #cairo_font_face_t with which @scaled_font was
3077 * created. This object is owned by cairo. To keep a reference to it,
3078 * you must call cairo_scaled_font_reference().
3083 cairo_scaled_font_get_font_face (cairo_scaled_font_t *scaled_font)
3085 if (scaled_font->status)
3086 return (cairo_font_face_t*) &_cairo_font_face_nil;
3088 if (scaled_font->original_font_face != NULL)
3089 return scaled_font->original_font_face;
3091 return scaled_font->font_face;
3093 slim_hidden_def (cairo_scaled_font_get_font_face);
3096 * cairo_scaled_font_get_font_matrix:
3097 * @scaled_font: a #cairo_scaled_font_t
3098 * @font_matrix: return value for the matrix
3100 * Stores the font matrix with which @scaled_font was created into
3106 cairo_scaled_font_get_font_matrix (cairo_scaled_font_t *scaled_font,
3107 cairo_matrix_t *font_matrix)
3109 if (scaled_font->status) {
3110 cairo_matrix_init_identity (font_matrix);
3114 *font_matrix = scaled_font->font_matrix;
3116 slim_hidden_def (cairo_scaled_font_get_font_matrix);
3119 * cairo_scaled_font_get_ctm:
3120 * @scaled_font: a #cairo_scaled_font_t
3121 * @ctm: return value for the CTM
3123 * Stores the CTM with which @scaled_font was created into @ctm.
3124 * Note that the translation offsets (x0, y0) of the CTM are ignored
3125 * by cairo_scaled_font_create(). So, the matrix this
3126 * function returns always has 0,0 as x0,y0.
3131 cairo_scaled_font_get_ctm (cairo_scaled_font_t *scaled_font,
3132 cairo_matrix_t *ctm)
3134 if (scaled_font->status) {
3135 cairo_matrix_init_identity (ctm);
3139 *ctm = scaled_font->ctm;
3141 slim_hidden_def (cairo_scaled_font_get_ctm);
3144 * cairo_scaled_font_get_scale_matrix:
3145 * @scaled_font: a #cairo_scaled_font_t
3146 * @scale_matrix: return value for the matrix
3148 * Stores the scale matrix of @scaled_font into @matrix.
3149 * The scale matrix is product of the font matrix and the ctm
3150 * associated with the scaled font, and hence is the matrix mapping from
3151 * font space to device space.
3156 cairo_scaled_font_get_scale_matrix (cairo_scaled_font_t *scaled_font,
3157 cairo_matrix_t *scale_matrix)
3159 if (scaled_font->status) {
3160 cairo_matrix_init_identity (scale_matrix);
3164 *scale_matrix = scaled_font->scale;
3168 * cairo_scaled_font_get_font_options:
3169 * @scaled_font: a #cairo_scaled_font_t
3170 * @options: return value for the font options
3172 * Stores the font options with which @scaled_font was created into
3178 cairo_scaled_font_get_font_options (cairo_scaled_font_t *scaled_font,
3179 cairo_font_options_t *options)
3181 if (cairo_font_options_status (options))
3184 if (scaled_font->status) {
3185 _cairo_font_options_init_default (options);
3189 _cairo_font_options_init_copy (options, &scaled_font->options);
3191 slim_hidden_def (cairo_scaled_font_get_font_options);