Bug Summary

File:root/firefox-clang/gfx/cairo/cairo/src/cairo-scaled-font.c
Warning:line 1563, column 2
Value stored to 'status' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

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