Bug Summary

File:root/firefox-clang/gfx/cairo/cairo/src/cairo-ft-font.c
Warning:line 553, column 18
Null pointer passed to 1st parameter expecting 'nonnull'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -O2 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name cairo-ft-font.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-23/lib/clang/23 -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 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 -U NDEBUG -internal-isystem /usr/lib/llvm-23/lib/clang/23/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -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-character-conversion -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 -fdiagnostics-absolute-paths -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -mllvm -dwarf-linkage-names=Abstract -faddrsig -fdwarf2-cfi-asm -o /tmp/scan-build-2026-11-12-001017-1011516-1 -x c /root/firefox-clang/gfx/cairo/cairo/src/cairo-ft-font.c
1/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
2/* cairo - a vector graphics library with display and print output
3 *
4 * Copyright © 2000 Keith Packard
5 * Copyright © 2005 Red Hat, Inc
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it either under the terms of the GNU Lesser General Public
9 * License version 2.1 as published by the Free Software Foundation
10 * (the "LGPL") or, at your option, under the terms of the Mozilla
11 * Public License Version 1.1 (the "MPL"). If you do not alter this
12 * notice, a recipient may use your version of this file under either
13 * the MPL or the LGPL.
14 *
15 * You should have received a copy of the LGPL along with this library
16 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
18 * You should have received a copy of the MPL along with this library
19 * in the file COPYING-MPL-1.1
20 *
21 * The contents of this file are subject to the Mozilla Public License
22 * Version 1.1 (the "License"); you may not use this file except in
23 * compliance with the License. You may obtain a copy of the License at
24 * http://www.mozilla.org/MPL/
25 *
26 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
27 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
28 * the specific language governing rights and limitations.
29 *
30 * The Original Code is the cairo graphics library.
31 *
32 * The Initial Developer of the Original Code is Red Hat, Inc.
33 *
34 * Contributor(s):
35 * Graydon Hoare <graydon@redhat.com>
36 * Owen Taylor <otaylor@redhat.com>
37 * Keith Packard <keithp@keithp.com>
38 * Carl Worth <cworth@cworth.org>
39 */
40
41#define _DEFAULT_SOURCE1 /* for strdup() */
42#include "cairoint.h"
43
44#include "cairo-error-private.h"
45#include "cairo-image-surface-private.h"
46#include "cairo-ft-private.h"
47#include "cairo-list-inline.h"
48#include "cairo-path-private.h"
49#include "cairo-pattern-private.h"
50#include "cairo-pixman-private.h"
51#include "cairo-recording-surface-private.h"
52
53#include <float.h>
54
55#include "cairo-fontconfig-private.h"
56
57#include <ft2build.h>
58#include FT_FREETYPE_H<freetype/freetype.h>
59#include FT_OUTLINE_H<freetype/ftoutln.h>
60#include FT_IMAGE_H<freetype/ftimage.h>
61#include FT_BITMAP_H<freetype/ftbitmap.h>
62#include FT_TRUETYPE_TABLES_H<freetype/tttables.h>
63#ifndef FT_FONT_FORMATS_H<freetype/ftfntfmt.h>
64#define FT_FONT_FORMATS_H<freetype/ftfntfmt.h> FT_XFREE86_H<freetype/ftfntfmt.h>
65#define FT_Get_Font_Format FT_Get_X11_Font_Format
66#endif
67#include FT_FONT_FORMATS_H<freetype/ftfntfmt.h>
68#include FT_MULTIPLE_MASTERS_H<freetype/ftmm.h>
69#include FT_SYNTHESIS_H<freetype/ftsynth.h>
70
71#ifdef FT_COLOR_H<freetype/ftcolor.h>
72#include FT_COLOR_H<freetype/ftcolor.h>
73#endif
74
75#include FT_LCD_FILTER_H<freetype/ftlcdfil.h>
76
77#if HAVE_FT_SVG_DOCUMENT
78#include FT_OTSVG_H<freetype/otsvg.h>
79#endif
80
81#if HAVE_UNISTD_H1
82#include <unistd.h>
83#elif !defined(access)
84#define access(p, m) 0
85#endif
86#include <dlfcn.h>
87
88/* FreeType version older than 2.11 does not have the FT_RENDER_MODE_SDF enum value in FT_Render_Mode */
89#if FREETYPE_MAJOR2 > 2 || (FREETYPE_MAJOR2 == 2 && FREETYPE_MINOR14 >= 11)
90#define HAVE_FT_RENDER_MODE_SDF1 1
91#endif
92
93#define DOUBLE_FROM_26_6(t)((double)(t) / 64.0) ((double)(t) / 64.0)
94#define DOUBLE_TO_16_16(d)((FT_Fixed)((d) * 65536.0)) ((FT_Fixed)((d) * 65536.0))
95#define DOUBLE_FROM_16_16(t)((double)(t) / 65536.0) ((double)(t) / 65536.0)
96
97/* SCALE() mimics code from commit 399b00a99b2bbc1c56a05974c936aa69a08021f5
98 * concerning a potential division by 0, but instead of doing a * (1/b), it
99 * does a/b, thus improving the accuracy. With a * (1/b), for a bitmap font
100 * of size 13, the computed -y_bearing was 0x1.6000000000001p+3 instead of
101 * 0x1.6p+3 (= 11). This triggered a bug in GNU Emacs (when built against
102 * cairo), which rounded the value to an integer with ceil().
103 * Details:
104 * https://gitlab.freedesktop.org/cairo/cairo/-/issues/503
105 * https://debbugs.gnu.org/cgi/bugreport.cgi?bug=44284
106 *
107 * Note that rounding errors are not necessarily expected by applications
108 * in simple cases like the GNU Emacs one (an identity transformation,
109 * which should normally leave the inputs unchanged). However, with the
110 * current cairo code, due to the scaling, there is no guarantee that
111 * rounding errors will always be avoided at the end. For instance,
112 * (a/b)*b may be different from a, but this is still better than doing
113 * (a*(1/b))*b.
114 *
115 * According to the commit mentioned above, avoiding a division by zero
116 * was an attempt to fix
117 * https://bugzilla.gnome.org/show_bug.cgi?id=311299
118 * but this did not actually solve the problem. So it might be possible
119 * to change SCALE() to just do (a) / (b).
120 */
121#define SCALE(a,b)((b) == 0 ? 0.0 : (a) / (b)) ((b) == 0 ? 0.0 : (a) / (b))
122
123/* This is the max number of FT_face objects we keep open at once
124 */
125#define MAX_OPEN_FACES10 10
126
127extern void mozilla_AddRefSharedFTFace(void* aContext);
128extern void mozilla_ReleaseSharedFTFace(void* aContext, void* aOwner);
129/* Returns true if the face's state has been modified by another owner. */
130extern int mozilla_LockSharedFTFace(void* aContext, void* aOwner);
131extern void mozilla_UnlockSharedFTFace(void* aContext);
132extern FT_Error mozilla_LoadFTGlyph(FT_Face aFace, uint32_t aGlyphIndex, int32_t aFlags);
133extern void mozilla_LockFTLibrary(FT_Library aLibrary);
134extern void mozilla_UnlockFTLibrary(FT_Library aLibrary);
135
136#define CAIRO_FT_LOCK(unscaled)((unscaled)->face_context ? (void)mozilla_LockSharedFTFace
((unscaled)->face_context, ((void*)0)) : (void)pthread_mutex_lock
(&((unscaled)->mutex)))
\
137 ((unscaled)->face_context \
138 ? (void)mozilla_LockSharedFTFace((unscaled)->face_context, NULL((void*)0)) \
139 : (void)CAIRO_MUTEX_LOCK((unscaled)->mutex)pthread_mutex_lock (&((unscaled)->mutex)))
140#define CAIRO_FT_UNLOCK(unscaled)((unscaled)->face_context ? mozilla_UnlockSharedFTFace((unscaled
)->face_context) : (void)pthread_mutex_unlock (&((unscaled
)->mutex)))
\
141 ((unscaled)->face_context \
142 ? mozilla_UnlockSharedFTFace((unscaled)->face_context) \
143 : (void)CAIRO_MUTEX_UNLOCK((unscaled)->mutex)pthread_mutex_unlock (&((unscaled)->mutex)))
144
145/**
146 * Function types for FreeType symbols we'll look up at runtime, rather than
147 * relying on build-time checks for availability.
148 */
149typedef FT_Error (*GetVarFunc) (FT_Face, FT_MM_Var**);
150typedef FT_Error (*DoneVarFunc) (FT_Library, FT_MM_Var*);
151typedef FT_Error (*GetVarDesignCoordsFunc) (FT_Face, FT_UInt, FT_Fixed*);
152typedef FT_Error (*SetVarDesignCoordsFunc) (FT_Face, FT_UInt, FT_Fixed*);
153typedef FT_Error (*GetVarBlendCoordsFunc) (FT_Face, FT_UInt, FT_Fixed*);
154
155/**
156 * SECTION:cairo-ft
157 * @Title: FreeType Fonts
158 * @Short_Description: Font support for FreeType
159 * @See_Also: #cairo_font_face_t
160 *
161 * The FreeType font backend is primarily used to render text on GNU/Linux
162 * systems, but can be used on other platforms too.
163 **/
164
165/**
166 * CAIRO_HAS_FT_FONT:
167 *
168 * Defined if the FreeType font backend is available.
169 * This macro can be used to conditionally compile backend-specific code.
170 *
171 * Since: 1.0
172 **/
173
174/**
175 * CAIRO_HAS_FC_FONT:
176 *
177 * Defined if the Fontconfig-specific functions of the FreeType font backend
178 * are available.
179 * This macro can be used to conditionally compile backend-specific code.
180 *
181 * Since: 1.10
182 **/
183
184/*
185 * The simple 2x2 matrix is converted into separate scale and shape
186 * factors so that hinting works right
187 */
188
189typedef struct _cairo_ft_font_transform {
190 double x_scale, y_scale;
191 double shape[2][2];
192} cairo_ft_font_transform_t;
193
194/*
195 * We create an object that corresponds to a single font on the disk;
196 * (identified by a filename/id pair) these are shared between all
197 * fonts using that file. For cairo_ft_font_face_create_for_ft_face(), we
198 * just create a one-off version with a permanent face value.
199 */
200
201typedef struct _cairo_ft_font_face cairo_ft_font_face_t;
202
203struct _cairo_ft_unscaled_font {
204 cairo_unscaled_font_t base;
205
206 cairo_bool_t from_face; /* was the FT_Face provided by user? */
207 FT_Face face; /* provided or cached face */
208 void *face_context;
209
210 /* only set if from_face is false */
211 char *filename;
212 int id;
213
214 /* We temporarily scale the unscaled font as needed */
215 cairo_bool_t have_scale;
216 cairo_matrix_t current_scale;
217 double x_scale; /* Extracted X scale factor */
218 double y_scale; /* Extracted Y scale factor */
219 cairo_bool_t have_shape; /* true if the current scale has a non-scale component*/
220 cairo_matrix_t current_shape;
221 FT_Matrix Current_Shape;
222
223 unsigned int have_color_set : 1;
224 unsigned int have_color : 1; /* true if the font contains color glyphs */
225 FT_Fixed *variations; /* variation settings that FT_Face came */
226 unsigned int num_palettes;
227
228 cairo_mutex_t mutex;
229 int lock_count;
230
231 cairo_ft_font_face_t *faces; /* Linked list of faces for this font */
232};
233
234static int
235_cairo_ft_unscaled_font_keys_equal (const void *key_a,
236 const void *key_b);
237
238static void
239_cairo_ft_unscaled_font_fini (cairo_ft_unscaled_font_t *unscaled);
240
241typedef struct _cairo_ft_options {
242 cairo_font_options_t base;
243 unsigned int load_flags; /* flags for FT_Load_Glyph */
244 unsigned int synth_flags;
245} cairo_ft_options_t;
246
247static void
248_cairo_ft_options_init_copy (cairo_ft_options_t *options,
249 const cairo_ft_options_t *other)
250{
251 _cairo_font_options_init_copy (&options->base, &other->base);
252 options->load_flags = other->load_flags;
253 options->synth_flags = other->synth_flags;
254}
255
256static void
257_cairo_ft_options_fini (cairo_ft_options_t *options)
258{
259 _cairo_font_options_fini (&options->base);
260}
261
262struct _cairo_ft_font_face {
263 cairo_font_face_t base;
264
265 cairo_ft_unscaled_font_t *unscaled;
266 cairo_ft_options_t ft_options;
267 cairo_ft_font_face_t *next;
268
269#if CAIRO_HAS_FC_FONT1
270 FcPattern *pattern; /* if pattern is set, the above fields will be NULL */
271 cairo_font_face_t *resolved_font_face;
272 FcConfig *resolved_config;
273#endif
274};
275
276static const cairo_unscaled_font_backend_t cairo_ft_unscaled_font_backend;
277
278#if CAIRO_HAS_FC_FONT1
279static cairo_status_t
280_cairo_ft_font_options_substitute (const cairo_font_options_t *options,
281 FcPattern *pattern);
282
283static cairo_font_face_t *
284_cairo_ft_resolve_pattern (FcPattern *pattern,
285 const cairo_matrix_t *font_matrix,
286 const cairo_matrix_t *ctm,
287 const cairo_font_options_t *options);
288
289#endif
290
291cairo_status_t
292_cairo_ft_to_cairo_error (FT_Error error)
293{
294 /* Currently we don't get many (any?) useful statuses here.
295 * Populate as needed. */
296 switch (error)
297 {
298 case FT_Err_Ok:
299 return CAIRO_STATUS_SUCCESS;
300 case FT_Err_Out_Of_Memory:
301 return CAIRO_STATUS_NO_MEMORY;
302 default:
303 return CAIRO_STATUS_FREETYPE_ERROR;
304 }
305}
306
307/*
308 * We maintain a hash table to map file/id => #cairo_ft_unscaled_font_t.
309 * The hash table itself isn't limited in size. However, we limit the
310 * number of FT_Face objects we keep around; when we've exceeded that
311 * limit and need to create a new FT_Face, we dump the FT_Face from a
312 * random #cairo_ft_unscaled_font_t which has an unlocked FT_Face, (if
313 * there are any).
314 */
315
316typedef struct _cairo_ft_unscaled_font_map {
317 cairo_hash_table_t *hash_table;
318 FT_Library ft_library;
319 int num_open_faces;
320} cairo_ft_unscaled_font_map_t;
321
322static cairo_ft_unscaled_font_map_t *cairo_ft_unscaled_font_map = NULL((void*)0);
323
324
325static FT_Face
326_cairo_ft_unscaled_font_lock_face (cairo_ft_unscaled_font_t *unscaled);
327
328static void
329_cairo_ft_unscaled_font_unlock_face (cairo_ft_unscaled_font_t *unscaled);
330
331static cairo_bool_t
332_cairo_ft_scaled_font_is_vertical (cairo_scaled_font_t *scaled_font);
333
334
335static void
336_font_map_release_face_lock_held (cairo_ft_unscaled_font_map_t *font_map,
337 cairo_ft_unscaled_font_t *unscaled)
338{
339 if (unscaled->face) {
340 FT_Done_Face (unscaled->face);
341 unscaled->face = NULL((void*)0);
342 unscaled->have_scale = FALSE0;
343
344 font_map->num_open_faces--;
345 }
346}
347
348static cairo_status_t
349_cairo_ft_unscaled_font_map_create (void)
350{
351 cairo_ft_unscaled_font_map_t *font_map;
352
353 /* This function is only intended to be called from
354 * _cairo_ft_unscaled_font_map_lock. So we'll crash if we can
355 * detect some other call path. */
356 assert (cairo_ft_unscaled_font_map == NULL)((void) sizeof (__assert_single_arg (cairo_ft_unscaled_font_map
== ((void*)0))), __extension__ ({ if (cairo_ft_unscaled_font_map
== ((void*)0)) ; else __assert_fail ("cairo_ft_unscaled_font_map == NULL"
, "/root/firefox-clang/gfx/cairo/cairo/src/cairo-ft-font.c", 356
, __extension__ __PRETTY_FUNCTION__); }))
;
357
358 font_map = _cairo_calloc (sizeof (cairo_ft_unscaled_font_map_t))((sizeof (cairo_ft_unscaled_font_map_t)) != 0 ? calloc(1,sizeof
(cairo_ft_unscaled_font_map_t)) : ((void*)0))
;
359 if (unlikely (font_map == NULL)(__builtin_expect (!!(font_map == ((void*)0)), 0)))
360 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
361
362 font_map->hash_table =
363 _cairo_hash_table_create (_cairo_ft_unscaled_font_keys_equal);
364
365 if (unlikely (font_map->hash_table == NULL)(__builtin_expect (!!(font_map->hash_table == ((void*)0)),
0))
)
366 goto FAIL;
367
368 if (unlikely (FT_Init_FreeType (&font_map->ft_library))(__builtin_expect (!!(FT_Init_FreeType (&font_map->ft_library
)), 0))
)
369 goto FAIL;
370
371 font_map->num_open_faces = 0;
372
373 cairo_ft_unscaled_font_map = font_map;
374 return CAIRO_STATUS_SUCCESS;
375
376FAIL:
377 if (font_map->hash_table)
378 _cairo_hash_table_destroy (font_map->hash_table);
379 free (font_map);
380
381 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
382}
383
384
385static void
386_cairo_ft_unscaled_font_map_pluck_entry (void *entry, void *closure)
387{
388 cairo_ft_unscaled_font_t *unscaled = entry;
389 cairo_ft_unscaled_font_map_t *font_map = closure;
390
391 _cairo_hash_table_remove (font_map->hash_table,
392 &unscaled->base.hash_entry);
393
394 if (unscaled->from_face)
395 mozilla_ReleaseSharedFTFace (unscaled->face_context, unscaled);
396 else
397 _font_map_release_face_lock_held (font_map, unscaled);
398
399 _cairo_ft_unscaled_font_fini (unscaled);
400 free (unscaled);
401}
402
403static void
404_cairo_ft_unscaled_font_map_destroy (void)
405{
406 cairo_ft_unscaled_font_map_t *font_map;
407
408 CAIRO_MUTEX_LOCK (_cairo_ft_unscaled_font_map_mutex)pthread_mutex_lock (&(_cairo_ft_unscaled_font_map_mutex));
409 font_map = cairo_ft_unscaled_font_map;
410 cairo_ft_unscaled_font_map = NULL((void*)0);
411 CAIRO_MUTEX_UNLOCK (_cairo_ft_unscaled_font_map_mutex)pthread_mutex_unlock (&(_cairo_ft_unscaled_font_map_mutex
))
;
412
413 if (font_map != NULL((void*)0)) {
414 _cairo_hash_table_foreach (font_map->hash_table,
415 _cairo_ft_unscaled_font_map_pluck_entry,
416 font_map);
417 assert (font_map->num_open_faces == 0)((void) sizeof (__assert_single_arg (font_map->num_open_faces
== 0)), __extension__ ({ if (font_map->num_open_faces == 0
) ; else __assert_fail ("font_map->num_open_faces == 0", "/root/firefox-clang/gfx/cairo/cairo/src/cairo-ft-font.c"
, 417, __extension__ __PRETTY_FUNCTION__); }))
;
418
419 FT_Done_FreeType (font_map->ft_library);
420
421 _cairo_hash_table_destroy (font_map->hash_table);
422
423 free (font_map);
424 }
425}
426
427static cairo_ft_unscaled_font_map_t *
428_cairo_ft_unscaled_font_map_lock (void)
429{
430 CAIRO_MUTEX_INITIALIZE ()do { } while (0);
431
432 CAIRO_MUTEX_LOCK (_cairo_ft_unscaled_font_map_mutex)pthread_mutex_lock (&(_cairo_ft_unscaled_font_map_mutex));
433
434 if (unlikely (cairo_ft_unscaled_font_map == NULL)(__builtin_expect (!!(cairo_ft_unscaled_font_map == ((void*)0
)), 0))
) {
435 if (unlikely (_cairo_ft_unscaled_font_map_create ())(__builtin_expect (!!(_cairo_ft_unscaled_font_map_create ()),
0))
) {
436 CAIRO_MUTEX_UNLOCK (_cairo_ft_unscaled_font_map_mutex)pthread_mutex_unlock (&(_cairo_ft_unscaled_font_map_mutex
))
;
437 return NULL((void*)0);
438 }
439 }
440
441 return cairo_ft_unscaled_font_map;
442}
443
444static void
445_cairo_ft_unscaled_font_map_unlock (void)
446{
447 CAIRO_MUTEX_UNLOCK (_cairo_ft_unscaled_font_map_mutex)pthread_mutex_unlock (&(_cairo_ft_unscaled_font_map_mutex
))
;
448}
449
450static void
451_cairo_ft_unscaled_font_init_key (cairo_ft_unscaled_font_t *key,
452 cairo_bool_t from_face,
453 char *filename,
454 int id,
455 FT_Face face,
456 void *face_context)
457{
458 uintptr_t hash;
459
460 key->from_face = from_face;
461 key->filename = filename;
462 key->id = id;
463 key->face = face;
464 key->face_context = face_context;
465
466 hash = _cairo_hash_string (filename);
467 /* the constants are just arbitrary primes */
468 hash += ((uintptr_t) id) * 1607;
469 hash += ((uintptr_t) face) * 2137;
470
471 key->base.hash_entry.hash = hash;
472}
473
474/**
475 * _cairo_ft_unscaled_font_init:
476 *
477 * Initialize a #cairo_ft_unscaled_font_t.
478 *
479 * There are two basic flavors of #cairo_ft_unscaled_font_t, one
480 * created from an FT_Face and the other created from a filename/id
481 * pair. These two flavors are identified as from_face and !from_face.
482 *
483 * To initialize a from_face font, pass filename==%NULL, id=0 and the
484 * desired face.
485 *
486 * To initialize a !from_face font, pass the filename/id as desired
487 * and face==%NULL.
488 *
489 * Note that the code handles these two flavors in very distinct
490 * ways. For example there is a hash_table mapping
491 * filename/id->#cairo_unscaled_font_t in the !from_face case, but no
492 * parallel in the from_face case, (where the calling code would have
493 * to do its own mapping to ensure similar sharing).
494 **/
495static cairo_status_t
496_cairo_ft_unscaled_font_init (cairo_ft_unscaled_font_t *unscaled,
497 cairo_bool_t from_face,
498 const char *filename,
499 int id,
500 FT_Face face,
501 void *face_context)
502{
503 _cairo_unscaled_font_init (&unscaled->base,
504 &cairo_ft_unscaled_font_backend);
505
506 unscaled->variations = NULL((void*)0);
507
508 if (from_face
15.1
'from_face' is 0
) {
16
Taking false branch
509 FT_MM_Var *ft_mm_var;
510 unscaled->from_face = TRUE1;
511 _cairo_ft_unscaled_font_init_key (unscaled, TRUE1, NULL((void*)0), id, face, face_context);
512
513
514 unscaled->have_color = FT_HAS_COLOR (face)( !!( (face)->face_flags & ( 1L << 14 ) ) ) != 0;
515 unscaled->have_color_set = TRUE1;
516
517 static GetVarFunc getVar;
518 static DoneVarFunc doneVar;
519 static GetVarDesignCoordsFunc getVarDesignCoords;
520
521 static int firstTime = 1;
522 if (firstTime) {
523 getVar = (GetVarFunc) dlsym (RTLD_DEFAULT((void *) 0), "FT_Get_MM_Var");
524 doneVar = (DoneVarFunc) dlsym (RTLD_DEFAULT((void *) 0), "FT_Done_MM_Var");
525 getVarDesignCoords = (GetVarDesignCoordsFunc) dlsym (RTLD_DEFAULT((void *) 0), "FT_Get_Var_Design_Coordinates");
526 firstTime = 0;
527 }
528
529 if (getVar && getVarDesignCoords) {
530 /* The external face may already be in use by another renderer. */
531 if (face_context)
532 mozilla_LockSharedFTFace (face_context, NULL((void*)0));
533 if (0 == (*getVar) (face, &ft_mm_var))
534 {
535 unscaled->variations = _cairo_calloc_ab (ft_mm_var->num_axis, sizeof (FT_Fixed));
536 if (unscaled->variations)
537 (*getVarDesignCoords) (face, ft_mm_var->num_axis, unscaled->variations);
538 if (doneVar)
539 (*doneVar) (face->glyph->library, ft_mm_var);
540 else
541 free (ft_mm_var);
542 }
543 if (face_context)
544 mozilla_UnlockSharedFTFace (face_context);
545 }
546 } else {
547 char *filename_copy;
548
549 unscaled->from_face = FALSE0;
550 unscaled->face = NULL((void*)0);
551 unscaled->face_context = NULL((void*)0);
552
553 filename_copy = strdup (filename);
17
Null pointer passed to 1st parameter expecting 'nonnull'
554 if (unlikely (filename_copy == NULL)(__builtin_expect (!!(filename_copy == ((void*)0)), 0)))
555 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
556
557 _cairo_ft_unscaled_font_init_key (unscaled, FALSE0, filename_copy, id, NULL((void*)0), NULL((void*)0));
558
559 unscaled->have_color_set = FALSE0;
560 }
561
562 unscaled->have_scale = FALSE0;
563 CAIRO_MUTEX_INIT (unscaled->mutex)do { cairo_mutex_t _tmp_mutex = { { 0, 0, 0, 0, PTHREAD_MUTEX_TIMED_NP
, 0, 0, { ((void*)0), ((void*)0) } } }; memcpy (&(unscaled
->mutex), &_tmp_mutex, sizeof (_tmp_mutex)); } while (
0)
;
564 unscaled->lock_count = 0;
565
566 unscaled->faces = NULL((void*)0);
567
568 return CAIRO_STATUS_SUCCESS;
569}
570
571/**
572 * _cairo_ft_unscaled_font_fini:
573 *
574 * Free all data associated with a #cairo_ft_unscaled_font_t.
575 *
576 * CAUTION: The unscaled->face field must be %NULL before calling this
577 * function. This is because the #cairo_ft_unscaled_font_t_map keeps a
578 * count of these faces (font_map->num_open_faces) so it maintains the
579 * unscaled->face field while it has its lock held. See
580 * _font_map_release_face_lock_held().
581 **/
582static void
583_cairo_ft_unscaled_font_fini (cairo_ft_unscaled_font_t *unscaled)
584{
585 assert (unscaled->face == NULL)((void) sizeof (__assert_single_arg (unscaled->face == ((void
*)0))), __extension__ ({ if (unscaled->face == ((void*)0))
; else __assert_fail ("unscaled->face == NULL", "/root/firefox-clang/gfx/cairo/cairo/src/cairo-ft-font.c"
, 585, __extension__ __PRETTY_FUNCTION__); }))
;
586
587 free (unscaled->filename);
588 unscaled->filename = NULL((void*)0);
589
590 free (unscaled->variations);
591
592 CAIRO_MUTEX_FINI (unscaled->mutex)pthread_mutex_destroy (&(unscaled->mutex));
593}
594
595static int
596_cairo_ft_unscaled_font_keys_equal (const void *key_a,
597 const void *key_b)
598{
599 const cairo_ft_unscaled_font_t *unscaled_a = key_a;
600 const cairo_ft_unscaled_font_t *unscaled_b = key_b;
601
602 if (unscaled_a->id == unscaled_b->id &&
603 unscaled_a->from_face == unscaled_b->from_face)
604 {
605 if (unscaled_a->from_face)
606 return unscaled_a->face == unscaled_b->face &&
607 unscaled_a->face_context == unscaled_b->face_context;
608
609 if (unscaled_a->filename == NULL((void*)0) && unscaled_b->filename == NULL((void*)0))
610 return TRUE1;
611 else if (unscaled_a->filename == NULL((void*)0) || unscaled_b->filename == NULL((void*)0))
612 return FALSE0;
613 else
614 return (strcmp (unscaled_a->filename, unscaled_b->filename) == 0);
615 }
616
617 return FALSE0;
618}
619
620/* Finds or creates a #cairo_ft_unscaled_font_t for the filename/id from
621 * pattern. Returns a new reference to the unscaled font.
622 */
623static cairo_status_t
624_cairo_ft_unscaled_font_create_internal (cairo_bool_t from_face,
625 char *filename,
626 int id,
627 FT_Face font_face,
628 void *face_context,
629 cairo_ft_unscaled_font_t **out)
630{
631 cairo_ft_unscaled_font_t key, *unscaled;
632 cairo_ft_unscaled_font_map_t *font_map;
633 cairo_status_t status;
634
635 font_map = _cairo_ft_unscaled_font_map_lock ();
636 if (unlikely (font_map == NULL)(__builtin_expect (!!(font_map == ((void*)0)), 0)))
9
Taking false branch
637 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
638
639 _cairo_ft_unscaled_font_init_key (&key, from_face, filename, id, font_face, face_context);
640
641 /* Return existing unscaled font if it exists in the hash table. */
642 unscaled = _cairo_hash_table_lookup (font_map->hash_table,
643 &key.base.hash_entry);
644 if (unscaled != NULL((void*)0)) {
10
Assuming 'unscaled' is equal to NULL
645 _cairo_unscaled_font_reference (&unscaled->base);
646 goto DONE;
647 }
648
649 /* Otherwise create it and insert into hash table. */
650 unscaled = _cairo_calloc (sizeof (cairo_ft_unscaled_font_t))((sizeof (cairo_ft_unscaled_font_t)) != 0 ? calloc(1,sizeof (
cairo_ft_unscaled_font_t)) : ((void*)0))
;
11
'?' condition is true
651 if (unlikely (unscaled == NULL)(__builtin_expect (!!(unscaled == ((void*)0)), 0))) {
12
Assuming 'unscaled' is not equal to null
13
Taking false branch
652 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
653 goto UNWIND_FONT_MAP_LOCK;
654 }
655
656 status = _cairo_ft_unscaled_font_init (unscaled, from_face, filename, id, font_face, face_context);
14
Passing null pointer value via 3rd parameter 'filename'
15
Calling '_cairo_ft_unscaled_font_init'
657 if (unlikely (status)(__builtin_expect (!!(status), 0)))
658 goto UNWIND_UNSCALED_MALLOC;
659
660 assert (unscaled->base.hash_entry.hash == key.base.hash_entry.hash)((void) sizeof (__assert_single_arg (unscaled->base.hash_entry
.hash == key.base.hash_entry.hash)), __extension__ ({ if (unscaled
->base.hash_entry.hash == key.base.hash_entry.hash) ; else
__assert_fail ("unscaled->base.hash_entry.hash == key.base.hash_entry.hash"
, "/root/firefox-clang/gfx/cairo/cairo/src/cairo-ft-font.c", 660
, __extension__ __PRETTY_FUNCTION__); }))
;
661 status = _cairo_hash_table_insert (font_map->hash_table,
662 &unscaled->base.hash_entry);
663 if (unlikely (status)(__builtin_expect (!!(status), 0)))
664 goto UNWIND_UNSCALED_FONT_INIT;
665
666 mozilla_AddRefSharedFTFace (face_context);
667
668DONE:
669 _cairo_ft_unscaled_font_map_unlock ();
670 *out = unscaled;
671 return CAIRO_STATUS_SUCCESS;
672
673UNWIND_UNSCALED_FONT_INIT:
674 _cairo_ft_unscaled_font_fini (unscaled);
675UNWIND_UNSCALED_MALLOC:
676 free (unscaled);
677UNWIND_FONT_MAP_LOCK:
678 _cairo_ft_unscaled_font_map_unlock ();
679 return status;
680}
681
682
683#if CAIRO_HAS_FC_FONT1
684static cairo_status_t
685_cairo_ft_unscaled_font_create_for_pattern (FcPattern *pattern,
686 cairo_ft_unscaled_font_t **out)
687{
688 FT_Face font_face = NULL((void*)0);
689 char *filename = NULL((void*)0);
2
'filename' initialized to a null pointer value
690 int id = 0;
691 FcResult ret;
692
693 ret = FcPatternGetFTFace (pattern, FC_FT_FACE"ftface", 0, &font_face);
694 if (ret == FcResultMatch)
3
Assuming 'ret' is equal to FcResultMatch
4
Taking true branch
695 goto DONE;
5
Control jumps to line 719
696 if (ret == FcResultOutOfMemory)
697 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
698
699 ret = FcPatternGetString (pattern, FC_FILE"file", 0, (FcChar8 **) &filename);
700 if (ret == FcResultOutOfMemory)
701 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
702 if (ret == FcResultMatch) {
703 if (access (filename, R_OK4) == 0) {
704 /* If FC_INDEX is not set, we just use 0 */
705 ret = FcPatternGetInteger (pattern, FC_INDEX"index", 0, &id);
706 if (ret == FcResultOutOfMemory)
707 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
708
709 goto DONE;
710 } else
711 return _cairo_error (CAIRO_STATUS_FILE_NOT_FOUND);
712 }
713
714 /* The pattern contains neither a face nor a filename, resolve it later. */
715 *out = NULL((void*)0);
716 return CAIRO_STATUS_SUCCESS;
717
718DONE:
719 return _cairo_ft_unscaled_font_create_internal (font_face != NULL((void*)0),
6
Assuming 'font_face' is equal to NULL
8
Calling '_cairo_ft_unscaled_font_create_internal'
720 filename, id, font_face, NULL((void*)0),
7
Passing null pointer value via 2nd parameter 'filename'
721 out);
722}
723#endif
724
725static cairo_status_t
726_cairo_ft_unscaled_font_create_from_face (FT_Face face,
727 void *face_context,
728 cairo_ft_unscaled_font_t **out)
729{
730 return _cairo_ft_unscaled_font_create_internal (TRUE1, NULL((void*)0), face->face_index, face, face_context, out);
731}
732
733static cairo_bool_t
734_cairo_ft_unscaled_font_destroy (void *abstract_font)
735{
736 cairo_ft_unscaled_font_t *unscaled = abstract_font;
737 cairo_ft_unscaled_font_map_t *font_map;
738
739 font_map = _cairo_ft_unscaled_font_map_lock ();
740 /* All created objects must have been mapped in the font map. */
741 assert (font_map != NULL)((void) sizeof (__assert_single_arg (font_map != ((void*)0)))
, __extension__ ({ if (font_map != ((void*)0)) ; else __assert_fail
("font_map != NULL", "/root/firefox-clang/gfx/cairo/cairo/src/cairo-ft-font.c"
, 741, __extension__ __PRETTY_FUNCTION__); }))
;
742
743 if (! _cairo_reference_count_dec_and_test (&unscaled->base.ref_count)(__atomic_fetch_sub(&(&unscaled->base.ref_count)->
ref_count, 1, 5) == 1)
) {
744 /* somebody recreated the font whilst we waited for the lock */
745 _cairo_ft_unscaled_font_map_unlock ();
746 return FALSE0;
747 }
748
749 _cairo_hash_table_remove (font_map->hash_table,
750 &unscaled->base.hash_entry);
751
752 if (unscaled->from_face) {
753 /* See comments in _ft_font_face_destroy about the "zombie" state
754 * for a _ft_font_face.
755 */
756 if (unscaled->faces && unscaled->faces->unscaled == NULL((void*)0)) {
757 assert (unscaled->faces->next == NULL)((void) sizeof (__assert_single_arg (unscaled->faces->next
== ((void*)0))), __extension__ ({ if (unscaled->faces->
next == ((void*)0)) ; else __assert_fail ("unscaled->faces->next == NULL"
, "/root/firefox-clang/gfx/cairo/cairo/src/cairo-ft-font.c", 757
, __extension__ __PRETTY_FUNCTION__); }))
;
758 CAIRO_FT_LOCK (unscaled)((unscaled)->face_context ? (void)mozilla_LockSharedFTFace
((unscaled)->face_context, ((void*)0)) : (void)pthread_mutex_lock
(&((unscaled)->mutex)))
;
759 cairo_font_face_destroy_moz_cairo_font_face_destroy (&unscaled->faces->base);
760 CAIRO_FT_UNLOCK (unscaled)((unscaled)->face_context ? mozilla_UnlockSharedFTFace((unscaled
)->face_context) : (void)pthread_mutex_unlock (&((unscaled
)->mutex)))
;
761 }
762 mozilla_ReleaseSharedFTFace (unscaled->face_context, unscaled);
763 } else {
764 _font_map_release_face_lock_held (font_map, unscaled);
765 }
766 unscaled->face = NULL((void*)0);
767 unscaled->face_context = NULL((void*)0);
768
769 _cairo_ft_unscaled_font_map_unlock ();
770
771 _cairo_ft_unscaled_font_fini (unscaled);
772 return TRUE1;
773}
774
775static cairo_bool_t
776_has_unlocked_face (const void *entry)
777{
778 const cairo_ft_unscaled_font_t *unscaled = entry;
779
780 return (!unscaled->from_face && unscaled->lock_count == 0 && unscaled->face);
781}
782
783/* Ensures that an unscaled font has a face object. If we exceed
784 * MAX_OPEN_FACES, try to close some.
785 *
786 * This differs from _cairo_ft_scaled_font_lock_face in that it doesn't
787 * set the scale on the face, but just returns it at the last scale.
788 */
789static cairo_warn FT_Face
790_cairo_ft_unscaled_font_lock_face (cairo_ft_unscaled_font_t *unscaled)
791{
792 cairo_ft_unscaled_font_map_t *font_map;
793 FT_Face face = NULL((void*)0);
794 FT_Error error;
795
796 if (unscaled->face_context) {
797 if (!mozilla_LockSharedFTFace (unscaled->face_context, unscaled)) {
798 unscaled->have_scale = FALSE0;
799 }
800 } else {
801 CAIRO_FT_LOCK (unscaled)((unscaled)->face_context ? (void)mozilla_LockSharedFTFace
((unscaled)->face_context, ((void*)0)) : (void)pthread_mutex_lock
(&((unscaled)->mutex)))
;
802 }
803 unscaled->lock_count++;
804
805 if (unscaled->face)
806 return unscaled->face;
807
808 /* If this unscaled font was created from an FT_Face then we just
809 * returned it above. */
810 assert (!unscaled->from_face)((void) sizeof (__assert_single_arg (!unscaled->from_face)
), __extension__ ({ if (!unscaled->from_face) ; else __assert_fail
("!unscaled->from_face", "/root/firefox-clang/gfx/cairo/cairo/src/cairo-ft-font.c"
, 810, __extension__ __PRETTY_FUNCTION__); }))
;
811
812 font_map = _cairo_ft_unscaled_font_map_lock ();
813 {
814 assert (font_map != NULL)((void) sizeof (__assert_single_arg (font_map != ((void*)0)))
, __extension__ ({ if (font_map != ((void*)0)) ; else __assert_fail
("font_map != NULL", "/root/firefox-clang/gfx/cairo/cairo/src/cairo-ft-font.c"
, 814, __extension__ __PRETTY_FUNCTION__); }))
;
815
816 while (font_map->num_open_faces >= MAX_OPEN_FACES10)
817 {
818 cairo_ft_unscaled_font_t *entry;
819
820 entry = _cairo_hash_table_random_entry (font_map->hash_table,
821 _has_unlocked_face);
822 if (entry == NULL((void*)0))
823 break;
824
825 _font_map_release_face_lock_held (font_map, entry);
826 }
827 }
828 _cairo_ft_unscaled_font_map_unlock ();
829
830 error = FT_New_Face (font_map->ft_library,
831 unscaled->filename,
832 unscaled->id,
833 &face);
834 if (error)
835 {
836 unscaled->lock_count--;
837 CAIRO_FT_UNLOCK (unscaled)((unscaled)->face_context ? mozilla_UnlockSharedFTFace((unscaled
)->face_context) : (void)pthread_mutex_unlock (&((unscaled
)->mutex)))
;
838 _cairo_error_throw (_cairo_ft_to_cairo_error (error))do { cairo_status_t status__ = _cairo_error (_cairo_ft_to_cairo_error
(error)); (void) status__; } while (0)
;
839 return NULL((void*)0);
840 }
841
842 unscaled->face = face;
843
844 unscaled->have_color = FT_HAS_COLOR (face)( !!( (face)->face_flags & ( 1L << 14 ) ) ) != 0;
845 unscaled->have_color_set = TRUE1;
846
847 font_map->num_open_faces++;
848
849 return face;
850}
851
852
853/* Unlock unscaled font locked with _cairo_ft_unscaled_font_lock_face
854 */
855static void
856_cairo_ft_unscaled_font_unlock_face (cairo_ft_unscaled_font_t *unscaled)
857{
858 assert (unscaled->lock_count > 0)((void) sizeof (__assert_single_arg (unscaled->lock_count >
0)), __extension__ ({ if (unscaled->lock_count > 0) ; else
__assert_fail ("unscaled->lock_count > 0", "/root/firefox-clang/gfx/cairo/cairo/src/cairo-ft-font.c"
, 858, __extension__ __PRETTY_FUNCTION__); }))
;
859
860 unscaled->lock_count--;
861
862 CAIRO_FT_UNLOCK (unscaled)((unscaled)->face_context ? mozilla_UnlockSharedFTFace((unscaled
)->face_context) : (void)pthread_mutex_unlock (&((unscaled
)->mutex)))
;
863}
864
865
866static cairo_status_t
867_compute_transform (cairo_ft_font_transform_t *sf,
868 cairo_matrix_t *scale,
869 cairo_ft_unscaled_font_t *unscaled)
870{
871 cairo_status_t status;
872 double x_scale, y_scale;
873 cairo_matrix_t normalized = *scale;
874
875 /* The font matrix has x and y "scale" components which we extract and
876 * use as character scale values. These influence the way freetype
877 * chooses hints, as well as selecting different bitmaps in
878 * hand-rendered fonts. We also copy the normalized matrix to
879 * freetype's transformation.
880 */
881
882 status = _cairo_matrix_compute_basis_scale_factors (scale,
883 &x_scale, &y_scale,
884 1);
885 if (unlikely (status)(__builtin_expect (!!(status), 0)))
886 return status;
887
888 /* FreeType docs say this about x_scale and y_scale:
889 * "A character width or height smaller than 1pt is set to 1pt;"
890 * So, we cap them from below at 1.0 and let the FT transform
891 * take care of sub-1.0 scaling. */
892 if (x_scale < 1.0)
893 x_scale = 1.0;
894 if (y_scale < 1.0)
895 y_scale = 1.0;
896
897 if (unscaled && (unscaled->face->face_flags & FT_FACE_FLAG_SCALABLE( 1L << 0 )) == 0) {
898 double min_distance = DBL_MAX1.7976931348623157e+308;
899 cairo_bool_t magnify = TRUE1;
900 int i;
901 double best_x_size = 0;
902 double best_y_size = 0;
903
904 for (i = 0; i < unscaled->face->num_fixed_sizes; i++) {
905 double x_size = unscaled->face->available_sizes[i].x_ppem / 64.;
906 double y_size = unscaled->face->available_sizes[i].y_ppem / 64.;
907 double distance = y_size - y_scale;
908
909 /*
910 * distance is positive if current strike is larger than desired
911 * size, and negative if smaller.
912 *
913 * We like to prefer down-scaling to upscaling.
914 */
915
916 if ((magnify && distance >= 0) || fabs (distance) <= min_distance) {
917 magnify = distance < 0;
918 min_distance = fabs (distance);
919 best_x_size = x_size;
920 best_y_size = y_size;
921 }
922 }
923
924 x_scale = best_x_size;
925 y_scale = best_y_size;
926 }
927
928 sf->x_scale = x_scale;
929 sf->y_scale = y_scale;
930
931 cairo_matrix_scale_moz_cairo_matrix_scale (&normalized, 1.0 / x_scale, 1.0 / y_scale);
932
933 _cairo_matrix_get_affine (&normalized,
934 &sf->shape[0][0], &sf->shape[0][1],
935 &sf->shape[1][0], &sf->shape[1][1],
936 NULL((void*)0), NULL((void*)0));
937
938 return CAIRO_STATUS_SUCCESS;
939}
940
941/* Temporarily scales an unscaled font to the give scale. We catch
942 * scaling to the same size, since changing a FT_Face is expensive.
943 */
944static cairo_status_t
945_cairo_ft_unscaled_font_set_scale (cairo_ft_unscaled_font_t *unscaled,
946 cairo_matrix_t *scale)
947{
948 cairo_status_t status;
949 cairo_ft_font_transform_t sf;
950 FT_Matrix mat;
951 FT_Error error;
952
953 assert (unscaled->face != NULL)((void) sizeof (__assert_single_arg (unscaled->face != ((void
*)0))), __extension__ ({ if (unscaled->face != ((void*)0))
; else __assert_fail ("unscaled->face != NULL", "/root/firefox-clang/gfx/cairo/cairo/src/cairo-ft-font.c"
, 953, __extension__ __PRETTY_FUNCTION__); }))
;
954
955 if (unscaled->have_scale &&
956 scale->xx == unscaled->current_scale.xx &&
957 scale->yx == unscaled->current_scale.yx &&
958 scale->xy == unscaled->current_scale.xy &&
959 scale->yy == unscaled->current_scale.yy)
960 return CAIRO_STATUS_SUCCESS;
961
962 unscaled->have_scale = TRUE1;
963 unscaled->current_scale = *scale;
964
965 status = _compute_transform (&sf, scale, unscaled);
966 if (unlikely (status)(__builtin_expect (!!(status), 0)))
967 return status;
968
969 unscaled->x_scale = sf.x_scale;
970 unscaled->y_scale = sf.y_scale;
971
972 mat.xx = DOUBLE_TO_16_16(sf.shape[0][0])((FT_Fixed)((sf.shape[0][0]) * 65536.0));
973 mat.yx = - DOUBLE_TO_16_16(sf.shape[0][1])((FT_Fixed)((sf.shape[0][1]) * 65536.0));
974 mat.xy = - DOUBLE_TO_16_16(sf.shape[1][0])((FT_Fixed)((sf.shape[1][0]) * 65536.0));
975 mat.yy = DOUBLE_TO_16_16(sf.shape[1][1])((FT_Fixed)((sf.shape[1][1]) * 65536.0));
976
977 unscaled->have_shape = (mat.xx != 0x10000 ||
978 mat.yx != 0x00000 ||
979 mat.xy != 0x00000 ||
980 mat.yy != 0x10000);
981
982 unscaled->Current_Shape = mat;
983 cairo_matrix_init_moz_cairo_matrix_init (&unscaled->current_shape,
984 sf.shape[0][0], sf.shape[0][1],
985 sf.shape[1][0], sf.shape[1][1],
986 0.0, 0.0);
987
988 FT_Set_Transform(unscaled->face, &mat, NULL((void*)0));
989
990 error = FT_Set_Char_Size (unscaled->face,
991 sf.x_scale * 64.0 + .5,
992 sf.y_scale * 64.0 + .5,
993 0, 0);
994 if (error)
995 return _cairo_error (_cairo_ft_to_cairo_error (error));
996
997 return CAIRO_STATUS_SUCCESS;
998}
999
1000/* we sometimes need to convert the glyph bitmap in a FT_GlyphSlot
1001 * into a different format. For example, we want to convert a
1002 * FT_PIXEL_MODE_LCD or FT_PIXEL_MODE_LCD_V bitmap into a 32-bit
1003 * ARGB or ABGR bitmap.
1004 *
1005 * this function prepares a target descriptor for this operation.
1006 *
1007 * input :: target bitmap descriptor. The function will set its
1008 * 'width', 'rows' and 'pitch' fields, and only these
1009 *
1010 * slot :: the glyph slot containing the source bitmap. this
1011 * function assumes that slot->format == FT_GLYPH_FORMAT_BITMAP
1012 *
1013 * mode :: the requested final rendering mode. supported values are
1014 * MONO, NORMAL (i.e. gray), LCD and LCD_V
1015 *
1016 * the function returns the size in bytes of the corresponding buffer,
1017 * it's up to the caller to allocate the corresponding memory block
1018 * before calling _fill_xrender_bitmap
1019 *
1020 * it also returns -1 in case of error (e.g. incompatible arguments,
1021 * like trying to convert a gray bitmap into a monochrome one)
1022 */
1023static int
1024_compute_xrender_bitmap_size(FT_Bitmap *target,
1025 FT_GlyphSlot slot,
1026 FT_Render_Mode mode)
1027{
1028 FT_Bitmap *ftbit;
1029 int width, height, pitch;
1030
1031 if (slot->format != FT_GLYPH_FORMAT_BITMAP)
1032 return -1;
1033
1034 /* compute the size of the final bitmap */
1035 ftbit = &slot->bitmap;
1036
1037 /* Reject absurd glyph dimensions to avoid overflow below. */
1038 if (ftbit->width > INT_MAX2147483647 / 4 || ftbit->rows > INT_MAX2147483647) {
1039 return -1;
1040 }
1041
1042 width = ftbit->width;
1043 height = ftbit->rows;
1044
1045 pitch = (width + 3) & ~3;
1046
1047 switch (ftbit->pixel_mode) {
1048 case FT_PIXEL_MODE_MONO:
1049 if (mode == FT_RENDER_MODE_MONO) {
1050 pitch = (((width + 31) & ~31) >> 3);
1051 break;
1052 }
1053 /* fall-through */
1054
1055 case FT_PIXEL_MODE_GRAY:
1056 if (mode == FT_RENDER_MODE_LCD ||
1057 mode == FT_RENDER_MODE_LCD_V)
1058 {
1059 /* each pixel is replicated into a 32-bit ARGB value */
1060 pitch = width * 4;
1061 }
1062 break;
1063
1064 case FT_PIXEL_MODE_LCD:
1065 if (mode != FT_RENDER_MODE_LCD)
1066 return -1;
1067
1068 /* horz pixel triplets are packed into 32-bit ARGB values */
1069 width /= 3;
1070 pitch = width * 4;
1071 break;
1072
1073 case FT_PIXEL_MODE_LCD_V:
1074 if (mode != FT_RENDER_MODE_LCD_V)
1075 return -1;
1076
1077 /* vert pixel triplets are packed into 32-bit ARGB values */
1078 height /= 3;
1079 pitch = width * 4;
1080 break;
1081
1082 case FT_PIXEL_MODE_BGRA:
1083 /* each pixel is replicated into a 32-bit ARGB value */
1084 pitch = width * 4;
1085 break;
1086
1087 default: /* unsupported source format */
1088 return -1;
1089 }
1090
1091 target->width = width;
1092 target->rows = height;
1093 target->pitch = pitch;
1094 target->buffer = NULL((void*)0);
1095
1096 /* Reject this size if the multiplication would overflow an int. */
1097 size_t result;
1098 if (_cairo_mul_size_t_overflow(pitch, height, &result)__builtin_mul_overflow((size_t)(pitch), (size_t)(height), (size_t
*)(&result))
|| result > INT_MAX2147483647)
1099 return -1;
1100
1101 return (int) result;
1102}
1103
1104/* this functions converts the glyph bitmap found in a FT_GlyphSlot
1105 * into a different format (see _compute_xrender_bitmap_size)
1106 *
1107 * you should call this function after _compute_xrender_bitmap_size
1108 *
1109 * target :: target bitmap descriptor. Note that its 'buffer' pointer
1110 * must point to memory allocated by the caller
1111 *
1112 * slot :: the glyph slot containing the source bitmap
1113 *
1114 * mode :: the requested final rendering mode
1115 *
1116 * bgr :: boolean, set if BGR or VBGR pixel ordering is needed
1117 */
1118static void
1119_fill_xrender_bitmap(FT_Bitmap *target,
1120 FT_GlyphSlot slot,
1121 FT_Render_Mode mode,
1122 int bgr)
1123{
1124 FT_Bitmap *ftbit = &slot->bitmap;
1125 unsigned char *srcLine = ftbit->buffer;
1126 unsigned char *dstLine = target->buffer;
1127 int src_pitch = ftbit->pitch;
1128 int width = target->width;
1129 int height = target->rows;
1130 int pitch = target->pitch;
1131 int subpixel;
1132 int h;
1133
1134 subpixel = (mode == FT_RENDER_MODE_LCD ||
1135 mode == FT_RENDER_MODE_LCD_V);
1136
1137 if (src_pitch < 0)
1138 srcLine -= src_pitch * (ftbit->rows - 1);
1139
1140 target->pixel_mode = ftbit->pixel_mode;
1141
1142 switch (ftbit->pixel_mode) {
1143 case FT_PIXEL_MODE_MONO:
1144 if (subpixel) {
1145 /* convert mono to ARGB32 values */
1146
1147 for (h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch) {
1148 int x;
1149
1150 for (x = 0; x < width; x++) {
1151 if (srcLine[(x >> 3)] & (0x80 >> (x & 7)))
1152 ((unsigned int *) dstLine)[x] = 0xffffffffU;
1153 }
1154 }
1155 target->pixel_mode = FT_PIXEL_MODE_LCD;
1156
1157 } else if (mode == FT_RENDER_MODE_NORMAL) {
1158 /* convert mono to 8-bit gray */
1159
1160 for (h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch) {
1161 int x;
1162
1163 for (x = 0; x < width; x++) {
1164 if (srcLine[(x >> 3)] & (0x80 >> (x & 7)))
1165 dstLine[x] = 0xff;
1166 }
1167 }
1168 target->pixel_mode = FT_PIXEL_MODE_GRAY;
1169
1170 } else {
1171 /* copy mono to mono */
1172
1173 int bytes = (width + 7) >> 3;
1174
1175 for (h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch)
1176 memcpy (dstLine, srcLine, bytes);
1177 }
1178 break;
1179
1180 case FT_PIXEL_MODE_GRAY:
1181 if (subpixel) {
1182 /* convert gray to ARGB32 values */
1183
1184 for (h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch) {
1185 int x;
1186 unsigned int *dst = (unsigned int *) dstLine;
1187
1188 for (x = 0; x < width; x++) {
1189 unsigned int pix = srcLine[x];
1190
1191 pix |= (pix << 8);
1192 pix |= (pix << 16);
1193
1194 dst[x] = pix;
1195 }
1196 }
1197 target->pixel_mode = FT_PIXEL_MODE_LCD;
1198 } else {
1199 /* copy gray into gray */
1200
1201 for (h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch)
1202 memcpy (dstLine, srcLine, width);
1203 }
1204 break;
1205
1206 case FT_PIXEL_MODE_LCD:
1207 if (!bgr) {
1208 /* convert horizontal RGB into ARGB32 */
1209
1210 for (h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch) {
1211 int x;
1212 unsigned char *src = srcLine;
1213 unsigned int *dst = (unsigned int *) dstLine;
1214
1215 for (x = 0; x < width; x++, src += 3) {
1216 unsigned int pix;
1217
1218 pix = ((unsigned int)src[0] << 16) |
1219 ((unsigned int)src[1] << 8) |
1220 ((unsigned int)src[2] ) |
1221 ((unsigned int)src[1] << 24) ;
1222
1223 dst[x] = pix;
1224 }
1225 }
1226 } else {
1227 /* convert horizontal BGR into ARGB32 */
1228
1229 for (h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch) {
1230
1231 int x;
1232 unsigned char *src = srcLine;
1233 unsigned int *dst = (unsigned int *) dstLine;
1234
1235 for (x = 0; x < width; x++, src += 3) {
1236 unsigned int pix;
1237
1238 pix = ((unsigned int)src[2] << 16) |
1239 ((unsigned int)src[1] << 8) |
1240 ((unsigned int)src[0] ) |
1241 ((unsigned int)src[1] << 24) ;
1242
1243 dst[x] = pix;
1244 }
1245 }
1246 }
1247 break;
1248
1249 case FT_PIXEL_MODE_LCD_V:
1250 /* convert vertical RGB into ARGB32 */
1251 if (!bgr) {
1252
1253 for (h = height; h > 0; h--, srcLine += 3 * src_pitch, dstLine += pitch) {
1254 int x;
1255 unsigned char* src = srcLine;
1256 unsigned int* dst = (unsigned int *) dstLine;
1257
1258 for (x = 0; x < width; x++, src += 1) {
1259 unsigned int pix;
1260 pix = ((unsigned int)src[0] << 16) |
1261 ((unsigned int)src[src_pitch] << 8) |
1262 ((unsigned int)src[src_pitch*2] ) |
1263 ((unsigned int)src[src_pitch] << 24) ;
1264 dst[x] = pix;
1265 }
1266 }
1267 } else {
1268
1269 for (h = height; h > 0; h--, srcLine += 3*src_pitch, dstLine += pitch) {
1270 int x;
1271 unsigned char *src = srcLine;
1272 unsigned int *dst = (unsigned int *) dstLine;
1273
1274 for (x = 0; x < width; x++, src += 1) {
1275 unsigned int pix;
1276
1277 pix = ((unsigned int)src[src_pitch * 2] << 16) |
1278 ((unsigned int)src[src_pitch] << 8) |
1279 ((unsigned int)src[0] ) |
1280 ((unsigned int)src[src_pitch] << 24) ;
1281
1282 dst[x] = pix;
1283 }
1284 }
1285 }
1286 break;
1287
1288 case FT_PIXEL_MODE_BGRA:
1289 for (h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch)
1290 memcpy (dstLine, srcLine, (size_t)width * 4);
1291 break;
1292
1293 default:
1294 assert (0)((void) sizeof (__assert_single_arg (0)), __extension__ ({ if
(0) ; else __assert_fail ("0", "/root/firefox-clang/gfx/cairo/cairo/src/cairo-ft-font.c"
, 1294, __extension__ __PRETTY_FUNCTION__); }))
;
1295 }
1296}
1297
1298
1299/* Fills in val->image with an image surface created from @bitmap
1300 */
1301static cairo_status_t
1302_get_bitmap_surface (FT_Bitmap *bitmap,
1303 FT_Library library,
1304 cairo_bool_t own_buffer,
1305 cairo_font_options_t *font_options,
1306 cairo_image_surface_t **surface)
1307{
1308 unsigned int width, height;
1309 unsigned char *data;
1310 int format = CAIRO_FORMAT_A8;
1311 int stride;
1312 cairo_image_surface_t *image;
1313 cairo_bool_t component_alpha = FALSE0;
1314
1315 width = bitmap->width;
1316 height = bitmap->rows;
1317
1318 if (width == 0 || height == 0) {
1319 *surface = (cairo_image_surface_t *)
1320 cairo_image_surface_create_for_data_moz_cairo_image_surface_create_for_data (NULL((void*)0), format, 0, 0, 0);
1321 return (*surface)->base.status;
1322 }
1323
1324 switch (bitmap->pixel_mode) {
1325 case FT_PIXEL_MODE_MONO:
1326 stride = (((width + 31) & ~31) >> 3);
1327 if (own_buffer) {
1328 data = bitmap->buffer;
1329 assert (stride == bitmap->pitch)((void) sizeof (__assert_single_arg (stride == bitmap->pitch
)), __extension__ ({ if (stride == bitmap->pitch) ; else __assert_fail
("stride == bitmap->pitch", "/root/firefox-clang/gfx/cairo/cairo/src/cairo-ft-font.c"
, 1329, __extension__ __PRETTY_FUNCTION__); }))
;
1330 } else {
1331 data = _cairo_malloc_ab (height, stride);
1332 if (!data)
1333 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1334
1335 if (stride == bitmap->pitch) {
1336 memcpy (data, bitmap->buffer, (size_t)stride * height);
1337 } else {
1338 int i;
1339 unsigned char *source, *dest;
1340 /* bitmap->pitch might exceed our computed row stride.
1341 * Copy only the (width+7)/8 payload bytes of each row,
1342 * which always fit in both buffers. */
1343 int row_bytes = (width + 7) >> 3;
1344
1345 if (bitmap->pitch < row_bytes) {
1346 free (data);
1347 return _cairo_error (CAIRO_STATUS_INVALID_FORMAT);
1348 }
1349
1350 source = bitmap->buffer;
1351 dest = data;
1352 for (i = height; i; i--) {
1353 memcpy (dest, source, row_bytes);
1354 memset (dest + row_bytes, '\0', stride - row_bytes);
1355
1356 source += bitmap->pitch;
1357 dest += stride;
1358 }
1359 }
1360 }
1361
1362#ifndef WORDS_BIGENDIAN
1363 {
1364 uint8_t *d = data;
1365 int count = stride * height;
1366
1367 while (count--) {
1368 *d = CAIRO_BITSWAP8 (*d)((((*d) * 0x0802LU & 0x22110LU) | ((*d) * 0x8020LU & 0x88440LU
)) * 0x10101LU >> 16)
;
1369 d++;
1370 }
1371 }
1372#endif
1373 format = CAIRO_FORMAT_A1;
1374 break;
1375
1376 case FT_PIXEL_MODE_LCD:
1377 case FT_PIXEL_MODE_LCD_V:
1378 case FT_PIXEL_MODE_GRAY:
1379 if (font_options->antialias != CAIRO_ANTIALIAS_SUBPIXEL ||
1380 bitmap->pixel_mode == FT_PIXEL_MODE_GRAY)
1381 {
1382 stride = bitmap->pitch;
1383
1384 /* We don't support stride not multiple of 4. */
1385 if (stride & 3)
1386 {
1387 assert (!own_buffer)((void) sizeof (__assert_single_arg (!own_buffer)), __extension__
({ if (!own_buffer) ; else __assert_fail ("!own_buffer", "/root/firefox-clang/gfx/cairo/cairo/src/cairo-ft-font.c"
, 1387, __extension__ __PRETTY_FUNCTION__); }))
;
1388 goto convert;
1389 }
1390
1391 if (own_buffer) {
1392 data = bitmap->buffer;
1393 } else {
1394 data = _cairo_malloc_ab (height, stride);
1395 if (!data)
1396 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1397
1398 memcpy (data, bitmap->buffer, (size_t)stride * height);
1399 }
1400
1401 format = CAIRO_FORMAT_A8;
1402 } else {
1403 data = bitmap->buffer;
1404 stride = bitmap->pitch;
1405 format = CAIRO_FORMAT_ARGB32;
1406 component_alpha = TRUE1;
1407 }
1408 break;
1409 case FT_PIXEL_MODE_BGRA:
1410 stride = width * 4;
1411 if (own_buffer) {
1412 data = bitmap->buffer;
1413 } else {
1414 data = _cairo_malloc_ab (height, stride);
1415 if (!data)
1416 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1417
1418 memcpy (data, bitmap->buffer, (size_t)stride * height);
1419 }
1420
1421 if (!_cairo_is_little_endian ())
1422 {
1423 /* Byteswap. */
1424 unsigned int i, count = height * width;
1425 uint32_t *p = (uint32_t *) data;
1426 for (i = 0; i < count; i++)
1427 p[i] = bswap_32 (p[i])__bswap_32 (p[i]);
1428 }
1429 format = CAIRO_FORMAT_ARGB32;
1430 break;
1431 case FT_PIXEL_MODE_GRAY2:
1432 case FT_PIXEL_MODE_GRAY4:
1433 convert:
1434 if (!own_buffer && library)
1435 {
1436 /* This is pretty much the only case that we can get in here. */
1437 /* Convert to 8bit grayscale. */
1438
1439 FT_Bitmap tmp;
1440 FT_Int align;
1441 FT_Error error;
1442
1443 format = CAIRO_FORMAT_A8;
1444
1445 align = cairo_format_stride_for_width_moz_cairo_format_stride_for_width (format, bitmap->width);
1446
1447 FT_Bitmap_New( &tmp );
1448
1449 error = FT_Bitmap_Convert( library, bitmap, &tmp, align );
1450 if (error)
1451 return _cairo_error (_cairo_ft_to_cairo_error (error));
1452
1453 /* tmp is our locally-managed view of bitmap, which belongs to
1454 * the glyph slot. Only access and free tmp. */
1455 stride = tmp.pitch;
1456 data = _cairo_malloc_ab (height, stride);
1457 if (!data) {
1458 FT_Bitmap_Done( library, &tmp );
1459 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1460 }
1461
1462 if (tmp.num_grays != 256)
1463 {
1464 unsigned int x, y;
1465 unsigned int mul = 255 / (tmp.num_grays - 1);
1466 FT_Byte *p = tmp.buffer;
1467 for (y = 0; y < height; y++) {
1468 for (x = 0; x < width; x++)
1469 p[x] *= mul;
1470 p += tmp.pitch;
1471 }
1472 }
1473
1474 memcpy (data, tmp.buffer, (size_t)stride * height);
1475 FT_Bitmap_Done( library, &tmp );
1476 break;
1477 }
1478 /* fall through */
1479 /* These could be triggered by very rare types of TrueType fonts */
1480 default:
1481 if (own_buffer)
1482 free (bitmap->buffer);
1483 return _cairo_error (CAIRO_STATUS_INVALID_FORMAT);
1484 }
1485
1486 /* XXX */
1487 *surface = image = (cairo_image_surface_t *)
1488 cairo_image_surface_create_for_data_moz_cairo_image_surface_create_for_data (data,
1489 format,
1490 width, height, stride);
1491 if (image->base.status) {
1492 free (data);
1493 return (*surface)->base.status;
1494 }
1495
1496 if (component_alpha)
1497 pixman_image_set_component_alpha_moz_pixman_image_set_component_alpha (image->pixman_image, TRUE1);
1498
1499 _cairo_image_surface_assume_ownership_of_data (image);
1500
1501 _cairo_debug_check_image_surface_is_defined (&image->base);
1502
1503 return CAIRO_STATUS_SUCCESS;
1504}
1505
1506/* Converts an outline FT_GlyphSlot into an image
1507 *
1508 * This could go through _render_glyph_bitmap as well, letting
1509 * FreeType convert the outline to a bitmap, but doing it ourselves
1510 * has two minor advantages: first, we save a copy of the bitmap
1511 * buffer: we can directly use the buffer that FreeType renders
1512 * into.
1513 *
1514 * Second, it may help when we add support for subpixel
1515 * rendering: the Xft code does it this way. (Keith thinks that
1516 * it may also be possible to get the subpixel rendering with
1517 * FT_Render_Glyph: something worth looking into in more detail
1518 * when we add subpixel support. If so, we may want to eliminate
1519 * this version of the code path entirely.
1520 */
1521static cairo_status_t
1522_render_glyph_outline (FT_Face face,
1523 cairo_font_options_t *font_options,
1524 cairo_image_surface_t **surface)
1525{
1526 cairo_subpixel_order_t rgba = CAIRO_SUBPIXEL_ORDER_DEFAULT;
1527 int lcd_filter = FT_LCD_FILTER_DEFAULT;
1528 FT_GlyphSlot glyphslot = face->glyph;
1529 FT_Outline *outline = &glyphslot->outline;
1530 FT_Bitmap bitmap;
1531 FT_BBox cbox;
1532 unsigned int width, height;
1533 cairo_status_t status;
1534 FT_Error error;
1535 FT_Library library = glyphslot->library;
1536 FT_Render_Mode render_mode = FT_RENDER_MODE_NORMAL;
1537
1538 switch (font_options->antialias) {
1539 case CAIRO_ANTIALIAS_NONE:
1540 render_mode = FT_RENDER_MODE_MONO;
1541 break;
1542
1543 case CAIRO_ANTIALIAS_SUBPIXEL:
1544 case CAIRO_ANTIALIAS_BEST:
1545 switch (font_options->subpixel_order) {
1546 case CAIRO_SUBPIXEL_ORDER_DEFAULT:
1547 case CAIRO_SUBPIXEL_ORDER_RGB:
1548 case CAIRO_SUBPIXEL_ORDER_BGR:
1549 render_mode = FT_RENDER_MODE_LCD;
1550 break;
1551
1552 case CAIRO_SUBPIXEL_ORDER_VRGB:
1553 case CAIRO_SUBPIXEL_ORDER_VBGR:
1554 render_mode = FT_RENDER_MODE_LCD_V;
1555 break;
1556 }
1557
1558 switch (font_options->lcd_filter) {
1559 case CAIRO_LCD_FILTER_NONE:
1560 lcd_filter = FT_LCD_FILTER_NONE;
1561 break;
1562 case CAIRO_LCD_FILTER_INTRA_PIXEL:
1563 lcd_filter = FT_LCD_FILTER_LEGACY;
1564 break;
1565 case CAIRO_LCD_FILTER_FIR3:
1566 lcd_filter = FT_LCD_FILTER_LIGHT;
1567 break;
1568 case CAIRO_LCD_FILTER_DEFAULT:
1569 case CAIRO_LCD_FILTER_FIR5:
1570 lcd_filter = FT_LCD_FILTER_DEFAULT;
1571 break;
1572 }
1573
1574 break;
1575
1576 case CAIRO_ANTIALIAS_DEFAULT:
1577 case CAIRO_ANTIALIAS_GRAY:
1578 case CAIRO_ANTIALIAS_GOOD:
1579 case CAIRO_ANTIALIAS_FAST:
1580 render_mode = FT_RENDER_MODE_NORMAL;
1581 }
1582
1583 FT_Outline_Get_CBox (outline, &cbox);
1584
1585 cbox.xMin &= -64;
1586 cbox.yMin &= -64;
1587 cbox.xMax = (cbox.xMax + 63) & -64;
1588 cbox.yMax = (cbox.yMax + 63) & -64;
1589
1590 width = (unsigned int) ((cbox.xMax - cbox.xMin) >> 6);
1591 height = (unsigned int) ((cbox.yMax - cbox.yMin) >> 6);
1592
1593 if (width * height == 0) {
1594 cairo_format_t format;
1595 /* Looks like fb handles zero-sized images just fine */
1596 switch (render_mode) {
1597 case FT_RENDER_MODE_MONO:
1598 format = CAIRO_FORMAT_A1;
1599 break;
1600 case FT_RENDER_MODE_LCD:
1601 case FT_RENDER_MODE_LCD_V:
1602 format= CAIRO_FORMAT_ARGB32;
1603 break;
1604 case FT_RENDER_MODE_LIGHT:
1605 case FT_RENDER_MODE_NORMAL:
1606 case FT_RENDER_MODE_MAX:
1607#if HAVE_FT_RENDER_MODE_SDF1
1608 case FT_RENDER_MODE_SDF:
1609#endif
1610 default:
1611 format = CAIRO_FORMAT_A8;
1612 break;
1613 }
1614
1615 (*surface) = (cairo_image_surface_t *)
1616 cairo_image_surface_create_for_data_moz_cairo_image_surface_create_for_data (NULL((void*)0), format, 0, 0, 0);
1617 pixman_image_set_component_alpha_moz_pixman_image_set_component_alpha ((*surface)->pixman_image, TRUE1);
1618 if ((*surface)->base.status)
1619 return (*surface)->base.status;
1620 } else {
1621
1622 int bitmap_size;
1623
1624 switch (render_mode) {
1625 case FT_RENDER_MODE_LCD:
1626 if (font_options->subpixel_order == CAIRO_SUBPIXEL_ORDER_BGR)
1627 rgba = CAIRO_SUBPIXEL_ORDER_BGR;
1628 else
1629 rgba = CAIRO_SUBPIXEL_ORDER_RGB;
1630 break;
1631
1632 case FT_RENDER_MODE_LCD_V:
1633 if (font_options->subpixel_order == CAIRO_SUBPIXEL_ORDER_VBGR)
1634 rgba = CAIRO_SUBPIXEL_ORDER_VBGR;
1635 else
1636 rgba = CAIRO_SUBPIXEL_ORDER_VRGB;
1637 break;
1638
1639 case FT_RENDER_MODE_MONO:
1640 case FT_RENDER_MODE_LIGHT:
1641 case FT_RENDER_MODE_NORMAL:
1642 case FT_RENDER_MODE_MAX:
1643#if HAVE_FT_RENDER_MODE_SDF1
1644 case FT_RENDER_MODE_SDF:
1645#endif
1646 default:
1647 break;
1648 }
1649
1650 FT_Library_SetLcdFilter (library, lcd_filter);
1651 error = FT_Render_Glyph (face->glyph, render_mode);
1652
1653 FT_Library_SetLcdFilter (library, FT_LCD_FILTER_NONE);
1654 if (error)
1655 return _cairo_error (_cairo_ft_to_cairo_error (error));
1656
1657 bitmap_size = _compute_xrender_bitmap_size (&bitmap,
1658 face->glyph,
1659 render_mode);
1660 if (bitmap_size < 0)
1661 return _cairo_error (CAIRO_STATUS_INVALID_FORMAT);
1662
1663 bitmap.buffer = _cairo_calloc (bitmap_size)((bitmap_size) != 0 ? calloc(1,bitmap_size) : ((void*)0));
1664 if (bitmap.buffer == NULL((void*)0))
1665 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1666
1667 _fill_xrender_bitmap (&bitmap, face->glyph, render_mode,
1668 (rgba == CAIRO_SUBPIXEL_ORDER_BGR || rgba == CAIRO_SUBPIXEL_ORDER_VBGR));
1669
1670 /* Note:
1671 * _get_bitmap_surface will free bitmap.buffer if there is an error
1672 */
1673 status = _get_bitmap_surface (&bitmap, NULL((void*)0), TRUE1, font_options, surface);
1674 if (unlikely (status)(__builtin_expect (!!(status), 0)))
1675 return status;
1676
1677 /* Note: the font's coordinate system is upside down from ours, so the
1678 * Y coordinate of the control box needs to be negated. Moreover, device
1679 * offsets are position of glyph origin relative to top left while xMin
1680 * and yMax are offsets of top left relative to origin. Another negation.
1681 */
1682 cairo_surface_set_device_offset_moz_cairo_surface_set_device_offset (&(*surface)->base,
1683 (double)-glyphslot->bitmap_left,
1684 (double)+glyphslot->bitmap_top);
1685 }
1686
1687 return CAIRO_STATUS_SUCCESS;
1688}
1689
1690/* Converts a bitmap (or other) FT_GlyphSlot into an image */
1691static cairo_status_t
1692_render_glyph_bitmap (FT_Face face,
1693 cairo_font_options_t *font_options,
1694 cairo_image_surface_t **surface)
1695{
1696 FT_GlyphSlot glyphslot = face->glyph;
1697 cairo_status_t status;
1698 FT_Error error;
1699
1700 /* According to the FreeType docs, glyphslot->format could be
1701 * something other than FT_GLYPH_FORMAT_OUTLINE or
1702 * FT_GLYPH_FORMAT_BITMAP. Calling FT_Render_Glyph gives FreeType
1703 * the opportunity to convert such to
1704 * bitmap. FT_GLYPH_FORMAT_COMPOSITE will not be encountered since
1705 * we avoid the FT_LOAD_NO_RECURSE flag.
1706 */
1707 error = FT_Render_Glyph (glyphslot, FT_RENDER_MODE_NORMAL);
1708 /* XXX ignoring all other errors for now. They are not fatal, typically
1709 * just a glyph-not-found. */
1710 if (error == FT_Err_Out_Of_Memory)
1711 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1712
1713 status = _get_bitmap_surface (&glyphslot->bitmap,
1714 glyphslot->library,
1715 FALSE0, font_options,
1716 surface);
1717 if (unlikely (status)(__builtin_expect (!!(status), 0)))
1718 return status;
1719
1720 /*
1721 * Note: the font's coordinate system is upside down from ours, so the
1722 * Y coordinate of the control box needs to be negated. Moreover, device
1723 * offsets are position of glyph origin relative to top left while
1724 * bitmap_left and bitmap_top are offsets of top left relative to origin.
1725 * Another negation.
1726 */
1727 cairo_surface_set_device_offset_moz_cairo_surface_set_device_offset (&(*surface)->base,
1728 -glyphslot->bitmap_left,
1729 +glyphslot->bitmap_top);
1730
1731 return CAIRO_STATUS_SUCCESS;
1732}
1733
1734static cairo_status_t
1735_transform_glyph_bitmap (cairo_matrix_t * shape,
1736 cairo_image_surface_t ** surface)
1737{
1738 cairo_matrix_t original_to_transformed;
1739 cairo_matrix_t transformed_to_original;
1740 cairo_image_surface_t *old_image;
1741 cairo_surface_t *image;
1742 double x[4], y[4];
1743 double origin_x, origin_y;
1744 int orig_width, orig_height;
1745 int i;
1746 int x_min, y_min, x_max, y_max;
1747 int width, height;
1748 cairo_status_t status;
1749 cairo_surface_pattern_t pattern;
1750
1751 /* We want to compute a transform that takes the origin
1752 * (device_x_offset, device_y_offset) to 0,0, then applies
1753 * the "shape" portion of the font transform
1754 */
1755 original_to_transformed = *shape;
1756
1757 cairo_surface_get_device_offset_moz_cairo_surface_get_device_offset (&(*surface)->base, &origin_x, &origin_y);
1758 orig_width = (*surface)->width;
1759 orig_height = (*surface)->height;
1760
1761 cairo_matrix_translate_moz_cairo_matrix_translate (&original_to_transformed,
1762 -origin_x, -origin_y);
1763
1764 /* Find the bounding box of the original bitmap under that
1765 * transform
1766 */
1767 x[0] = 0; y[0] = 0;
1768 x[1] = orig_width; y[1] = 0;
1769 x[2] = orig_width; y[2] = orig_height;
1770 x[3] = 0; y[3] = orig_height;
1771
1772 for (i = 0; i < 4; i++)
1773 cairo_matrix_transform_point_moz_cairo_matrix_transform_point (&original_to_transformed,
1774 &x[i], &y[i]);
1775
1776 x_min = floor (x[0]); y_min = floor (y[0]);
1777 x_max = ceil (x[0]); y_max = ceil (y[0]);
1778
1779 for (i = 1; i < 4; i++) {
1780 if (x[i] < x_min)
1781 x_min = floor (x[i]);
1782 else if (x[i] > x_max)
1783 x_max = ceil (x[i]);
1784 if (y[i] < y_min)
1785 y_min = floor (y[i]);
1786 else if (y[i] > y_max)
1787 y_max = ceil (y[i]);
1788 }
1789
1790 /* Adjust the transform so that the bounding box starts at 0,0 ...
1791 * this gives our final transform from original bitmap to transformed
1792 * bitmap.
1793 */
1794 original_to_transformed.x0 -= x_min;
1795 original_to_transformed.y0 -= y_min;
1796
1797 /* Create the transformed bitmap */
1798 width = x_max - x_min;
1799 height = y_max - y_min;
1800
1801 transformed_to_original = original_to_transformed;
1802 status = cairo_matrix_invert_moz_cairo_matrix_invert (&transformed_to_original);
1803 if (unlikely (status)(__builtin_expect (!!(status), 0)))
1804 return status;
1805
1806 if ((*surface)->format == CAIRO_FORMAT_ARGB32 &&
1807 !pixman_image_get_component_alpha_moz_pixman_image_get_component_alpha ((*surface)->pixman_image))
1808 image = cairo_image_surface_create_moz_cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
1809 else
1810 image = cairo_image_surface_create_moz_cairo_image_surface_create (CAIRO_FORMAT_A8, width, height);
1811 if (unlikely (image->status)(__builtin_expect (!!(image->status), 0)))
1812 return image->status;
1813
1814 /* Draw the original bitmap transformed into the new bitmap
1815 */
1816 _cairo_pattern_init_for_surface (&pattern, &(*surface)->base);
1817 cairo_pattern_set_matrix_moz_cairo_pattern_set_matrix (&pattern.base, &transformed_to_original);
1818
1819 status = _cairo_surface_paint (image,
1820 CAIRO_OPERATOR_SOURCE,
1821 &pattern.base,
1822 NULL((void*)0));
1823
1824 _cairo_pattern_fini (&pattern.base);
1825
1826 if (unlikely (status)(__builtin_expect (!!(status), 0))) {
1827 cairo_surface_destroy_moz_cairo_surface_destroy (image);
1828 return status;
1829 }
1830
1831 /* Now update the cache entry for the new bitmap, recomputing
1832 * the origin based on the final transform.
1833 */
1834 cairo_matrix_transform_point_moz_cairo_matrix_transform_point (&original_to_transformed,
1835 &origin_x, &origin_y);
1836
1837 old_image = (*surface);
1838 (*surface) = (cairo_image_surface_t *)image;
1839
1840 /* Note: we converted subpixel-rendered RGBA images to grayscale,
1841 * so, no need to copy component alpha to new image. */
1842
1843 cairo_surface_destroy_moz_cairo_surface_destroy (&old_image->base);
1844
1845 cairo_surface_set_device_offset_moz_cairo_surface_set_device_offset (&(*surface)->base,
1846 _cairo_lround (origin_x),
1847 _cairo_lround (origin_y));
1848 return CAIRO_STATUS_SUCCESS;
1849}
1850
1851static const cairo_unscaled_font_backend_t cairo_ft_unscaled_font_backend = {
1852 _cairo_ft_unscaled_font_destroy,
1853#if 0
1854 _cairo_ft_unscaled_font_create_glyph
1855#endif
1856};
1857
1858/* #cairo_ft_scaled_font_t */
1859
1860typedef struct _cairo_ft_scaled_font {
1861 cairo_scaled_font_t base;
1862 cairo_ft_unscaled_font_t *unscaled;
1863 cairo_ft_options_t ft_options;
1864} cairo_ft_scaled_font_t;
1865
1866static const cairo_scaled_font_backend_t _cairo_ft_scaled_font_backend;
1867
1868#if CAIRO_HAS_FC_FONT1
1869/* The load flags passed to FT_Load_Glyph control aspects like hinting and
1870 * antialiasing. Here we compute them from the fields of a FcPattern.
1871 */
1872static void
1873_get_pattern_ft_options (FcPattern *pattern, cairo_ft_options_t *ret)
1874{
1875 FcBool antialias, vertical_layout, hinting, autohint, bitmap, embolden;
1876 cairo_ft_options_t ft_options;
1877 int rgba;
1878 int hintstyle;
1879 char *variations;
1880
1881 _cairo_font_options_init_default (&ft_options.base);
1882 ft_options.load_flags = FT_LOAD_DEFAULT0x0;
1883 ft_options.synth_flags = 0;
1884
1885 /* Check whether to force use of embedded bitmaps */
1886 if (FcPatternGetBool (pattern,
1887 FC_EMBEDDED_BITMAP"embeddedbitmap", 0, &bitmap) != FcResultMatch)
1888 bitmap = FcFalse0;
1889
1890 /* disable antialiasing if requested */
1891 if (FcPatternGetBool (pattern,
1892 FC_ANTIALIAS"antialias", 0, &antialias) != FcResultMatch)
1893 antialias = FcTrue1;
1894
1895 if (antialias) {
1896 cairo_subpixel_order_t subpixel_order;
1897 int lcd_filter;
1898
1899 /* disable hinting if requested */
1900 if (FcPatternGetBool (pattern,
1901 FC_HINTING"hinting", 0, &hinting) != FcResultMatch)
1902 hinting = FcTrue1;
1903
1904 if (FcPatternGetInteger (pattern,
1905 FC_RGBA"rgba", 0, &rgba) != FcResultMatch)
1906 rgba = FC_RGBA_UNKNOWN0;
1907
1908 switch (rgba) {
1909 case FC_RGBA_RGB1:
1910 subpixel_order = CAIRO_SUBPIXEL_ORDER_RGB;
1911 break;
1912 case FC_RGBA_BGR2:
1913 subpixel_order = CAIRO_SUBPIXEL_ORDER_BGR;
1914 break;
1915 case FC_RGBA_VRGB3:
1916 subpixel_order = CAIRO_SUBPIXEL_ORDER_VRGB;
1917 break;
1918 case FC_RGBA_VBGR4:
1919 subpixel_order = CAIRO_SUBPIXEL_ORDER_VBGR;
1920 break;
1921 case FC_RGBA_UNKNOWN0:
1922 case FC_RGBA_NONE5:
1923 default:
1924 subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT;
1925 break;
1926 }
1927
1928 if (subpixel_order != CAIRO_SUBPIXEL_ORDER_DEFAULT) {
1929 ft_options.base.subpixel_order = subpixel_order;
1930 ft_options.base.antialias = CAIRO_ANTIALIAS_SUBPIXEL;
1931 }
1932
1933 if (FcPatternGetInteger (pattern,
1934 FC_LCD_FILTER"lcdfilter", 0, &lcd_filter) == FcResultMatch)
1935 {
1936 switch (lcd_filter) {
1937 case FC_LCD_NONE0:
1938 ft_options.base.lcd_filter = CAIRO_LCD_FILTER_NONE;
1939 break;
1940 case FC_LCD_DEFAULT1:
1941 ft_options.base.lcd_filter = CAIRO_LCD_FILTER_FIR5;
1942 break;
1943 case FC_LCD_LIGHT2:
1944 ft_options.base.lcd_filter = CAIRO_LCD_FILTER_FIR3;
1945 break;
1946 case FC_LCD_LEGACY3:
1947 ft_options.base.lcd_filter = CAIRO_LCD_FILTER_INTRA_PIXEL;
1948 break;
1949 }
1950 }
1951
1952 if (FcPatternGetInteger (pattern,
1953 FC_HINT_STYLE"hintstyle", 0, &hintstyle) != FcResultMatch)
1954 hintstyle = FC_HINT_FULL3;
1955
1956 if (!hinting)
1957 hintstyle = FC_HINT_NONE0;
1958
1959 switch (hintstyle) {
1960 case FC_HINT_NONE0:
1961 ft_options.base.hint_style = CAIRO_HINT_STYLE_NONE;
1962 break;
1963 case FC_HINT_SLIGHT1:
1964 ft_options.base.hint_style = CAIRO_HINT_STYLE_SLIGHT;
1965 break;
1966 case FC_HINT_MEDIUM2:
1967 default:
1968 ft_options.base.hint_style = CAIRO_HINT_STYLE_MEDIUM;
1969 break;
1970 case FC_HINT_FULL3:
1971 ft_options.base.hint_style = CAIRO_HINT_STYLE_FULL;
1972 break;
1973 }
1974
1975 /* Force embedded bitmaps off if no hinting requested */
1976 if (ft_options.base.hint_style == CAIRO_HINT_STYLE_NONE)
1977 bitmap = FcFalse0;
1978
1979 if (!bitmap)
1980 ft_options.load_flags |= FT_LOAD_NO_BITMAP( 1L << 3 );
1981
1982 } else {
1983 ft_options.base.antialias = CAIRO_ANTIALIAS_NONE;
1984 }
1985
1986 /* force autohinting if requested */
1987 if (FcPatternGetBool (pattern,
1988 FC_AUTOHINT"autohint", 0, &autohint) != FcResultMatch)
1989 autohint = FcFalse0;
1990
1991 if (autohint)
1992 ft_options.load_flags |= FT_LOAD_FORCE_AUTOHINT( 1L << 5 );
1993
1994 if (FcPatternGetBool (pattern,
1995 FC_VERTICAL_LAYOUT"verticallayout", 0, &vertical_layout) != FcResultMatch)
1996 vertical_layout = FcFalse0;
1997
1998 if (vertical_layout)
1999 ft_options.load_flags |= FT_LOAD_VERTICAL_LAYOUT( 1L << 4 );
2000
2001 if (FcPatternGetBool (pattern,
2002 FC_EMBOLDEN"embolden", 0, &embolden) != FcResultMatch)
2003 embolden = FcFalse0;
2004
2005 if (embolden)
2006 ft_options.synth_flags |= CAIRO_FT_SYNTHESIZE_BOLD;
2007
2008#ifndef FC_FONT_VARIATIONS"fontvariations"
2009#define FC_FONT_VARIATIONS"fontvariations" "fontvariations"
2010#endif
2011 if (FcPatternGetString (pattern, FC_FONT_VARIATIONS"fontvariations", 0, (FcChar8 **) &variations) == FcResultMatch) {
2012 ft_options.base.variations = strdup (variations);
2013 }
2014
2015 *ret = ft_options;
2016}
2017#endif
2018
2019static void
2020_cairo_ft_options_merge (cairo_ft_options_t *options,
2021 cairo_ft_options_t *other)
2022{
2023 int load_flags = other->load_flags;
2024 int load_target = FT_LOAD_TARGET_NORMAL( (FT_Int32)((FT_RENDER_MODE_NORMAL) & 15) << 16 );
2025
2026 /* clear load target mode */
2027 load_flags &= ~(FT_LOAD_TARGET_(FT_LOAD_TARGET_MODE(other->load_flags))( (FT_Int32)(((FT_Render_Mode)(( (other->load_flags) >>
16 ) & 15)) & 15) << 16 )
);
2028
2029 if (load_flags & FT_LOAD_NO_HINTING( 1L << 1 ))
2030 other->base.hint_style = CAIRO_HINT_STYLE_NONE;
2031
2032 if (other->base.antialias == CAIRO_ANTIALIAS_NONE ||
2033 options->base.antialias == CAIRO_ANTIALIAS_NONE) {
2034 options->base.antialias = CAIRO_ANTIALIAS_NONE;
2035 options->base.subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT;
2036 }
2037
2038 if (other->base.antialias == CAIRO_ANTIALIAS_SUBPIXEL &&
2039 options->base.antialias == CAIRO_ANTIALIAS_DEFAULT) {
2040 options->base.antialias = CAIRO_ANTIALIAS_SUBPIXEL;
2041 options->base.subpixel_order = other->base.subpixel_order;
2042 }
2043
2044 if (options->base.hint_style == CAIRO_HINT_STYLE_DEFAULT)
2045 options->base.hint_style = other->base.hint_style;
2046
2047 if (other->base.hint_style == CAIRO_HINT_STYLE_NONE)
2048 options->base.hint_style = CAIRO_HINT_STYLE_NONE;
2049
2050 if (options->base.lcd_filter == CAIRO_LCD_FILTER_DEFAULT)
2051 options->base.lcd_filter = other->base.lcd_filter;
2052
2053 if (other->base.lcd_filter == CAIRO_LCD_FILTER_NONE)
2054 options->base.lcd_filter = CAIRO_LCD_FILTER_NONE;
2055
2056 if (options->base.antialias == CAIRO_ANTIALIAS_NONE) {
2057 if (options->base.hint_style == CAIRO_HINT_STYLE_NONE)
2058 load_flags |= FT_LOAD_NO_HINTING( 1L << 1 );
2059 else
2060 load_target = FT_LOAD_TARGET_MONO( (FT_Int32)((FT_RENDER_MODE_MONO) & 15) << 16 );
2061 load_flags |= FT_LOAD_MONOCHROME( 1L << 12 );
2062 } else {
2063 switch (options->base.hint_style) {
2064 case CAIRO_HINT_STYLE_NONE:
2065 load_flags |= FT_LOAD_NO_HINTING( 1L << 1 );
2066 break;
2067 case CAIRO_HINT_STYLE_SLIGHT:
2068 load_target = FT_LOAD_TARGET_LIGHT( (FT_Int32)((FT_RENDER_MODE_LIGHT) & 15) << 16 );
2069 break;
2070 case CAIRO_HINT_STYLE_MEDIUM:
2071 break;
2072 case CAIRO_HINT_STYLE_FULL:
2073 case CAIRO_HINT_STYLE_DEFAULT:
2074 if (options->base.antialias == CAIRO_ANTIALIAS_SUBPIXEL) {
2075 switch (options->base.subpixel_order) {
2076 case CAIRO_SUBPIXEL_ORDER_DEFAULT:
2077 case CAIRO_SUBPIXEL_ORDER_RGB:
2078 case CAIRO_SUBPIXEL_ORDER_BGR:
2079 load_target = FT_LOAD_TARGET_LCD( (FT_Int32)((FT_RENDER_MODE_LCD) & 15) << 16 );
2080 break;
2081 case CAIRO_SUBPIXEL_ORDER_VRGB:
2082 case CAIRO_SUBPIXEL_ORDER_VBGR:
2083 load_target = FT_LOAD_TARGET_LCD_V( (FT_Int32)((FT_RENDER_MODE_LCD_V) & 15) << 16 );
2084 break;
2085 }
2086 }
2087 break;
2088 }
2089 }
2090
2091 if (other->base.variations) {
2092 if (options->base.variations) {
2093 char *p;
2094
2095 /* 'merge' variations by concatenating - later entries win */
2096 p = malloc (strlen (other->base.variations) + strlen (options->base.variations) + 2);
2097 p[0] = 0;
2098 strcat (p, other->base.variations);
2099 strcat (p, ",");
2100 strcat (p, options->base.variations);
2101 free (options->base.variations);
2102 options->base.variations = p;
2103 }
2104 else {
2105 options->base.variations = strdup (other->base.variations);
2106 }
2107 }
2108
2109 options->load_flags = load_flags | load_target;
2110 options->synth_flags = other->synth_flags;
2111}
2112
2113static cairo_status_t
2114_cairo_ft_font_face_scaled_font_create (void *abstract_font_face,
2115 const cairo_matrix_t *font_matrix,
2116 const cairo_matrix_t *ctm,
2117 const cairo_font_options_t *options,
2118 cairo_scaled_font_t **font_out)
2119{
2120 cairo_ft_font_face_t *font_face = abstract_font_face;
2121 cairo_ft_scaled_font_t *scaled_font;
2122 FT_Face face;
2123 FT_Size_Metrics *metrics;
2124 cairo_font_extents_t fs_metrics;
2125 cairo_status_t status;
2126 cairo_ft_unscaled_font_t *unscaled;
2127
2128 assert (font_face->unscaled)((void) sizeof (__assert_single_arg (font_face->unscaled))
, __extension__ ({ if (font_face->unscaled) ; else __assert_fail
("font_face->unscaled", "/root/firefox-clang/gfx/cairo/cairo/src/cairo-ft-font.c"
, 2128, __extension__ __PRETTY_FUNCTION__); }))
;
2129
2130 face = _cairo_ft_unscaled_font_lock_face (font_face->unscaled);
2131 if (unlikely (face == NULL)(__builtin_expect (!!(face == ((void*)0)), 0))) /* backend error */
2132 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2133
2134 scaled_font = _cairo_calloc (sizeof (cairo_ft_scaled_font_t))((sizeof (cairo_ft_scaled_font_t)) != 0 ? calloc(1,sizeof (cairo_ft_scaled_font_t
)) : ((void*)0))
;
2135 if (unlikely (scaled_font == NULL)(__builtin_expect (!!(scaled_font == ((void*)0)), 0))) {
2136 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
2137 goto FAIL;
2138 }
2139
2140 scaled_font->unscaled = unscaled = font_face->unscaled;
2141 _cairo_unscaled_font_reference (&unscaled->base);
2142
2143 _cairo_font_options_init_copy (&scaled_font->ft_options.base, options);
2144 _cairo_ft_options_merge (&scaled_font->ft_options, &font_face->ft_options);
2145
2146 status = _cairo_scaled_font_init (&scaled_font->base,
2147 &font_face->base,
2148 font_matrix, ctm, options,
2149 &_cairo_ft_scaled_font_backend);
2150 if (unlikely (status)(__builtin_expect (!!(status), 0)))
2151 goto CLEANUP_SCALED_FONT;
2152
2153 status = _cairo_ft_unscaled_font_set_scale (unscaled,
2154 &scaled_font->base.scale);
2155 if (unlikely (status)(__builtin_expect (!!(status), 0))) {
2156 /* This can only fail if we encounter an error with the underlying
2157 * font, so propagate the error back to the font-face. */
2158 _cairo_ft_unscaled_font_unlock_face (unscaled);
2159 _cairo_unscaled_font_destroy (&unscaled->base);
2160 free (scaled_font);
2161 return status;
2162 }
2163
2164
2165 metrics = &face->size->metrics;
2166
2167 /*
2168 * Get to unscaled metrics so that the upper level can get back to
2169 * user space
2170 *
2171 * Also use this path for bitmap-only fonts. The other branch uses
2172 * face members that are only relevant for scalable fonts. This is
2173 * detected by simply checking for units_per_EM==0.
2174 */
2175 if (scaled_font->base.options.hint_metrics != CAIRO_HINT_METRICS_OFF ||
2176 face->units_per_EM == 0) {
2177 fs_metrics.ascent = SCALE (DOUBLE_FROM_26_6 (metrics->ascender), unscaled->y_scale)((unscaled->y_scale) == 0 ? 0.0 : (((double)(metrics->ascender
) / 64.0)) / (unscaled->y_scale))
;
2178 fs_metrics.descent = SCALE (DOUBLE_FROM_26_6 (- metrics->descender), unscaled->y_scale)((unscaled->y_scale) == 0 ? 0.0 : (((double)(- metrics->
descender) / 64.0)) / (unscaled->y_scale))
;
2179 fs_metrics.height = SCALE (DOUBLE_FROM_26_6 (metrics->height), unscaled->y_scale)((unscaled->y_scale) == 0 ? 0.0 : (((double)(metrics->height
) / 64.0)) / (unscaled->y_scale))
;
2180 if (!_cairo_ft_scaled_font_is_vertical (&scaled_font->base)) {
2181 fs_metrics.max_x_advance = SCALE (DOUBLE_FROM_26_6 (metrics->max_advance), unscaled->x_scale)((unscaled->x_scale) == 0 ? 0.0 : (((double)(metrics->max_advance
) / 64.0)) / (unscaled->x_scale))
;
2182 fs_metrics.max_y_advance = 0;
2183 } else {
2184 fs_metrics.max_x_advance = 0;
2185 fs_metrics.max_y_advance = SCALE (DOUBLE_FROM_26_6 (metrics->max_advance), unscaled->y_scale)((unscaled->y_scale) == 0 ? 0.0 : (((double)(metrics->max_advance
) / 64.0)) / (unscaled->y_scale))
;
2186 }
2187 } else {
2188 double scale = face->units_per_EM;
2189
2190 fs_metrics.ascent = face->ascender / scale;
2191 fs_metrics.descent = - face->descender / scale;
2192 fs_metrics.height = face->height / scale;
2193 if (!_cairo_ft_scaled_font_is_vertical (&scaled_font->base)) {
2194 fs_metrics.max_x_advance = face->max_advance_width / scale;
2195 fs_metrics.max_y_advance = 0;
2196 } else {
2197 fs_metrics.max_x_advance = 0;
2198 fs_metrics.max_y_advance = face->max_advance_height / scale;
2199 }
2200 }
2201
2202 status = _cairo_scaled_font_set_metrics (&scaled_font->base, &fs_metrics);
2203 if (unlikely (status)(__builtin_expect (!!(status), 0)))
2204 goto CLEANUP_SCALED_FONT;
2205
2206 _cairo_ft_unscaled_font_unlock_face (unscaled);
2207
2208 *font_out = &scaled_font->base;
2209 return CAIRO_STATUS_SUCCESS;
2210
2211 CLEANUP_SCALED_FONT:
2212 _cairo_unscaled_font_destroy (&unscaled->base);
2213 free (scaled_font);
2214 FAIL:
2215 _cairo_ft_unscaled_font_unlock_face (font_face->unscaled);
2216 *font_out = _cairo_scaled_font_create_in_error (status);
2217 return CAIRO_STATUS_SUCCESS; /* non-backend error */
2218}
2219
2220cairo_bool_t
2221_cairo_scaled_font_is_ft (cairo_scaled_font_t *scaled_font)
2222{
2223 return scaled_font->backend == &_cairo_ft_scaled_font_backend;
2224}
2225
2226static void
2227_cairo_ft_scaled_font_fini (void *abstract_font)
2228{
2229 cairo_ft_scaled_font_t *scaled_font = abstract_font;
2230
2231 if (scaled_font == NULL((void*)0))
2232 return;
2233
2234 _cairo_font_options_fini (&scaled_font->ft_options.base);
2235 _cairo_unscaled_font_destroy (&scaled_font->unscaled->base);
2236}
2237
2238static int
2239_move_to (FT_Vector *to, void *closure)
2240{
2241 cairo_path_fixed_t *path = closure;
2242 cairo_fixed_t x, y;
2243
2244 x = _cairo_fixed_from_26_6 (to->x);
2245 y = _cairo_fixed_from_26_6 (to->y);
2246
2247 if (_cairo_path_fixed_close_path (path) != CAIRO_STATUS_SUCCESS)
2248 return 1;
2249 if (_cairo_path_fixed_move_to (path, x, y) != CAIRO_STATUS_SUCCESS)
2250 return 1;
2251
2252 return 0;
2253}
2254
2255static int
2256_line_to (FT_Vector *to, void *closure)
2257{
2258 cairo_path_fixed_t *path = closure;
2259 cairo_fixed_t x, y;
2260
2261 x = _cairo_fixed_from_26_6 (to->x);
2262 y = _cairo_fixed_from_26_6 (to->y);
2263
2264 if (_cairo_path_fixed_line_to (path, x, y) != CAIRO_STATUS_SUCCESS)
2265 return 1;
2266
2267 return 0;
2268}
2269
2270static int
2271_conic_to (FT_Vector *control, FT_Vector *to, void *closure)
2272{
2273 cairo_path_fixed_t *path = closure;
2274
2275 cairo_fixed_t x0, y0;
2276 cairo_fixed_t x1, y1;
2277 cairo_fixed_t x2, y2;
2278 cairo_fixed_t x3, y3;
2279 cairo_point_t conic;
2280
2281 if (! _cairo_path_fixed_get_current_point (path, &x0, &y0))
2282 return 1;
2283
2284 conic.x = _cairo_fixed_from_26_6 (control->x);
2285 conic.y = _cairo_fixed_from_26_6 (control->y);
2286
2287 x3 = _cairo_fixed_from_26_6 (to->x);
2288 y3 = _cairo_fixed_from_26_6 (to->y);
2289
2290 x1 = x0 + 2.0/3.0 * (conic.x - x0);
2291 y1 = y0 + 2.0/3.0 * (conic.y - y0);
2292
2293 x2 = x3 + 2.0/3.0 * (conic.x - x3);
2294 y2 = y3 + 2.0/3.0 * (conic.y - y3);
2295
2296 if (_cairo_path_fixed_curve_to (path,
2297 x1, y1,
2298 x2, y2,
2299 x3, y3) != CAIRO_STATUS_SUCCESS)
2300 return 1;
2301
2302 return 0;
2303}
2304
2305static int
2306_cubic_to (FT_Vector *control1, FT_Vector *control2,
2307 FT_Vector *to, void *closure)
2308{
2309 cairo_path_fixed_t *path = closure;
2310 cairo_fixed_t x0, y0;
2311 cairo_fixed_t x1, y1;
2312 cairo_fixed_t x2, y2;
2313
2314 x0 = _cairo_fixed_from_26_6 (control1->x);
2315 y0 = _cairo_fixed_from_26_6 (control1->y);
2316
2317 x1 = _cairo_fixed_from_26_6 (control2->x);
2318 y1 = _cairo_fixed_from_26_6 (control2->y);
2319
2320 x2 = _cairo_fixed_from_26_6 (to->x);
2321 y2 = _cairo_fixed_from_26_6 (to->y);
2322
2323 if (_cairo_path_fixed_curve_to (path,
2324 x0, y0,
2325 x1, y1,
2326 x2, y2) != CAIRO_STATUS_SUCCESS)
2327 return 1;
2328
2329 return 0;
2330}
2331
2332cairo_status_t
2333_cairo_ft_face_decompose_glyph_outline (FT_Face face,
2334 cairo_path_fixed_t **pathp)
2335{
2336 static const FT_Outline_Funcs outline_funcs = {
2337 (FT_Outline_MoveToFunc)_move_to,
2338 (FT_Outline_LineToFunc)_line_to,
2339 (FT_Outline_ConicToFunc)_conic_to,
2340 (FT_Outline_CubicToFunc)_cubic_to,
2341 0, /* shift */
2342 0, /* delta */
2343 };
2344 static const FT_Matrix invert_y = {
2345 DOUBLE_TO_16_16 (1.0)((FT_Fixed)((1.0) * 65536.0)), 0,
2346 0, DOUBLE_TO_16_16 (-1.0)((FT_Fixed)((-1.0) * 65536.0)),
2347 };
2348
2349 FT_GlyphSlot glyph;
2350 cairo_path_fixed_t *path;
2351 cairo_status_t status;
2352
2353 path = _cairo_path_fixed_create ();
2354 if (!path)
2355 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2356
2357 glyph = face->glyph;
2358
2359 /* Font glyphs have an inverted Y axis compared to cairo. */
2360 FT_Outline_Transform (&glyph->outline, &invert_y);
2361 if (FT_Outline_Decompose (&glyph->outline, &outline_funcs, path)) {
2362 _cairo_path_fixed_destroy (path);
2363 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2364 }
2365
2366 status = _cairo_path_fixed_close_path (path);
2367 if (unlikely (status)(__builtin_expect (!!(status), 0))) {
2368 _cairo_path_fixed_destroy (path);
2369 return status;
2370 }
2371
2372 *pathp = path;
2373
2374 return CAIRO_STATUS_SUCCESS;
2375}
2376
2377/*
2378 * Translate glyph to match its metrics.
2379 */
2380static void
2381_cairo_ft_scaled_glyph_vertical_layout_bearing_fix (void *abstract_font,
2382 FT_GlyphSlot glyph)
2383{
2384 cairo_ft_scaled_font_t *scaled_font = abstract_font;
2385 FT_Vector vector;
2386
2387 vector.x = glyph->metrics.vertBearingX - glyph->metrics.horiBearingX;
2388 vector.y = -glyph->metrics.vertBearingY - glyph->metrics.horiBearingY;
2389
2390 if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
2391 FT_Vector_Transform (&vector, &scaled_font->unscaled->Current_Shape);
2392 FT_Outline_Translate(&glyph->outline, vector.x, vector.y);
2393 } else if (glyph->format == FT_GLYPH_FORMAT_BITMAP) {
2394 glyph->bitmap_left += vector.x / 64;
2395 glyph->bitmap_top += vector.y / 64;
2396 }
2397}
2398
2399static void
2400cairo_ft_apply_variations (FT_Face face,
2401 cairo_ft_scaled_font_t *scaled_font)
2402{
2403 FT_MM_Var *ft_mm_var;
2404 FT_Error ret;
2405 unsigned int instance_id = scaled_font->unscaled->id >> 16;
2406
2407 static GetVarFunc getVar;
2408 static DoneVarFunc doneVar;
2409 static GetVarDesignCoordsFunc getVarDesignCoords;
2410 static SetVarDesignCoordsFunc setVarDesignCoords;
2411
2412 static int firstTime = 1;
2413 if (firstTime) {
2414 getVar = (GetVarFunc) dlsym (RTLD_DEFAULT((void *) 0), "FT_Get_MM_Var");
2415 doneVar = (DoneVarFunc) dlsym (RTLD_DEFAULT((void *) 0), "FT_Done_MM_Var");
2416 getVarDesignCoords = (GetVarDesignCoordsFunc) dlsym (RTLD_DEFAULT((void *) 0), "FT_Get_Var_Design_Coordinates");
2417 setVarDesignCoords = (SetVarDesignCoordsFunc) dlsym (RTLD_DEFAULT((void *) 0), "FT_Set_Var_Design_Coordinates");
2418 firstTime = 0;
2419 }
2420
2421 if (!getVar || !setVarDesignCoords)
2422 return;
2423
2424 ret = (*getVar) (face, &ft_mm_var);
2425 if (ret == 0) {
2426 FT_Fixed *current_coords;
2427 FT_Fixed *coords;
2428 unsigned int i;
2429 const char *p;
2430
2431 coords = malloc (sizeof (FT_Fixed) * ft_mm_var->num_axis);
2432 /* FIXME check coords. */
2433
2434 if (scaled_font->unscaled->variations)
2435 {
2436 memcpy (coords, scaled_font->unscaled->variations, ft_mm_var->num_axis * sizeof (*coords));
2437 }
2438 else if (instance_id && instance_id <= ft_mm_var->num_namedstyles)
2439 {
2440 FT_Var_Named_Style *instance = &ft_mm_var->namedstyle[instance_id - 1];
2441 memcpy (coords, instance->coords, ft_mm_var->num_axis * sizeof (*coords));
2442 }
2443 else
2444 for (i = 0; i < ft_mm_var->num_axis; i++)
2445 coords[i] = ft_mm_var->axis[i].def;
2446
2447 p = scaled_font->ft_options.base.variations;
2448 while (p && *p) {
2449 const char *start;
2450 const char *end, *end2;
2451 FT_ULong tag;
2452 double value;
2453
2454 while (_cairo_isspace (*p)) p++;
2455
2456 start = p;
2457 end = strchr (p, ',')_Generic (0 ? (p) : (void *) 1, const void *: (const char *) (
strchr (p, ',')), default: strchr (p, ','))
;
2458 if (end && (end - p < 6))
2459 goto skip;
2460
2461 tag = FT_MAKE_TAG(p[0], p[1], p[2], p[3])( ( (FT_Tag)(unsigned char)(p[0]) << 24 ) | ( (FT_Tag)(
unsigned char)(p[1]) << 16 ) | ( (FT_Tag)(unsigned char
)(p[2]) << 8 ) | (FT_Tag)(unsigned char)(p[3]) )
;
2462
2463 p += 4;
2464 while (_cairo_isspace (*p)) p++;
2465 if (*p == '=') p++;
2466
2467 if (p - start < 5)
2468 goto skip;
2469
2470 value = _cairo_strtod (p, (char **) &end2);
2471
2472 while (end2 && _cairo_isspace (*end2)) end2++;
2473
2474 if (end2 && (*end2 != ',' && *end2 != '\0'))
2475 goto skip;
2476
2477 for (i = 0; i < ft_mm_var->num_axis; i++) {
2478 if (ft_mm_var->axis[i].tag == tag) {
2479 coords[i] = (FT_Fixed)(value*65536);
2480 break;
2481 }
2482 }
2483
2484skip:
2485 p = end ? end + 1 : NULL((void*)0);
2486 }
2487
2488 current_coords = malloc (sizeof (FT_Fixed) * ft_mm_var->num_axis);
2489
2490 if (getVarDesignCoords) {
2491 ret = (*getVarDesignCoords) (face, ft_mm_var->num_axis, current_coords);
2492 if (ret == 0) {
2493 for (i = 0; i < ft_mm_var->num_axis; i++) {
2494 if (coords[i] != current_coords[i])
2495 break;
2496 }
2497 if (i == ft_mm_var->num_axis)
2498 goto done;
2499 }
2500 }
2501
2502 (*setVarDesignCoords) (face, ft_mm_var->num_axis, coords);
2503done:
2504 free (coords);
2505 free (current_coords);
2506
2507 if (doneVar)
2508 (*doneVar) (face->glyph->library, ft_mm_var);
2509 else
2510 free (ft_mm_var);
2511 }
2512}
2513
2514typedef enum {
2515 CAIRO_FT_GLYPH_TYPE_BITMAP,
2516 CAIRO_FT_GLYPH_TYPE_OUTLINE,
2517 CAIRO_FT_GLYPH_TYPE_SVG,
2518 CAIRO_FT_GLYPH_TYPE_COLR_V0,
2519 CAIRO_FT_GLYPH_TYPE_COLR_V1,
2520} cairo_ft_glyph_format_t;
2521
2522typedef struct {
2523 cairo_scaled_glyph_private_t base;
2524
2525 cairo_ft_glyph_format_t format;
2526} cairo_ft_glyph_private_t;
2527
2528static const int ft_glyph_private_key;
2529
2530static cairo_int_status_t
2531_cairo_ft_scaled_glyph_load_glyph (cairo_ft_scaled_font_t *scaled_font,
2532 cairo_scaled_glyph_t *scaled_glyph,
2533 FT_Face face,
2534 int load_flags,
2535 cairo_bool_t use_em_size,
2536 cairo_bool_t vertical_layout)
2537{
2538 FT_Error error;
2539 cairo_status_t status;
2540 cairo_ft_glyph_private_t *glyph_priv;
2541
2542 glyph_priv = (cairo_ft_glyph_private_t *) _cairo_scaled_glyph_find_private (scaled_glyph,
2543 &ft_glyph_private_key);
2544 assert (glyph_priv != NULL)((void) sizeof (__assert_single_arg (glyph_priv != ((void*)0)
)), __extension__ ({ if (glyph_priv != ((void*)0)) ; else __assert_fail
("glyph_priv != NULL", "/root/firefox-clang/gfx/cairo/cairo/src/cairo-ft-font.c"
, 2544, __extension__ __PRETTY_FUNCTION__); }))
;
2545
2546 if (use_em_size) {
2547 cairo_matrix_t em_size;
2548 cairo_matrix_init_scale_moz_cairo_matrix_init_scale (&em_size, face->units_per_EM, face->units_per_EM);
2549 status = _cairo_ft_unscaled_font_set_scale (scaled_font->unscaled, &em_size);
2550 } else {
2551 status = _cairo_ft_unscaled_font_set_scale (scaled_font->unscaled,
2552 &scaled_font->base.scale);
2553 }
2554 if (unlikely (status)(__builtin_expect (!!(status), 0)))
2555 return status;
2556
2557 cairo_ft_apply_variations (face, scaled_font);
2558
2559#if defined(HAVE_FT_LOAD_NO_SVG)
2560 if (load_flags & FT_LOAD_COLOR( 1L << 20 ) && glyph_priv->format == CAIRO_FT_GLYPH_TYPE_COLR_V1)
2561 load_flags |= FT_LOAD_NO_SVG( 1L << 24 );
2562#endif
2563
2564 error = FT_Load_Glyph (face,
2565 _cairo_scaled_glyph_index(scaled_glyph)((unsigned long)((scaled_glyph)->hash_entry.hash & 0xffffff
))
,
2566 load_flags);
2567 /* XXX ignoring all other errors for now. They are not fatal, typically
2568 * just a glyph-not-found. */
2569 if (error == FT_Err_Out_Of_Memory)
2570 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2571
2572 /*
2573 * synthesize glyphs if requested
2574 */
2575 if (scaled_font->ft_options.synth_flags & CAIRO_FT_SYNTHESIZE_BOLD)
2576 FT_GlyphSlot_Embolden (face->glyph);
2577
2578 if (scaled_font->ft_options.synth_flags & CAIRO_FT_SYNTHESIZE_OBLIQUE)
2579 FT_GlyphSlot_Oblique (face->glyph);
2580
2581 if (vertical_layout)
2582 _cairo_ft_scaled_glyph_vertical_layout_bearing_fix (scaled_font, face->glyph);
2583
2584 if (face->glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
2585 FT_Pos xshift, yshift;
2586
2587 xshift = _cairo_scaled_glyph_xphase (scaled_glyph)(int)(((scaled_glyph)->hash_entry.hash >> 24) & 3
)
<< 4;
2588 yshift = _cairo_scaled_glyph_yphase (scaled_glyph)(int)(((scaled_glyph)->hash_entry.hash >> 26) & 3
)
<< 4;
2589
2590 FT_Outline_Translate (&face->glyph->outline, xshift, -yshift);
2591 }
2592
2593 return CAIRO_STATUS_SUCCESS;
2594}
2595
2596static void
2597_cairo_ft_glyph_fini (cairo_scaled_glyph_private_t *glyph_private,
2598 cairo_scaled_glyph_t *glyph,
2599 cairo_scaled_font_t *font)
2600{
2601 cairo_list_del (&glyph_private->link);
2602 free (glyph_private);
2603}
2604
2605
2606#ifdef FT_COLOR_H<freetype/ftcolor.h>
2607static void
2608_cairo_ft_scaled_glyph_set_palette (cairo_ft_scaled_font_t *scaled_font,
2609 FT_Face face,
2610 unsigned int *num_entries_ret,
2611 FT_Color **entries_ret)
2612{
2613 unsigned int num_entries = 0;
2614 FT_Color *entries = NULL((void*)0);
2615
2616 FT_Palette_Data palette_data;
2617
2618 if (FT_Palette_Data_Get (face, &palette_data) == 0 && palette_data.num_palettes > 0) {
2619 FT_UShort palette_index = CAIRO_COLOR_PALETTE_DEFAULT0;
2620 if (scaled_font->base.options.palette_index < palette_data.num_palettes)
2621 palette_index = scaled_font->base.options.palette_index;
2622
2623 if (FT_Palette_Select (face, palette_index, &entries) == 0) {
2624 num_entries = palette_data.num_palette_entries;
2625
2626 /* Overlay custom colors */
2627 for (unsigned int i = 0; i < scaled_font->base.options.custom_palette_size; i++) {
2628 cairo_palette_color_t *entry = &scaled_font->base.options.custom_palette[i];
2629 if (entry->index < num_entries) {
2630 entries[entry->index].red = 255 * entry->red;
2631 entries[entry->index].green = 255 * entry->green;
2632 entries[entry->index].blue = 255 * entry->blue;
2633 entries[entry->index].alpha = 255 * entry->alpha;
2634 }
2635 }
2636 }
2637 }
2638
2639 if (num_entries_ret)
2640 *num_entries_ret = num_entries;
2641
2642 if (entries_ret)
2643 *entries_ret = entries;
2644}
2645#else
2646static void
2647_cairo_ft_scaled_glyph_set_palette (cairo_ft_scaled_font_t *scaled_font,
2648 FT_Face face,
2649 unsigned int *num_entries_ret,
2650 void **entries_ret)
2651{
2652 if (num_entries_ret)
2653 *num_entries_ret = 0;
2654
2655 if (entries_ret)
2656 *entries_ret = NULL((void*)0);
2657}
2658#endif
2659
2660/* returns TRUE if foreground color used */
2661static cairo_bool_t
2662_cairo_ft_scaled_glyph_set_foreground_color (cairo_ft_scaled_font_t *scaled_font,
2663 cairo_scaled_glyph_t *scaled_glyph,
2664 FT_Face face,
2665 const cairo_color_t *foreground_color)
2666{
2667 cairo_bool_t uses_foreground_color = FALSE0;
2668#ifdef FT_COLOR_H<freetype/ftcolor.h>
2669 FT_LayerIterator iterator;
2670 FT_UInt layer_glyph_index;
2671 FT_UInt layer_color_index;
2672 FT_Color color;
2673
2674 /* Check if there is a layer that uses the foreground color */
2675 iterator.p = NULL((void*)0);
2676 while (FT_Get_Color_Glyph_Layer(face,
2677 _cairo_scaled_glyph_index (scaled_glyph)((unsigned long)((scaled_glyph)->hash_entry.hash & 0xffffff
))
,
2678 &layer_glyph_index,
2679 &layer_color_index,
2680 &iterator)) {
2681 if (layer_color_index == 0xFFFF) {
2682 uses_foreground_color = TRUE1;
2683 break;
2684 }
2685 }
2686
2687 if (uses_foreground_color) {
2688 color.red = (FT_Byte)(foreground_color->red * 0xFF);
2689 color.green = (FT_Byte)(foreground_color->green * 0xFF);
2690 color.blue = (FT_Byte)(foreground_color->blue * 0xFF);
2691 color.alpha = (FT_Byte)(foreground_color->alpha * 0xFF);
2692 FT_Palette_Set_Foreground_Color (face, color);
2693 }
2694#endif
2695 return uses_foreground_color;
2696}
2697
2698static cairo_int_status_t
2699_cairo_ft_scaled_glyph_init_surface (cairo_ft_scaled_font_t *scaled_font,
2700 cairo_scaled_glyph_t *scaled_glyph,
2701 cairo_ft_glyph_private_t *glyph_priv,
2702 cairo_scaled_glyph_info_t info,
2703 FT_Face face,
2704 const cairo_color_t *foreground_color,
2705 cairo_bool_t vertical_layout,
2706 int load_flags)
2707{
2708 cairo_ft_unscaled_font_t *unscaled = scaled_font->unscaled;
2709 FT_GlyphSlot glyph;
2710 cairo_status_t status;
2711 cairo_image_surface_t *surface;
2712 cairo_bool_t uses_foreground_color = FALSE0;
2713
2714 /* Only one info type at a time handled in this function */
2715 assert (info == CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE || info == CAIRO_SCALED_GLYPH_INFO_SURFACE)((void) sizeof (__assert_single_arg (info == CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE
|| info == CAIRO_SCALED_GLYPH_INFO_SURFACE)), __extension__ (
{ if (info == CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE || info ==
CAIRO_SCALED_GLYPH_INFO_SURFACE) ; else __assert_fail ("info == CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE || info == CAIRO_SCALED_GLYPH_INFO_SURFACE"
, "/root/firefox-clang/gfx/cairo/cairo/src/cairo-ft-font.c", 2715
, __extension__ __PRETTY_FUNCTION__); }))
;
2716
2717 if (info == CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE) {
2718 if (!unscaled->have_color) {
2719 scaled_glyph->color_glyph = FALSE0;
2720 scaled_glyph->color_glyph_set = TRUE1;
2721 return CAIRO_INT_STATUS_UNSUPPORTED;
2722 }
2723
2724 uses_foreground_color = _cairo_ft_scaled_glyph_set_foreground_color (scaled_font,
2725 scaled_glyph,
2726 face,
2727 foreground_color);
2728 _cairo_ft_scaled_glyph_set_palette (scaled_font, face, NULL((void*)0), NULL((void*)0));
2729
2730 load_flags &= ~FT_LOAD_MONOCHROME( 1L << 12 );
2731 /* clear load target mode */
2732 load_flags &= ~(FT_LOAD_TARGET_(FT_LOAD_TARGET_MODE(load_flags))( (FT_Int32)(((FT_Render_Mode)(( (load_flags) >> 16 ) &
15)) & 15) << 16 )
);
2733 load_flags |= FT_LOAD_TARGET_NORMAL( (FT_Int32)((FT_RENDER_MODE_NORMAL) & 15) << 16 );
2734 load_flags |= FT_LOAD_COLOR( 1L << 20 );
2735 } else { /* info == CAIRO_SCALED_GLYPH_INFO_SURFACE */
2736 load_flags &= ~FT_LOAD_COLOR( 1L << 20 );
2737 }
2738
2739 status = _cairo_ft_scaled_glyph_load_glyph (scaled_font,
2740 scaled_glyph,
2741 face,
2742 load_flags,
2743 FALSE0,
2744 vertical_layout);
2745 if (unlikely (status)(__builtin_expect (!!(status), 0)))
2746 return status;
2747
2748 glyph = face->glyph;
2749
2750 if (glyph_priv->format == CAIRO_FT_GLYPH_TYPE_OUTLINE) {
2751
2752 status = _render_glyph_outline (face, &scaled_font->ft_options.base,
2753 &surface);
2754 } else {
2755 status = _render_glyph_bitmap (face, &scaled_font->ft_options.base,
2756 &surface);
2757 if (likely (status == CAIRO_STATUS_SUCCESS)(__builtin_expect (!!(status == CAIRO_STATUS_SUCCESS), 1)) && unscaled->have_shape) {
2758 status = _transform_glyph_bitmap (&unscaled->current_shape,
2759 &surface);
2760 if (unlikely (status)(__builtin_expect (!!(status), 0)))
2761 cairo_surface_destroy_moz_cairo_surface_destroy (&surface->base);
2762 }
2763 }
2764
2765 if (unlikely (status)(__builtin_expect (!!(status), 0)))
2766 return status;
2767
2768 if (info == CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE) {
2769 /* We tried loading a color glyph and can now check if we got
2770 * a color glyph and set scaled_glyph->color_glyph
2771 * accordingly */
2772 if (pixman_image_get_format_moz_pixman_image_get_format (surface->pixman_image) == PIXMAN_a8r8g8b8 &&
2773 !pixman_image_get_component_alpha_moz_pixman_image_get_component_alpha (surface->pixman_image))
2774 {
2775 _cairo_scaled_glyph_set_color_surface (scaled_glyph,
2776 &scaled_font->base,
2777 surface,
2778 uses_foreground_color ? foreground_color : NULL((void*)0));
2779
2780 scaled_glyph->color_glyph = TRUE1;
2781 } else {
2782 /* We didn't ask for a non-color surface, but store it
2783 * anyway so we don't have to load it again. */
2784 _cairo_scaled_glyph_set_surface (scaled_glyph,
2785 &scaled_font->base,
2786 surface);
2787 scaled_glyph->color_glyph = FALSE0;
2788 status = CAIRO_INT_STATUS_UNSUPPORTED;
2789 }
2790 scaled_glyph->color_glyph_set = TRUE1;
2791 } else { /* info == CAIRO_SCALED_GLYPH_INFO_SURFACE */
2792 _cairo_scaled_glyph_set_surface (scaled_glyph,
2793 &scaled_font->base,
2794 surface);
2795 }
2796
2797 return status;
2798}
2799
2800static cairo_int_status_t
2801_cairo_ft_scaled_glyph_init_record_colr_v0_glyph (cairo_ft_scaled_font_t *scaled_font,
2802 cairo_scaled_glyph_t *scaled_glyph,
2803 FT_Face face,
2804 cairo_bool_t vertical_layout,
2805 int load_flags)
2806{
2807#ifdef FT_COLOR_H<freetype/ftcolor.h>
2808 cairo_surface_t *recording_surface;
2809 cairo_t *cr;
2810 cairo_status_t status;
2811 FT_Color *palette;
2812 unsigned int num_palette_entries;
2813 FT_LayerIterator iterator;
2814 FT_UInt layer_glyph_index;
2815 FT_UInt layer_color_index;
2816 cairo_path_fixed_t *path_fixed;
2817 cairo_path_t *path;
2818
2819 _cairo_ft_scaled_glyph_set_palette (scaled_font, face, &num_palette_entries, &palette);
2820
2821 load_flags &= ~FT_LOAD_MONOCHROME( 1L << 12 );
2822 /* clear load target mode */
2823 load_flags &= ~(FT_LOAD_TARGET_(FT_LOAD_TARGET_MODE(load_flags))( (FT_Int32)(((FT_Render_Mode)(( (load_flags) >> 16 ) &
15)) & 15) << 16 )
);
2824 load_flags |= FT_LOAD_TARGET_NORMAL( (FT_Int32)((FT_RENDER_MODE_NORMAL) & 15) << 16 );
2825 load_flags |= FT_LOAD_COLOR( 1L << 20 );
2826
2827 recording_surface =
2828 cairo_recording_surface_create_moz_cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, NULL((void*)0));
2829
2830 cr = cairo_create_moz_cairo_create (recording_surface);
2831
2832 if (!_cairo_matrix_is_scale_0 (&scaled_font->base.scale)) {
2833 cairo_matrix_t scale;
2834 scale = scaled_font->base.scale;
2835 scale.x0 = scale.y0 = 0.;
2836 cairo_set_matrix_moz_cairo_set_matrix (cr, &scale);
2837 }
2838
2839 iterator.p = NULL((void*)0);
2840 while (FT_Get_Color_Glyph_Layer(face,
2841 _cairo_scaled_glyph_index (scaled_glyph)((unsigned long)((scaled_glyph)->hash_entry.hash & 0xffffff
))
,
2842 &layer_glyph_index,
2843 &layer_color_index,
2844 &iterator))
2845 {
2846 cairo_pattern_t *pattern;
2847 if (layer_color_index == 0xFFFF) {
2848 pattern = _cairo_pattern_create_foreground_marker ();
2849 } else {
2850 double r = 0, g = 0, b = 0, a = 1;
2851 if (layer_color_index < num_palette_entries) {
2852 FT_Color *color = &palette[layer_color_index];
2853 r = color->red / 255.0;
2854 g = color->green/ 255.0;
2855 b = color->blue / 255.0;
2856 a = color->alpha / 255.0;
2857 }
2858 pattern = cairo_pattern_create_rgba_moz_cairo_pattern_create_rgba (r, g, b, a);
2859 }
2860 cairo_set_source_moz_cairo_set_source (cr, pattern);
2861 cairo_pattern_destroy_moz_cairo_pattern_destroy (pattern);
2862
2863 if (FT_Load_Glyph (face, layer_glyph_index, load_flags) != 0) {
2864 status = CAIRO_INT_STATUS_UNSUPPORTED;
2865 goto cleanup;
2866 }
2867
2868 status = _cairo_ft_face_decompose_glyph_outline (face, &path_fixed);
2869 if (unlikely (status)(__builtin_expect (!!(status), 0)))
2870 return status;
2871
2872 path = _cairo_path_create (path_fixed, cr);
2873 _cairo_path_fixed_destroy (path_fixed);
2874 cairo_append_path_moz_cairo_append_path(cr, path);
2875 cairo_path_destroy_moz_cairo_path_destroy (path);
2876 cairo_fill_moz_cairo_fill (cr);
2877 }
2878
2879 cleanup:
2880 cairo_destroy_moz_cairo_destroy (cr);
2881
2882 if (status) {
2883 cairo_surface_destroy_moz_cairo_surface_destroy (recording_surface);
2884 return status;
2885 }
2886
2887 _cairo_scaled_glyph_set_recording_surface (scaled_glyph,
2888 &scaled_font->base,
2889 recording_surface,
2890 NULL((void*)0));
2891 return status;
2892#else
2893 return CAIRO_INT_STATUS_UNSUPPORTED;
2894#endif
2895}
2896
2897static cairo_int_status_t
2898_cairo_ft_scaled_glyph_init_record_colr_v1_glyph (cairo_ft_scaled_font_t *scaled_font,
2899 cairo_scaled_glyph_t *scaled_glyph,
2900 FT_Face face,
2901 const cairo_color_t *foreground_color,
2902 cairo_text_extents_t *extents)
2903{
2904#if HAVE_FT_COLR_V1
2905 cairo_status_t status = CAIRO_STATUS_SUCCESS;
2906 cairo_surface_t *recording_surface;
2907 cairo_t *cr;
2908 FT_Color *palette;
2909 unsigned int num_palette_entries;
2910 cairo_bool_t foreground_source_used = FALSE0;
2911
2912 recording_surface =
2913 cairo_recording_surface_create_moz_cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, NULL((void*)0));
2914
2915 cairo_surface_set_device_scale (recording_surface, 1, -1);
2916
2917 cr = cairo_create_moz_cairo_create (recording_surface);
2918
2919 cairo_set_font_size_moz_cairo_set_font_size (cr, 1.0);
2920 cairo_set_font_options_moz_cairo_set_font_options (cr, &scaled_font->base.options);
2921
2922 extents->x_bearing = DOUBLE_FROM_26_6(face->bbox.xMin)((double)(face->bbox.xMin) / 64.0);
2923 extents->y_bearing = DOUBLE_FROM_26_6(face->bbox.yMin)((double)(face->bbox.yMin) / 64.0);
2924 extents->width = DOUBLE_FROM_26_6(face->bbox.xMax)((double)(face->bbox.xMax) / 64.0) - extents->x_bearing;
2925 extents->height = DOUBLE_FROM_26_6(face->bbox.yMax)((double)(face->bbox.yMax) / 64.0) - extents->y_bearing;
2926
2927 _cairo_ft_scaled_glyph_set_palette (scaled_font, face, &num_palette_entries, &palette);
2928
2929 if (!_cairo_matrix_is_scale_0 (&scaled_font->base.scale)) {
2930 cairo_pattern_t *foreground_pattern = _cairo_pattern_create_solid (foreground_color);
2931 status = _cairo_render_colr_v1_glyph (face,
2932 _cairo_scaled_glyph_index (scaled_glyph)((unsigned long)((scaled_glyph)->hash_entry.hash & 0xffffff
))
,
2933 palette,
2934 num_palette_entries,
2935 cr,
2936 foreground_pattern,
2937 &foreground_source_used);
2938 cairo_pattern_destroy_moz_cairo_pattern_destroy (foreground_pattern);
2939 if (status == CAIRO_STATUS_SUCCESS)
2940 status = cairo_status_moz_cairo_status (cr);
2941 }
2942
2943 cairo_destroy_moz_cairo_destroy (cr);
2944
2945 if (status) {
2946 cairo_surface_destroy_moz_cairo_surface_destroy (recording_surface);
2947 scaled_glyph->color_glyph = FALSE0;
2948 scaled_glyph->color_glyph_set = TRUE1;
2949 return status;
2950 }
2951
2952 _cairo_scaled_glyph_set_recording_surface (scaled_glyph,
2953 &scaled_font->base,
2954 recording_surface,
2955 foreground_source_used ? foreground_color : NULL((void*)0));
2956
2957 scaled_glyph->color_glyph = TRUE1;
2958 scaled_glyph->color_glyph_set = TRUE1;
2959
2960 /* get metrics */
2961
2962 /* Copied from cairo-user-font.c */
2963 cairo_matrix_t extent_scale;
2964 double extent_x_scale = 1.0;
2965 double extent_y_scale = 1.0;
2966 double snap_x_scale;
2967 double snap_y_scale;
2968 double fixed_scale, x_scale, y_scale;
2969
2970 extent_scale = scaled_font->base.scale_inverse;
2971 snap_x_scale = 1.0;
2972 snap_y_scale = 1.0;
2973 status = _cairo_matrix_compute_basis_scale_factors (&extent_scale,
2974 &x_scale, &y_scale,
2975 1);
2976 if (status == CAIRO_STATUS_SUCCESS) {
2977 if (x_scale == 0)
2978 x_scale = 1;
2979 if (y_scale == 0)
2980 y_scale = 1;
2981
2982 snap_x_scale = x_scale;
2983 snap_y_scale = y_scale;
2984
2985 /* since glyphs are pretty much 1.0x1.0, we can reduce error by
2986 * scaling to a larger square. say, 1024.x1024. */
2987 fixed_scale = 1024;
2988 x_scale /= fixed_scale;
2989 y_scale /= fixed_scale;
2990
2991 cairo_matrix_scale_moz_cairo_matrix_scale (&extent_scale, 1.0 / x_scale, 1.0 / y_scale);
2992
2993 extent_x_scale = x_scale;
2994 extent_y_scale = y_scale;
2995 }
2996
2997 {
2998 /* compute width / height */
2999 cairo_box_t bbox;
3000 double x1, y1, x2, y2;
3001 double x_scale, y_scale;
3002
3003 /* Compute extents.x/y/width/height from recording_surface,
3004 * in font space.
3005 */
3006 status = _cairo_recording_surface_get_bbox ((cairo_recording_surface_t *) recording_surface,
3007 &bbox,
3008 &extent_scale);
3009 if (unlikely (status)(__builtin_expect (!!(status), 0)))
3010 return status;
3011
3012 _cairo_box_to_doubles (&bbox, &x1, &y1, &x2, &y2);
3013
3014 x_scale = extent_x_scale;
3015 y_scale = extent_y_scale;
3016 extents->x_bearing = x1 * x_scale;
3017 extents->y_bearing = y1 * y_scale;
3018 extents->width = (x2 - x1) * x_scale;
3019 extents->height = (y2 - y1) * y_scale;
3020 }
3021
3022 if (scaled_font->base.options.hint_metrics != CAIRO_HINT_METRICS_OFF) {
3023 extents->x_advance = _cairo_lround (extents->x_advance / snap_x_scale) * snap_x_scale;
3024 extents->y_advance = _cairo_lround (extents->y_advance / snap_y_scale) * snap_y_scale;
3025 }
3026
3027 return status;
3028#else
3029 return CAIRO_INT_STATUS_UNSUPPORTED;
3030#endif
3031}
3032
3033static cairo_int_status_t
3034_cairo_ft_scaled_glyph_init_record_svg_glyph (cairo_ft_scaled_font_t *scaled_font,
3035 cairo_scaled_glyph_t *scaled_glyph,
3036 FT_Face face,
3037 const cairo_color_t *foreground_color,
3038 cairo_text_extents_t *extents)
3039{
3040#if HAVE_FT_SVG_DOCUMENT
3041 cairo_status_t status = CAIRO_STATUS_SUCCESS;
3042 cairo_surface_t *recording_surface;
3043 cairo_t *cr;
3044 FT_SVG_Document svg_doc = face->glyph->other;
3045 char *svg_document;
3046 FT_Color *palette;
3047 unsigned int num_palette_entries;
3048 cairo_bool_t foreground_source_used = FALSE0;
3049
3050 /* Create NULL terminated SVG document */
3051 svg_document = _cairo_strndupstrndup ((const char*)svg_doc->svg_document, svg_doc->svg_document_length);
3052
3053 recording_surface =
3054 cairo_recording_surface_create_moz_cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, NULL((void*)0));
3055
3056 cr = cairo_create_moz_cairo_create (recording_surface);
3057
3058 if (!_cairo_matrix_is_scale_0 (&scaled_font->base.scale)) {
3059 cairo_matrix_t scale;
3060 scale = scaled_font->base.scale;
3061 scale.x0 = scale.y0 = 0.;
3062 cairo_set_matrix_moz_cairo_set_matrix (cr, &scale);
3063 }
3064
3065 cairo_set_font_size_moz_cairo_set_font_size (cr, 1.0);
3066 cairo_set_font_options_moz_cairo_set_font_options (cr, &scaled_font->base.options);
3067
3068 extents->x_bearing = DOUBLE_FROM_26_6(face->bbox.xMin)((double)(face->bbox.xMin) / 64.0);
3069 extents->y_bearing = DOUBLE_FROM_26_6(face->bbox.yMin)((double)(face->bbox.yMin) / 64.0);
3070 extents->width = DOUBLE_FROM_26_6(face->bbox.xMax)((double)(face->bbox.xMax) / 64.0) - extents->x_bearing;
3071 extents->height = DOUBLE_FROM_26_6(face->bbox.yMax)((double)(face->bbox.yMax) / 64.0) - extents->y_bearing;
3072
3073 _cairo_ft_scaled_glyph_set_palette (scaled_font, face, &num_palette_entries, &palette);
3074
3075 if (!_cairo_matrix_is_scale_0 (&scaled_font->base.scale)) {
3076 cairo_pattern_t *foreground_pattern = _cairo_pattern_create_solid (foreground_color);
3077 status = _cairo_render_svg_glyph (svg_document,
3078 svg_doc->start_glyph_id,
3079 svg_doc->end_glyph_id,
3080 _cairo_scaled_glyph_index(scaled_glyph)((unsigned long)((scaled_glyph)->hash_entry.hash & 0xffffff
))
,
3081 svg_doc->units_per_EM,
3082 palette,
3083 num_palette_entries,
3084 cr,
3085 foreground_pattern,
3086 &foreground_source_used);
3087 cairo_pattern_destroy_moz_cairo_pattern_destroy (foreground_pattern);
3088 if (status == CAIRO_STATUS_SUCCESS)
3089 status = cairo_status_moz_cairo_status (cr);
3090 }
3091
3092 cairo_destroy_moz_cairo_destroy (cr);
3093 free (svg_document);
3094
3095 if (status) {
3096 cairo_surface_destroy_moz_cairo_surface_destroy (recording_surface);
3097 scaled_glyph->color_glyph = FALSE0;
3098 scaled_glyph->color_glyph_set = TRUE1;
3099 return status;
3100 }
3101
3102 _cairo_scaled_glyph_set_recording_surface (scaled_glyph,
3103 &scaled_font->base,
3104 recording_surface,
3105 foreground_source_used ? foreground_color : NULL((void*)0));
3106
3107 scaled_glyph->color_glyph = TRUE1;
3108 scaled_glyph->color_glyph_set = TRUE1;
3109
3110 /* get metrics */
3111
3112 /* Copied from cairo-user-font.c */
3113 cairo_matrix_t extent_scale;
3114 double extent_x_scale;
3115 double extent_y_scale;
3116 double snap_x_scale;
3117 double snap_y_scale;
3118 double fixed_scale, x_scale, y_scale;
3119
3120 extent_scale = scaled_font->base.scale_inverse;
3121 snap_x_scale = 1.0;
3122 snap_y_scale = 1.0;
3123 status = _cairo_matrix_compute_basis_scale_factors (&extent_scale,
3124 &x_scale, &y_scale,
3125 1);
3126 if (status == CAIRO_STATUS_SUCCESS) {
3127 if (x_scale == 0)
3128 x_scale = 1;
3129 if (y_scale == 0)
3130 y_scale = 1;
3131
3132 snap_x_scale = x_scale;
3133 snap_y_scale = y_scale;
3134
3135 /* since glyphs are pretty much 1.0x1.0, we can reduce error by
3136 * scaling to a larger square. say, 1024.x1024. */
3137 fixed_scale = 1024;
3138 x_scale /= fixed_scale;
3139 y_scale /= fixed_scale;
3140
3141 cairo_matrix_scale_moz_cairo_matrix_scale (&extent_scale, 1.0 / x_scale, 1.0 / y_scale);
3142
3143 extent_x_scale = x_scale;
3144 extent_y_scale = y_scale;
3145 }
3146
3147 {
3148 /* compute width / height */
3149 cairo_box_t bbox;
3150 double x1, y1, x2, y2;
3151 double x_scale, y_scale;
3152
3153 /* Compute extents.x/y/width/height from recording_surface,
3154 * in font space.
3155 */
3156 status = _cairo_recording_surface_get_bbox ((cairo_recording_surface_t *) recording_surface,
3157 &bbox,
3158 &extent_scale);
3159 if (unlikely (status)(__builtin_expect (!!(status), 0)))
3160 return status;
3161
3162 _cairo_box_to_doubles (&bbox, &x1, &y1, &x2, &y2);
3163
3164 x_scale = extent_x_scale;
3165 y_scale = extent_y_scale;
3166 extents->x_bearing = x1 * x_scale;
3167 extents->y_bearing = y1 * y_scale;
3168 extents->width = (x2 - x1) * x_scale;
3169 extents->height = (y2 - y1) * y_scale;
3170 }
3171
3172 if (scaled_font->base.options.hint_metrics != CAIRO_HINT_METRICS_OFF) {
3173 extents->x_advance = _cairo_lround (extents->x_advance / snap_x_scale) * snap_x_scale;
3174 extents->y_advance = _cairo_lround (extents->y_advance / snap_y_scale) * snap_y_scale;
3175 }
3176
3177 return status;
3178#else
3179 return CAIRO_INT_STATUS_UNSUPPORTED;
3180#endif
3181}
3182
3183static cairo_int_status_t
3184_cairo_ft_scaled_glyph_init_surface_for_recording_surface (cairo_ft_scaled_font_t *scaled_font,
3185 cairo_scaled_glyph_t *scaled_glyph,
3186 const cairo_color_t *foreground_color)
3187{
3188 cairo_surface_t *surface;
3189 int width, height;
3190 cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
3191 cairo_bool_t foreground_used;
3192
3193 width = _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.x) -
3194 _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x);
3195 height = _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.y) -
3196 _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y);
3197
3198 surface = cairo_image_surface_create_moz_cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
3199
3200 cairo_surface_set_device_offset_moz_cairo_surface_set_device_offset (surface,
3201 - _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x),
3202 - _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y));
3203
3204 status = _cairo_recording_surface_replay_with_foreground_color (scaled_glyph->recording_surface,
3205 surface,
3206 foreground_color,
3207 &foreground_used);
3208 if (unlikely (status)(__builtin_expect (!!(status), 0))) {
3209 cairo_surface_destroy_moz_cairo_surface_destroy(surface);
3210 return status;
3211 }
3212
3213 _cairo_scaled_glyph_set_color_surface (scaled_glyph,
3214 &scaled_font->base,
3215 (cairo_image_surface_t *)surface,
3216 foreground_used ? foreground_color : NULL((void*)0));
3217 surface = NULL((void*)0);
3218
3219 if (surface)
3220 cairo_surface_destroy_moz_cairo_surface_destroy (surface);
3221
3222 return status;
3223}
3224
3225static void
3226_cairo_ft_scaled_glyph_get_metrics (cairo_ft_scaled_font_t *scaled_font,
3227 FT_Face face,
3228 cairo_bool_t vertical_layout,
3229 int load_flags,
3230 cairo_text_extents_t *fs_metrics)
3231{
3232 FT_Glyph_Metrics *metrics;
3233 cairo_ft_unscaled_font_t *unscaled = scaled_font->unscaled;
3234 cairo_bool_t hint_metrics = scaled_font->base.options.hint_metrics != CAIRO_HINT_METRICS_OFF;
3235 FT_GlyphSlot glyph = face->glyph;
3236
3237 /*
3238 * Compute font-space metrics
3239 */
3240 metrics = &glyph->metrics;
3241
3242 /*
3243 * Note: Y coordinates of the horizontal bearing need to be negated.
3244 *
3245 * Scale metrics back to glyph space from the scaled glyph space returned
3246 * by FreeType
3247 *
3248 * If we want hinted metrics but aren't asking for hinted glyphs from
3249 * FreeType, then we need to do the metric hinting ourselves.
3250 */
3251
3252 if (hint_metrics && (load_flags & FT_LOAD_NO_HINTING( 1L << 1 )))
3253 {
3254 FT_Pos x1, x2;
3255 FT_Pos y1, y2;
3256 FT_Pos advance;
3257
3258 if (!vertical_layout) {
3259 x1 = (metrics->horiBearingX) & -64;
3260 x2 = (metrics->horiBearingX + metrics->width + 63) & -64;
3261 y1 = (-metrics->horiBearingY) & -64;
3262 y2 = (-metrics->horiBearingY + metrics->height + 63) & -64;
3263
3264 advance = ((metrics->horiAdvance + 32) & -64);
3265
3266 fs_metrics->x_bearing = SCALE (DOUBLE_FROM_26_6 (x1), unscaled->x_scale)((unscaled->x_scale) == 0 ? 0.0 : (((double)(x1) / 64.0)) /
(unscaled->x_scale))
;
3267 fs_metrics->y_bearing = SCALE (DOUBLE_FROM_26_6 (y1), unscaled->y_scale)((unscaled->y_scale) == 0 ? 0.0 : (((double)(y1) / 64.0)) /
(unscaled->y_scale))
;
3268
3269 fs_metrics->width = SCALE (DOUBLE_FROM_26_6 (x2 - x1), unscaled->x_scale)((unscaled->x_scale) == 0 ? 0.0 : (((double)(x2 - x1) / 64.0
)) / (unscaled->x_scale))
;
3270 fs_metrics->height = SCALE (DOUBLE_FROM_26_6 (y2 - y1), unscaled->y_scale)((unscaled->y_scale) == 0 ? 0.0 : (((double)(y2 - y1) / 64.0
)) / (unscaled->y_scale))
;
3271
3272 fs_metrics->x_advance = SCALE (DOUBLE_FROM_26_6 (advance), unscaled->x_scale)((unscaled->x_scale) == 0 ? 0.0 : (((double)(advance) / 64.0
)) / (unscaled->x_scale))
;
3273 fs_metrics->y_advance = 0;
3274 } else {
3275 x1 = (metrics->vertBearingX) & -64;
3276 x2 = (metrics->vertBearingX + metrics->width + 63) & -64;
3277 y1 = (metrics->vertBearingY) & -64;
3278 y2 = (metrics->vertBearingY + metrics->height + 63) & -64;
3279
3280 advance = ((metrics->vertAdvance + 32) & -64);
3281
3282 fs_metrics->x_bearing = SCALE (DOUBLE_FROM_26_6 (x1), unscaled->x_scale)((unscaled->x_scale) == 0 ? 0.0 : (((double)(x1) / 64.0)) /
(unscaled->x_scale))
;
3283 fs_metrics->y_bearing = SCALE (DOUBLE_FROM_26_6 (y1), unscaled->y_scale)((unscaled->y_scale) == 0 ? 0.0 : (((double)(y1) / 64.0)) /
(unscaled->y_scale))
;
3284
3285 fs_metrics->width = SCALE (DOUBLE_FROM_26_6 (x2 - x1), unscaled->x_scale)((unscaled->x_scale) == 0 ? 0.0 : (((double)(x2 - x1) / 64.0
)) / (unscaled->x_scale))
;
3286 fs_metrics->height = SCALE (DOUBLE_FROM_26_6 (y2 - y1), unscaled->y_scale)((unscaled->y_scale) == 0 ? 0.0 : (((double)(y2 - y1) / 64.0
)) / (unscaled->y_scale))
;
3287
3288 fs_metrics->x_advance = 0;
3289 fs_metrics->y_advance = SCALE (DOUBLE_FROM_26_6 (advance), unscaled->y_scale)((unscaled->y_scale) == 0 ? 0.0 : (((double)(advance) / 64.0
)) / (unscaled->y_scale))
;
3290 }
3291 } else {
3292 fs_metrics->width = SCALE (DOUBLE_FROM_26_6 (metrics->width), unscaled->x_scale)((unscaled->x_scale) == 0 ? 0.0 : (((double)(metrics->width
) / 64.0)) / (unscaled->x_scale))
;
3293 fs_metrics->height = SCALE (DOUBLE_FROM_26_6 (metrics->height), unscaled->y_scale)((unscaled->y_scale) == 0 ? 0.0 : (((double)(metrics->height
) / 64.0)) / (unscaled->y_scale))
;
3294
3295 if (!vertical_layout) {
3296 fs_metrics->x_bearing = SCALE (DOUBLE_FROM_26_6 (metrics->horiBearingX), unscaled->x_scale)((unscaled->x_scale) == 0 ? 0.0 : (((double)(metrics->horiBearingX
) / 64.0)) / (unscaled->x_scale))
;
3297 fs_metrics->y_bearing = SCALE (DOUBLE_FROM_26_6 (-metrics->horiBearingY), unscaled->y_scale)((unscaled->y_scale) == 0 ? 0.0 : (((double)(-metrics->
horiBearingY) / 64.0)) / (unscaled->y_scale))
;
3298
3299 if (hint_metrics || glyph->format != FT_GLYPH_FORMAT_OUTLINE)
3300 fs_metrics->x_advance = SCALE (DOUBLE_FROM_26_6 (metrics->horiAdvance), unscaled->x_scale)((unscaled->x_scale) == 0 ? 0.0 : (((double)(metrics->horiAdvance
) / 64.0)) / (unscaled->x_scale))
;
3301 else
3302 fs_metrics->x_advance = SCALE (DOUBLE_FROM_16_16 (glyph->linearHoriAdvance), unscaled->x_scale)((unscaled->x_scale) == 0 ? 0.0 : (((double)(glyph->linearHoriAdvance
) / 65536.0)) / (unscaled->x_scale))
;
3303 fs_metrics->y_advance = 0;
3304 } else {
3305 fs_metrics->x_bearing = SCALE (DOUBLE_FROM_26_6 (metrics->vertBearingX), unscaled->x_scale)((unscaled->x_scale) == 0 ? 0.0 : (((double)(metrics->vertBearingX
) / 64.0)) / (unscaled->x_scale))
;
3306 fs_metrics->y_bearing = SCALE (DOUBLE_FROM_26_6 (metrics->vertBearingY), unscaled->y_scale)((unscaled->y_scale) == 0 ? 0.0 : (((double)(metrics->vertBearingY
) / 64.0)) / (unscaled->y_scale))
;
3307
3308 fs_metrics->x_advance = 0;
3309 if (hint_metrics || glyph->format != FT_GLYPH_FORMAT_OUTLINE)
3310 fs_metrics->y_advance = SCALE (DOUBLE_FROM_26_6 (metrics->vertAdvance), unscaled->y_scale)((unscaled->y_scale) == 0 ? 0.0 : (((double)(metrics->vertAdvance
) / 64.0)) / (unscaled->y_scale))
;
3311 else
3312 fs_metrics->y_advance = SCALE (DOUBLE_FROM_16_16 (glyph->linearVertAdvance), unscaled->y_scale)((unscaled->y_scale) == 0 ? 0.0 : (((double)(glyph->linearVertAdvance
) / 65536.0)) / (unscaled->y_scale))
;
3313 }
3314 }
3315}
3316
3317static cairo_bool_t
3318_cairo_ft_scaled_glyph_is_colr_v0 (cairo_ft_scaled_font_t *scaled_font,
3319 cairo_scaled_glyph_t *scaled_glyph,
3320 FT_Face face)
3321{
3322#ifdef FT_COLOR_H<freetype/ftcolor.h>
3323 FT_LayerIterator iterator;
3324 FT_UInt layer_glyph_index;
3325 FT_UInt layer_color_index;
3326
3327 iterator.p = NULL((void*)0);
3328 if (FT_Get_Color_Glyph_Layer(face,
3329 _cairo_scaled_glyph_index (scaled_glyph)((unsigned long)((scaled_glyph)->hash_entry.hash & 0xffffff
))
,
3330 &layer_glyph_index,
3331 &layer_color_index,
3332 &iterator) == 1)
3333 {
3334 return TRUE1;
3335 }
3336#endif
3337 return FALSE0;
3338}
3339
3340static cairo_bool_t
3341_cairo_ft_scaled_glyph_is_colr_v1 (cairo_ft_scaled_font_t *scaled_font,
3342 cairo_scaled_glyph_t *scaled_glyph,
3343 FT_Face face)
3344{
3345#if HAVE_FT_COLR_V1
3346 FT_OpaquePaint paint = { NULL((void*)0), 0 };
3347
3348 if (FT_Get_Color_Glyph_Paint (face,
3349 _cairo_scaled_glyph_index (scaled_glyph)((unsigned long)((scaled_glyph)->hash_entry.hash & 0xffffff
))
,
3350 FT_COLOR_INCLUDE_ROOT_TRANSFORM,
3351 &paint) == 1)
3352 {
3353 return TRUE1;
3354 }
3355#endif
3356 return FALSE0;
3357}
3358
3359static cairo_int_status_t
3360_cairo_ft_scaled_glyph_init_metrics (cairo_ft_scaled_font_t *scaled_font,
3361 cairo_scaled_glyph_t *scaled_glyph,
3362 FT_Face face,
3363 cairo_bool_t vertical_layout,
3364 int load_flags,
3365 const cairo_color_t *foreground_color)
3366{
3367 cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
3368 cairo_text_extents_t fs_metrics;
3369 cairo_ft_glyph_private_t *glyph_priv;
3370
3371 cairo_bool_t hint_metrics = scaled_font->base.options.hint_metrics != CAIRO_HINT_METRICS_OFF;
3372
3373 /* _cairo_ft_scaled_glyph_init_metrics() is called once the first
3374 * time a cairo_scaled_glyph_t is created. We first allocate the
3375 * cairo_ft_glyph_private_t struct and determine the glyph type.
3376 */
3377
3378 glyph_priv = _cairo_calloc (sizeof (*glyph_priv))((sizeof (*glyph_priv)) != 0 ? calloc(1,sizeof (*glyph_priv))
: ((void*)0))
;
3379 if (unlikely (glyph_priv == NULL)(__builtin_expect (!!(glyph_priv == ((void*)0)), 0)))
3380 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
3381
3382 _cairo_scaled_glyph_attach_private (scaled_glyph, &glyph_priv->base,
3383 &ft_glyph_private_key,
3384 _cairo_ft_glyph_fini);
3385
3386 /* We need to load color to determine if this is a color format. */
3387 int color_flag = 0;
3388
3389 if (scaled_font->unscaled->have_color && scaled_font->base.options.color_mode != CAIRO_COLOR_MODE_NO_COLOR)
3390 color_flag = FT_LOAD_COLOR( 1L << 20 );
3391
3392 /* Ensure use_em_size = FALSE as the format (bitmap or outline)
3393 * may change with the size. */
3394 status = _cairo_ft_scaled_glyph_load_glyph (scaled_font,
3395 scaled_glyph,
3396 face,
3397 load_flags | color_flag,
3398 FALSE0,
3399 vertical_layout);
3400 if (unlikely (status)(__builtin_expect (!!(status), 0)))
3401 return status;
3402
3403 cairo_bool_t is_svg_format = FALSE0;
3404#if HAVE_FT_SVG_DOCUMENT
3405 if (face->glyph->format == FT_GLYPH_FORMAT_SVG)
3406 is_svg_format = TRUE1;
3407#endif
3408
3409 if (is_svg_format) {
3410 glyph_priv->format = CAIRO_FT_GLYPH_TYPE_SVG;
3411
3412#if defined(HAVE_FT_COLR_V1) && defined(HAVE_FT_LOAD_NO_SVG)
3413 /* Prefer COLRv1 table over SVG table due to performance reasons for now */
3414 if (_cairo_ft_scaled_glyph_is_colr_v1 (scaled_font, scaled_glyph, face)) {
3415 glyph_priv->format = CAIRO_FT_GLYPH_TYPE_COLR_V1;
3416 }
3417#endif
3418
3419 } else if (face->glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
3420 glyph_priv->format = CAIRO_FT_GLYPH_TYPE_OUTLINE;
3421 if (color_flag) {
3422 if (_cairo_ft_scaled_glyph_is_colr_v1 (scaled_font, scaled_glyph, face))
3423 glyph_priv->format = CAIRO_FT_GLYPH_TYPE_COLR_V1;
3424 else if (_cairo_ft_scaled_glyph_is_colr_v0 (scaled_font, scaled_glyph, face))
3425 glyph_priv->format = CAIRO_FT_GLYPH_TYPE_COLR_V0;
3426 }
3427 } else {
3428 /* For anything else we let FreeType render a bitmap. */
3429 glyph_priv->format = CAIRO_FT_GLYPH_TYPE_BITMAP;
3430 }
3431
3432 /* If hinting is off, load the glyph with font size set the the em size. */
3433 if (!hint_metrics) {
3434 status = _cairo_ft_scaled_glyph_load_glyph (scaled_font,
3435 scaled_glyph,
3436 face,
3437 load_flags | color_flag,
3438 TRUE1,
3439 vertical_layout);
3440 if (unlikely (status)(__builtin_expect (!!(status), 0)))
3441 return status;
3442 }
3443
3444 _cairo_ft_scaled_glyph_get_metrics (scaled_font,
3445 face,
3446 vertical_layout,
3447 load_flags,
3448 &fs_metrics);
3449
3450
3451 /* SVG and COLRv1 glyphs require the bounding box to be obtained
3452 * from the ink extents of the rendering. We need to render glyph
3453 * to a recording surface to obtain these extents. But we also
3454 * need the advance from _cairo_ft_scaled_glyph_get_metrics()
3455 * before calling this function.
3456 */
3457
3458 if (glyph_priv->format == CAIRO_FT_GLYPH_TYPE_SVG) {
3459 status = (cairo_int_status_t)_cairo_ft_scaled_glyph_init_record_svg_glyph (scaled_font,
3460 scaled_glyph,
3461 face,
3462 foreground_color,
3463 &fs_metrics);
3464 if (unlikely (status)(__builtin_expect (!!(status), 0)))
3465 return status;
3466 }
3467
3468 if (glyph_priv->format == CAIRO_FT_GLYPH_TYPE_COLR_V1) {
3469 /* Restore font size if previously loaded at em_size. */
3470 if (!hint_metrics) {
3471 status = _cairo_ft_scaled_glyph_load_glyph (scaled_font,
3472 scaled_glyph,
3473 face,
3474 load_flags | color_flag,
3475 FALSE0,
3476 vertical_layout);
3477 if (unlikely (status)(__builtin_expect (!!(status), 0)))
3478 return status;
3479 }
3480
3481 status = (cairo_int_status_t)_cairo_ft_scaled_glyph_init_record_colr_v1_glyph (scaled_font,
3482 scaled_glyph,
3483 face,
3484 foreground_color,
3485 &fs_metrics);
3486 if (unlikely (status)(__builtin_expect (!!(status), 0)))
3487 return status;
3488 }
3489
3490 _cairo_scaled_glyph_set_metrics (scaled_glyph,
3491 &scaled_font->base,
3492 &fs_metrics);
3493
3494 return status;
3495}
3496
3497static cairo_int_status_t
3498_cairo_ft_scaled_glyph_init (void *abstract_font,
3499 cairo_scaled_glyph_t *scaled_glyph,
3500 cairo_scaled_glyph_info_t info,
3501 const cairo_color_t *foreground_color)
3502{
3503 cairo_ft_scaled_font_t *scaled_font = abstract_font;
3504 cairo_ft_unscaled_font_t *unscaled = scaled_font->unscaled;
3505 FT_Face face;
3506 int load_flags = scaled_font->ft_options.load_flags;
3507 cairo_bool_t vertical_layout = FALSE0;
3508 cairo_status_t status = CAIRO_STATUS_SUCCESS;
3509 cairo_ft_glyph_private_t *glyph_priv;
3510
3511 face = _cairo_ft_unscaled_font_lock_face (unscaled);
3512 if (!face)
3513 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
3514
3515 /* Ignore global advance unconditionally */
3516 load_flags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH( 1L << 9 );
3517
3518 if ((info & CAIRO_SCALED_GLYPH_INFO_PATH) != 0 &&
3519 (info & (CAIRO_SCALED_GLYPH_INFO_SURFACE |
3520 CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE)) == 0) {
3521 load_flags |= FT_LOAD_NO_BITMAP( 1L << 3 );
3522 }
3523
3524 /*
3525 * Don't pass FT_LOAD_VERTICAL_LAYOUT to FT_Load_Glyph here as
3526 * suggested by freetype people.
3527 */
3528 if (load_flags & FT_LOAD_VERTICAL_LAYOUT( 1L << 4 )) {
3529 load_flags &= ~FT_LOAD_VERTICAL_LAYOUT( 1L << 4 );
3530 vertical_layout = TRUE1;
3531 }
3532
3533 /* Metrics will always be requested when a scaled glyph is created */
3534 if (info & CAIRO_SCALED_GLYPH_INFO_METRICS) {
3535 status = _cairo_ft_scaled_glyph_init_metrics (scaled_font,
3536 scaled_glyph,
3537 face,
3538 vertical_layout,
3539 load_flags,
3540 foreground_color);
3541 if (unlikely (status)(__builtin_expect (!!(status), 0)))
3542 goto FAIL;
3543 }
3544
3545 glyph_priv = (cairo_ft_glyph_private_t *) _cairo_scaled_glyph_find_private (scaled_glyph,
3546 &ft_glyph_private_key);
3547 assert (glyph_priv != NULL)((void) sizeof (__assert_single_arg (glyph_priv != ((void*)0)
)), __extension__ ({ if (glyph_priv != ((void*)0)) ; else __assert_fail
("glyph_priv != NULL", "/root/firefox-clang/gfx/cairo/cairo/src/cairo-ft-font.c"
, 3547, __extension__ __PRETTY_FUNCTION__); }))
;
3548
3549 if (info & CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE) {
3550 status = CAIRO_INT_STATUS_UNSUPPORTED;
3551 if (glyph_priv->format == CAIRO_FT_GLYPH_TYPE_SVG ||
3552 glyph_priv->format == CAIRO_FT_GLYPH_TYPE_COLR_V0 ||
3553 glyph_priv->format == CAIRO_FT_GLYPH_TYPE_COLR_V1)
3554 {
3555 status = _cairo_ft_scaled_glyph_load_glyph (scaled_font,
3556 scaled_glyph,
3557 face,
3558 load_flags | FT_LOAD_COLOR( 1L << 20 ),
3559 FALSE0,
3560 vertical_layout);
3561 if (unlikely (status)(__builtin_expect (!!(status), 0)))
3562 goto FAIL;
3563
3564 if (glyph_priv->format == CAIRO_FT_GLYPH_TYPE_SVG) {
3565 status = _cairo_ft_scaled_glyph_init_record_svg_glyph (scaled_font,
3566 scaled_glyph,
3567 face,
3568 foreground_color,
3569 &scaled_glyph->fs_metrics);
3570 } else if (glyph_priv->format == CAIRO_FT_GLYPH_TYPE_COLR_V1) {
3571 status = _cairo_ft_scaled_glyph_init_record_colr_v1_glyph (scaled_font,
3572 scaled_glyph,
3573 face,
3574 foreground_color,
3575 &scaled_glyph->fs_metrics);
3576 } else if (glyph_priv->format == CAIRO_FT_GLYPH_TYPE_COLR_V0) {
3577 status = _cairo_ft_scaled_glyph_init_record_colr_v0_glyph (scaled_font,
3578 scaled_glyph,
3579 face,
3580 vertical_layout,
3581 load_flags);
3582 }
3583 }
3584 if (status)
3585 goto FAIL;
3586 }
3587
3588 if ((info & CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE) && scaled_font->base.options.color_mode != CAIRO_COLOR_MODE_NO_COLOR) {
3589 if (glyph_priv->format == CAIRO_FT_GLYPH_TYPE_SVG ||
3590 glyph_priv->format == CAIRO_FT_GLYPH_TYPE_COLR_V1)
3591 {
3592 status = _cairo_ft_scaled_glyph_init_surface_for_recording_surface (scaled_font,
3593 scaled_glyph,
3594 foreground_color);
3595 } else {
3596 status = _cairo_ft_scaled_glyph_init_surface (scaled_font,
3597 scaled_glyph,
3598 glyph_priv,
3599 CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE,
3600 face,
3601 foreground_color,
3602 vertical_layout,
3603 load_flags);
3604 }
3605 if (unlikely (status)(__builtin_expect (!!(status), 0)))
3606 goto FAIL;
3607 }
3608
3609 if (info & CAIRO_SCALED_GLYPH_INFO_SURFACE) {
3610 status = _cairo_ft_scaled_glyph_init_surface (scaled_font,
3611 scaled_glyph,
3612 glyph_priv,
3613 CAIRO_SCALED_GLYPH_INFO_SURFACE,
3614 face,
3615 NULL((void*)0), /* foreground color */
3616 vertical_layout,
3617 load_flags);
3618 if (unlikely (status)(__builtin_expect (!!(status), 0)))
3619 goto FAIL;
3620 }
3621
3622 if (info & CAIRO_SCALED_GLYPH_INFO_PATH) {
3623 cairo_path_fixed_t *path = NULL((void*)0); /* hide compiler warning */
3624
3625 /* Load non-color glyph */
3626 status = _cairo_ft_scaled_glyph_load_glyph (scaled_font,
3627 scaled_glyph,
3628 face,
3629 load_flags,
3630 FALSE0,
3631 vertical_layout);
3632 if (unlikely (status)(__builtin_expect (!!(status), 0)))
3633 goto FAIL;
3634
3635 if (face->glyph->format == FT_GLYPH_FORMAT_OUTLINE)
3636 status = _cairo_ft_face_decompose_glyph_outline (face, &path);
3637 else
3638 status = CAIRO_INT_STATUS_UNSUPPORTED;
3639
3640 if (unlikely (status)(__builtin_expect (!!(status), 0)))
3641 goto FAIL;
3642
3643 _cairo_scaled_glyph_set_path (scaled_glyph,
3644 &scaled_font->base,
3645 path);
3646 }
3647 FAIL:
3648 _cairo_ft_unscaled_font_unlock_face (unscaled);
3649
3650 return status;
3651}
3652
3653static unsigned long
3654_cairo_ft_ucs4_to_index (void *abstract_font,
3655 uint32_t ucs4)
3656{
3657 cairo_ft_scaled_font_t *scaled_font = abstract_font;
3658 cairo_ft_unscaled_font_t *unscaled = scaled_font->unscaled;
3659 FT_Face face;
3660 FT_UInt index;
3661
3662 face = _cairo_ft_unscaled_font_lock_face (unscaled);
3663 if (!face)
3664 return 0;
3665
3666#if CAIRO_HAS_FC_FONT1
3667 index = FcFreeTypeCharIndex (face, ucs4);
3668#else
3669 index = FT_Get_Char_Index (face, ucs4);
3670#endif
3671
3672 _cairo_ft_unscaled_font_unlock_face (unscaled);
3673 return index;
3674}
3675
3676static cairo_int_status_t
3677_cairo_ft_load_truetype_table (void *abstract_font,
3678 unsigned long tag,
3679 long offset,
3680 unsigned char *buffer,
3681 unsigned long *length)
3682{
3683 cairo_ft_scaled_font_t *scaled_font = abstract_font;
3684 cairo_ft_unscaled_font_t *unscaled = scaled_font->unscaled;
3685 FT_Face face;
3686 cairo_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
3687
3688 /* We don't support the FreeType feature of loading a table
3689 * without specifying the size since this may overflow our
3690 * buffer. */
3691 assert (length != NULL)((void) sizeof (__assert_single_arg (length != ((void*)0))), __extension__
({ if (length != ((void*)0)) ; else __assert_fail ("length != NULL"
, "/root/firefox-clang/gfx/cairo/cairo/src/cairo-ft-font.c", 3691
, __extension__ __PRETTY_FUNCTION__); }))
;
3692
3693 if (_cairo_ft_scaled_font_is_vertical (&scaled_font->base))
3694 return CAIRO_INT_STATUS_UNSUPPORTED;
3695
3696 face = _cairo_ft_unscaled_font_lock_face (unscaled);
3697 if (!face)
3698 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
3699
3700 if (FT_IS_SFNT (face)( !!( (face)->face_flags & ( 1L << 3 ) ) )) {
3701 if (buffer == NULL((void*)0))
3702 *length = 0;
3703
3704 if (FT_Load_Sfnt_Table (face, tag, offset, buffer, length) == 0)
3705 status = CAIRO_STATUS_SUCCESS;
3706 }
3707
3708 _cairo_ft_unscaled_font_unlock_face (unscaled);
3709
3710 return status;
3711}
3712
3713static cairo_int_status_t
3714_cairo_ft_index_to_ucs4(void *abstract_font,
3715 unsigned long index,
3716 uint32_t *ucs4)
3717{
3718 cairo_ft_scaled_font_t *scaled_font = abstract_font;
3719 cairo_ft_unscaled_font_t *unscaled = scaled_font->unscaled;
3720 FT_Face face;
3721 FT_ULong charcode;
3722 FT_UInt gindex;
3723
3724 face = _cairo_ft_unscaled_font_lock_face (unscaled);
3725 if (!face)
3726 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
3727
3728 *ucs4 = (uint32_t) -1;
3729 charcode = FT_Get_First_Char(face, &gindex);
3730 while (gindex != 0) {
3731 if (gindex == index) {
3732 *ucs4 = charcode;
3733 break;
3734 }
3735 charcode = FT_Get_Next_Char (face, charcode, &gindex);
3736 }
3737
3738 _cairo_ft_unscaled_font_unlock_face (unscaled);
3739
3740 return CAIRO_STATUS_SUCCESS;
3741}
3742
3743static cairo_int_status_t
3744_cairo_ft_is_synthetic (void *abstract_font,
3745 cairo_bool_t *is_synthetic)
3746{
3747 cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
3748 cairo_ft_scaled_font_t *scaled_font = abstract_font;
3749 cairo_ft_unscaled_font_t *unscaled = scaled_font->unscaled;
3750 FT_Face face;
3751 FT_Error error;
3752
3753 static GetVarFunc getVar;
3754 static DoneVarFunc doneVar;
3755 static GetVarBlendCoordsFunc getVarBlendCoords;
3756
3757 static int firstTime = 1;
3758 if (firstTime) {
3759 getVar = (GetVarFunc) dlsym (RTLD_DEFAULT((void *) 0), "FT_Get_MM_Var");
3760 doneVar = (DoneVarFunc) dlsym (RTLD_DEFAULT((void *) 0), "FT_Done_MM_Var");
3761 getVarBlendCoords = (GetVarBlendCoordsFunc) dlsym (RTLD_DEFAULT((void *) 0), "FT_Get_Var_Blend_Coordinates");
3762 firstTime = 0;
3763 }
3764
3765 if (scaled_font->ft_options.synth_flags != 0) {
3766 *is_synthetic = TRUE1;
3767 return status;
3768 }
3769
3770 *is_synthetic = FALSE0;
3771 face = _cairo_ft_unscaled_font_lock_face (unscaled);
3772 if (!face)
3773 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
3774
3775 if (face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS( 1L << 8 )) {
3776 FT_MM_Var *mm_var = NULL((void*)0);
3777 FT_Fixed *coords = NULL((void*)0);
3778 int num_axis;
3779 int i;
3780
3781 /* If this is an MM or variable font we can't assume the current outlines
3782 * are the same as the font tables */
3783 *is_synthetic = TRUE1;
3784
3785 error = getVar ? (*getVar) (face, &mm_var) : -1;
3786 if (error) {
3787 status = _cairo_error (_cairo_ft_to_cairo_error (error));
3788 goto cleanup;
3789 }
3790
3791 num_axis = mm_var->num_axis;
3792 coords = _cairo_malloc_ab (num_axis, sizeof(FT_Fixed));
3793 if (!coords) {
3794 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
3795 goto cleanup;
3796 }
3797
3798 /* Check if the current design coordinates are the default
3799 * coordinates. In this case the current outlines match the
3800 * font tables.
3801 */
3802 if (getVarBlendCoords) {
3803 (*getVarBlendCoords) (face, num_axis, coords);
3804 *is_synthetic = FALSE0;
3805 for (i = 0; i < num_axis; i++) {
3806 if (coords[i]) {
3807 *is_synthetic = TRUE1;
3808 break;
3809 }
3810 }
3811 }
3812
3813 cleanup:
3814 free (coords);
3815 if (doneVar)
3816 (*doneVar) (face->glyph->library, mm_var);
3817 else
3818 free (mm_var);
3819 }
3820
3821 _cairo_ft_unscaled_font_unlock_face (unscaled);
3822
3823 return status;
3824}
3825
3826static cairo_int_status_t
3827_cairo_index_to_glyph_name (void *abstract_font,
3828 char **glyph_names,
3829 int num_glyph_names,
3830 unsigned long glyph_index,
3831 unsigned long *glyph_array_index)
3832{
3833 cairo_ft_scaled_font_t *scaled_font = abstract_font;
3834 cairo_ft_unscaled_font_t *unscaled = scaled_font->unscaled;
3835 FT_Face face;
3836 char buffer[256]; /* PLRM specifies max name length of 127 */
3837 FT_Error error;
3838 int i;
3839
3840 face = _cairo_ft_unscaled_font_lock_face (unscaled);
3841 if (!face)
3842 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
3843
3844 error = FT_Get_Glyph_Name (face, glyph_index, buffer, sizeof buffer);
3845
3846 _cairo_ft_unscaled_font_unlock_face (unscaled);
3847
3848 if (error != FT_Err_Ok) {
3849 /* propagate fatal errors from FreeType */
3850 if (error == FT_Err_Out_Of_Memory)
3851 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
3852
3853 return CAIRO_INT_STATUS_UNSUPPORTED;
3854 }
3855
3856 /* FT first numbers the glyphs in the order they are read from the
3857 * Type 1 font. Then if .notdef is not the first glyph, the first
3858 * glyph is swapped with .notdef to ensure that .notdef is at
3859 * glyph index 0.
3860 *
3861 * As all but two glyphs in glyph_names already have the same
3862 * index as the FT glyph index, we first check if
3863 * glyph_names[glyph_index] is the name we are looking for. If not
3864 * we fall back to searching the entire array.
3865 */
3866
3867 if ((long)glyph_index < num_glyph_names &&
3868 strcmp (glyph_names[glyph_index], buffer) == 0)
3869 {
3870 *glyph_array_index = glyph_index;
3871
3872 return CAIRO_STATUS_SUCCESS;
3873 }
3874
3875 for (i = 0; i < num_glyph_names; i++) {
3876 if (strcmp (glyph_names[i], buffer) == 0) {
3877 *glyph_array_index = i;
3878
3879 return CAIRO_STATUS_SUCCESS;
3880 }
3881 }
3882
3883 return CAIRO_INT_STATUS_UNSUPPORTED;
3884}
3885
3886static cairo_bool_t
3887_ft_is_type1 (FT_Face face)
3888{
3889 const char *font_format = FT_Get_Font_Format (face);
3890 if (font_format &&
3891 (strcmp (font_format, "Type 1") == 0 ||
3892 strcmp (font_format, "CFF") == 0))
3893 {
3894 return TRUE1;
3895 }
3896
3897 return FALSE0;
3898}
3899
3900static cairo_int_status_t
3901_cairo_ft_load_type1_data (void *abstract_font,
3902 long offset,
3903 unsigned char *buffer,
3904 unsigned long *length)
3905{
3906 cairo_ft_scaled_font_t *scaled_font = abstract_font;
3907 cairo_ft_unscaled_font_t *unscaled = scaled_font->unscaled;
3908 FT_Face face;
3909 cairo_status_t status = CAIRO_STATUS_SUCCESS;
3910 unsigned long available_length;
3911 unsigned long ret;
3912
3913 assert (length != NULL)((void) sizeof (__assert_single_arg (length != ((void*)0))), __extension__
({ if (length != ((void*)0)) ; else __assert_fail ("length != NULL"
, "/root/firefox-clang/gfx/cairo/cairo/src/cairo-ft-font.c", 3913
, __extension__ __PRETTY_FUNCTION__); }))
;
3914
3915 if (_cairo_ft_scaled_font_is_vertical (&scaled_font->base))
3916 return CAIRO_INT_STATUS_UNSUPPORTED;
3917
3918 face = _cairo_ft_unscaled_font_lock_face (unscaled);
3919 if (!face)
3920 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
3921
3922 if (FT_IS_SFNT (face)( !!( (face)->face_flags & ( 1L << 3 ) ) )) {
3923 status = CAIRO_INT_STATUS_UNSUPPORTED;
3924 goto unlock;
3925 }
3926
3927 if (! _ft_is_type1 (face)) {
3928 status = CAIRO_INT_STATUS_UNSUPPORTED;
3929 goto unlock;
3930 }
3931
3932 available_length = MAX (face->stream->size - offset, 0)((face->stream->size - offset) > (0) ? (face->stream
->size - offset) : (0))
;
3933 if (!buffer) {
3934 *length = available_length;
3935 } else {
3936 if (*length > available_length) {
3937 status = CAIRO_INT_STATUS_UNSUPPORTED;
3938 } else if (face->stream->read != NULL((void*)0)) {
3939 /* Note that read() may be implemented as a macro, thanks POSIX!, so we
3940 * need to wrap the following usage in parentheses in order to
3941 * disambiguate it for the pre-processor - using the verbose function
3942 * pointer dereference for clarity.
3943 */
3944 ret = (* face->stream->read) (face->stream,
3945 offset,
3946 buffer,
3947 *length);
3948 if (ret != *length)
3949 status = _cairo_error (CAIRO_STATUS_READ_ERROR);
3950 } else {
3951 memcpy (buffer, face->stream->base + offset, *length);
3952 }
3953 }
3954
3955 unlock:
3956 _cairo_ft_unscaled_font_unlock_face (unscaled);
3957
3958 return status;
3959}
3960
3961static cairo_bool_t
3962_cairo_ft_has_color_glyphs (void *scaled)
3963{
3964 cairo_ft_unscaled_font_t *unscaled = ((cairo_ft_scaled_font_t *)scaled)->unscaled;
3965
3966 if (!unscaled->have_color_set) {
3967 FT_Face face;
3968 face = _cairo_ft_unscaled_font_lock_face (unscaled);
3969 if (unlikely (face == NULL)(__builtin_expect (!!(face == ((void*)0)), 0)))
3970 return FALSE0;
3971 _cairo_ft_unscaled_font_unlock_face (unscaled);
3972 }
3973
3974 return unscaled->have_color;
3975}
3976
3977static const cairo_scaled_font_backend_t _cairo_ft_scaled_font_backend = {
3978 CAIRO_FONT_TYPE_FT,
3979 _cairo_ft_scaled_font_fini,
3980 _cairo_ft_scaled_glyph_init,
3981 NULL((void*)0), /* text_to_glyphs */
3982 _cairo_ft_ucs4_to_index,
3983 _cairo_ft_load_truetype_table,
3984 _cairo_ft_index_to_ucs4,
3985 _cairo_ft_is_synthetic,
3986 _cairo_index_to_glyph_name,
3987 _cairo_ft_load_type1_data,
3988 _cairo_ft_has_color_glyphs
3989};
3990
3991/* #cairo_ft_font_face_t */
3992
3993#if CAIRO_HAS_FC_FONT1
3994static cairo_font_face_t *
3995_cairo_ft_font_face_create_for_pattern (FcPattern *pattern);
3996
3997static cairo_status_t
3998_cairo_ft_font_face_create_for_toy (cairo_toy_font_face_t *toy_face,
3999 cairo_font_face_t **font_face_out)
4000{
4001 cairo_font_face_t *font_face = (cairo_font_face_t *) &_cairo_font_face_nil;
4002 FcPattern *pattern;
4003 int fcslant;
4004 int fcweight;
4005
4006 pattern = FcPatternCreate ();
4007 if (!pattern) {
4008 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY)do { cairo_status_t status__ = _cairo_error (CAIRO_STATUS_NO_MEMORY
); (void) status__; } while (0)
;
4009 return font_face->status;
4010 }
4011
4012 if (!FcPatternAddString (pattern,
4013 FC_FAMILY"family", (unsigned char *) toy_face->family))
4014 {
4015 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY)do { cairo_status_t status__ = _cairo_error (CAIRO_STATUS_NO_MEMORY
); (void) status__; } while (0)
;
4016 goto FREE_PATTERN;
4017 }
4018
4019 switch (toy_face->slant)
4020 {
4021 case CAIRO_FONT_SLANT_ITALIC:
4022 fcslant = FC_SLANT_ITALIC100;
4023 break;
4024 case CAIRO_FONT_SLANT_OBLIQUE:
4025 fcslant = FC_SLANT_OBLIQUE110;
4026 break;
4027 case CAIRO_FONT_SLANT_NORMAL:
4028 default:
4029 fcslant = FC_SLANT_ROMAN0;
4030 break;
4031 }
4032
4033 if (!FcPatternAddInteger (pattern, FC_SLANT"slant", fcslant)) {
4034 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY)do { cairo_status_t status__ = _cairo_error (CAIRO_STATUS_NO_MEMORY
); (void) status__; } while (0)
;
4035 goto FREE_PATTERN;
4036 }
4037
4038 switch (toy_face->weight)
4039 {
4040 case CAIRO_FONT_WEIGHT_BOLD:
4041 fcweight = FC_WEIGHT_BOLD200;
4042 break;
4043 case CAIRO_FONT_WEIGHT_NORMAL:
4044 default:
4045 fcweight = FC_WEIGHT_MEDIUM100;
4046 break;
4047 }
4048
4049 if (!FcPatternAddInteger (pattern, FC_WEIGHT"weight", fcweight)) {
4050 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY)do { cairo_status_t status__ = _cairo_error (CAIRO_STATUS_NO_MEMORY
); (void) status__; } while (0)
;
4051 goto FREE_PATTERN;
4052 }
4053
4054 font_face = _cairo_ft_font_face_create_for_pattern (pattern);
4055
4056 FREE_PATTERN:
4057 FcPatternDestroy (pattern);
4058
4059 *font_face_out = font_face;
4060 return font_face->status;
4061}
4062#endif
4063
4064static cairo_bool_t
4065_cairo_ft_font_face_destroy (void *abstract_face)
4066{
4067 cairo_ft_font_face_t *font_face = abstract_face;
4068
4069 /* When destroying a face created by cairo_ft_font_face_create_for_ft_face,
4070 * we have a special "zombie" state for the face when the unscaled font
4071 * is still alive but there are no other references to a font face with
4072 * the same FT_Face.
4073 *
4074 * We go from:
4075 *
4076 * font_face ------> unscaled
4077 * <-....weak....../
4078 *
4079 * To:
4080 *
4081 * font_face <------- unscaled
4082 */
4083
4084 if (font_face->unscaled) {
4085 CAIRO_FT_LOCK (font_face->unscaled)((font_face->unscaled)->face_context ? (void)mozilla_LockSharedFTFace
((font_face->unscaled)->face_context, ((void*)0)) : (void
)pthread_mutex_lock (&((font_face->unscaled)->mutex
)))
;
4086
4087 if (font_face->unscaled->from_face &&
4088 font_face->next == NULL((void*)0) &&
4089 font_face->unscaled->faces == font_face &&
4090 CAIRO_REFERENCE_COUNT_GET_VALUE (&font_face->unscaled->base.ref_count)_cairo_atomic_int_get (&(&font_face->unscaled->
base.ref_count)->ref_count)
> 1)
4091 {
4092 CAIRO_FT_UNLOCK (font_face->unscaled)((font_face->unscaled)->face_context ? mozilla_UnlockSharedFTFace
((font_face->unscaled)->face_context) : (void)pthread_mutex_unlock
(&((font_face->unscaled)->mutex)))
;
4093 _cairo_unscaled_font_destroy (&font_face->unscaled->base);
4094 font_face->unscaled = NULL((void*)0);
4095
4096 return FALSE0;
4097 }
4098
4099 cairo_ft_font_face_t *tmp_face = NULL((void*)0);
4100 cairo_ft_font_face_t *last_face = NULL((void*)0);
4101
4102 /* Remove face from linked list */
4103 for (tmp_face = font_face->unscaled->faces;
4104 tmp_face;
4105 tmp_face = tmp_face->next)
4106 {
4107 if (tmp_face == font_face) {
4108 if (last_face)
4109 last_face->next = tmp_face->next;
4110 else
4111 font_face->unscaled->faces = tmp_face->next;
4112 }
4113
4114 last_face = tmp_face;
4115 }
4116
4117 CAIRO_FT_UNLOCK (font_face->unscaled)((font_face->unscaled)->face_context ? mozilla_UnlockSharedFTFace
((font_face->unscaled)->face_context) : (void)pthread_mutex_unlock
(&((font_face->unscaled)->mutex)))
;
4118 _cairo_unscaled_font_destroy (&font_face->unscaled->base);
4119 font_face->unscaled = NULL((void*)0);
4120 }
4121
4122 _cairo_ft_options_fini (&font_face->ft_options);
4123
4124#if CAIRO_HAS_FC_FONT1
4125 if (font_face->pattern) {
4126 FcPatternDestroy (font_face->pattern);
4127 cairo_font_face_destroy_moz_cairo_font_face_destroy (font_face->resolved_font_face);
4128 }
4129#endif
4130
4131 return TRUE1;
4132}
4133
4134static cairo_font_face_t *
4135_cairo_ft_font_face_get_implementation (void *abstract_face,
4136 const cairo_matrix_t *font_matrix,
4137 const cairo_matrix_t *ctm,
4138 const cairo_font_options_t *options)
4139{
4140 /* The handling of font options is different depending on how the
4141 * font face was created. When the user creates a font face with
4142 * cairo_ft_font_face_create_for_ft_face(), then the load flags
4143 * passed in augment the load flags for the options. But for
4144 * cairo_ft_font_face_create_for_pattern(), the load flags are
4145 * derived from a pattern where the user has called
4146 * cairo_ft_font_options_substitute(), so *just* use those load
4147 * flags and ignore the options.
4148 */
4149
4150#if CAIRO_HAS_FC_FONT1
4151 cairo_ft_font_face_t *font_face = abstract_face;
4152
4153 /* If we have an unresolved pattern, resolve it and create
4154 * unscaled font. Otherwise, use the ones stored in font_face.
4155 */
4156 if (font_face->pattern) {
4157 cairo_font_face_t *resolved;
4158
4159 /* Cache the resolved font whilst the FcConfig remains consistent. */
4160 resolved = font_face->resolved_font_face;
4161 if (resolved != NULL((void*)0)) {
4162 if (! FcInitBringUptoDate ()) {
4163 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY)do { cairo_status_t status__ = _cairo_error (CAIRO_STATUS_NO_MEMORY
); (void) status__; } while (0)
;
4164 return (cairo_font_face_t *) &_cairo_font_face_nil;
4165 }
4166
4167 if (font_face->resolved_config == FcConfigGetCurrent ())
4168 return cairo_font_face_reference_moz_cairo_font_face_reference (resolved);
4169
4170 cairo_font_face_destroy_moz_cairo_font_face_destroy (resolved);
4171 font_face->resolved_font_face = NULL((void*)0);
4172 }
4173
4174 resolved = _cairo_ft_resolve_pattern (font_face->pattern,
4175 font_matrix,
4176 ctm,
4177 options);
4178 if (unlikely (resolved->status)(__builtin_expect (!!(resolved->status), 0)))
4179 return resolved;
4180
4181 font_face->resolved_font_face = cairo_font_face_reference_moz_cairo_font_face_reference (resolved);
4182 font_face->resolved_config = FcConfigGetCurrent ();
4183
4184 return resolved;
4185 }
4186#endif
4187
4188 return abstract_face;
4189}
4190
4191static void
4192_cairo_ft_font_face_lock (void *abstract_face)
4193{
4194 cairo_ft_font_face_t *font_face = abstract_face;
4195 if (font_face->unscaled) {
4196 CAIRO_FT_LOCK (font_face->unscaled)((font_face->unscaled)->face_context ? (void)mozilla_LockSharedFTFace
((font_face->unscaled)->face_context, ((void*)0)) : (void
)pthread_mutex_lock (&((font_face->unscaled)->mutex
)))
;
4197 }
4198}
4199
4200static void
4201_cairo_ft_font_face_unlock (void *abstract_face)
4202{
4203 cairo_ft_font_face_t *font_face = abstract_face;
4204 if (font_face->unscaled) {
4205 CAIRO_FT_UNLOCK (font_face->unscaled)((font_face->unscaled)->face_context ? mozilla_UnlockSharedFTFace
((font_face->unscaled)->face_context) : (void)pthread_mutex_unlock
(&((font_face->unscaled)->mutex)))
;
4206 }
4207}
4208
4209const cairo_font_face_backend_t _cairo_ft_font_face_backend = {
4210 CAIRO_FONT_TYPE_FT,
4211#if CAIRO_HAS_FC_FONT1
4212 _cairo_ft_font_face_create_for_toy,
4213#else
4214 NULL((void*)0),
4215#endif
4216 _cairo_ft_font_face_destroy,
4217 _cairo_ft_font_face_scaled_font_create,
4218 _cairo_ft_font_face_get_implementation,
4219/*
4220 _cairo_ft_font_face_lock,
4221 _cairo_ft_font_face_unlock
4222*/
4223};
4224
4225#if CAIRO_HAS_FC_FONT1
4226static cairo_font_face_t *
4227_cairo_ft_font_face_create_for_pattern (FcPattern *pattern)
4228{
4229 cairo_ft_font_face_t *font_face;
4230
4231 font_face = _cairo_calloc (sizeof (cairo_ft_font_face_t))((sizeof (cairo_ft_font_face_t)) != 0 ? calloc(1,sizeof (cairo_ft_font_face_t
)) : ((void*)0))
;
4232 if (unlikely (font_face == NULL)(__builtin_expect (!!(font_face == ((void*)0)), 0))) {
4233 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY)do { cairo_status_t status__ = _cairo_error (CAIRO_STATUS_NO_MEMORY
); (void) status__; } while (0)
;
4234 return (cairo_font_face_t *) &_cairo_font_face_nil;
4235 }
4236
4237 font_face->unscaled = NULL((void*)0);
4238
4239 _get_pattern_ft_options (pattern, &font_face->ft_options);
4240
4241 font_face->next = NULL((void*)0);
4242
4243 font_face->pattern = FcPatternDuplicate (pattern);
4244 if (unlikely (font_face->pattern == NULL)(__builtin_expect (!!(font_face->pattern == ((void*)0)), 0
))
) {
4245 free (font_face);
4246 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY)do { cairo_status_t status__ = _cairo_error (CAIRO_STATUS_NO_MEMORY
); (void) status__; } while (0)
;
4247 return (cairo_font_face_t *) &_cairo_font_face_nil;
4248 }
4249
4250 font_face->resolved_font_face = NULL((void*)0);
4251 font_face->resolved_config = NULL((void*)0);
4252
4253 _cairo_font_face_init (&font_face->base, &_cairo_ft_font_face_backend);
4254
4255 return &font_face->base;
4256}
4257#endif
4258
4259static cairo_font_face_t *
4260_cairo_ft_font_face_create (cairo_ft_unscaled_font_t *unscaled,
4261 cairo_ft_options_t *ft_options)
4262{
4263 cairo_ft_font_face_t *font_face, **prev_font_face;
4264
4265 CAIRO_FT_LOCK (unscaled)((unscaled)->face_context ? (void)mozilla_LockSharedFTFace
((unscaled)->face_context, ((void*)0)) : (void)pthread_mutex_lock
(&((unscaled)->mutex)))
;
4266
4267 /* Looked for an existing matching font face */
4268 for (font_face = unscaled->faces, prev_font_face = &unscaled->faces;
4269 font_face;
4270 prev_font_face = &font_face->next, font_face = font_face->next)
4271 {
4272 if (font_face->ft_options.load_flags == ft_options->load_flags &&
4273 font_face->ft_options.synth_flags == ft_options->synth_flags &&
4274 cairo_font_options_equal_moz_cairo_font_options_equal (&font_face->ft_options.base, &ft_options->base))
4275 {
4276 if (font_face->base.status) {
4277 /* The font_face has been left in an error state, abandon it. */
4278 *prev_font_face = font_face->next;
4279 break;
4280 }
4281
4282 if (font_face->unscaled == NULL((void*)0)) {
4283 /* Resurrect this "zombie" font_face (from
4284 * _cairo_ft_font_face_destroy), switching its unscaled_font
4285 * from owner to ownee. */
4286 font_face->unscaled = unscaled;
4287 _cairo_unscaled_font_reference (&unscaled->base);
4288 } else {
4289 cairo_font_face_reference_moz_cairo_font_face_reference (&font_face->base);
4290 }
4291
4292 CAIRO_FT_UNLOCK (unscaled)((unscaled)->face_context ? mozilla_UnlockSharedFTFace((unscaled
)->face_context) : (void)pthread_mutex_unlock (&((unscaled
)->mutex)))
;
4293 return &font_face->base;
4294 }
4295 }
4296
4297 /* No match found, create a new one */
4298 font_face = _cairo_calloc (sizeof (cairo_ft_font_face_t))((sizeof (cairo_ft_font_face_t)) != 0 ? calloc(1,sizeof (cairo_ft_font_face_t
)) : ((void*)0))
;
4299 if (unlikely (!font_face)(__builtin_expect (!!(!font_face), 0))) {
4300 CAIRO_FT_UNLOCK (unscaled)((unscaled)->face_context ? mozilla_UnlockSharedFTFace((unscaled
)->face_context) : (void)pthread_mutex_unlock (&((unscaled
)->mutex)))
;
4301 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY)do { cairo_status_t status__ = _cairo_error (CAIRO_STATUS_NO_MEMORY
); (void) status__; } while (0)
;
4302 return (cairo_font_face_t *)&_cairo_font_face_nil;
4303 }
4304
4305 font_face->unscaled = unscaled;
4306 _cairo_unscaled_font_reference (&unscaled->base);
4307
4308 _cairo_ft_options_init_copy (&font_face->ft_options, ft_options);
4309
4310 if (unscaled->faces && unscaled->faces->unscaled == NULL((void*)0)) {
4311 /* This "zombie" font_face (from _cairo_ft_font_face_destroy)
4312 * is no longer needed. */
4313 assert (unscaled->from_face && unscaled->faces->next == NULL)((void) sizeof (__assert_single_arg (unscaled->from_face &&
unscaled->faces->next == ((void*)0))), __extension__ (
{ if (unscaled->from_face && unscaled->faces->
next == ((void*)0)) ; else __assert_fail ("unscaled->from_face && unscaled->faces->next == NULL"
, "/root/firefox-clang/gfx/cairo/cairo/src/cairo-ft-font.c", 4313
, __extension__ __PRETTY_FUNCTION__); }))
;
4314 cairo_font_face_destroy_moz_cairo_font_face_destroy (&unscaled->faces->base);
4315 unscaled->faces = NULL((void*)0);
4316 }
4317
4318 font_face->next = unscaled->faces;
4319 unscaled->faces = font_face;
4320
4321#if CAIRO_HAS_FC_FONT1
4322 font_face->pattern = NULL((void*)0);
4323#endif
4324
4325 _cairo_font_face_init (&font_face->base, &_cairo_ft_font_face_backend);
4326
4327 CAIRO_FT_UNLOCK (unscaled)((unscaled)->face_context ? mozilla_UnlockSharedFTFace((unscaled
)->face_context) : (void)pthread_mutex_unlock (&((unscaled
)->mutex)))
;
4328 return &font_face->base;
4329}
4330
4331/* implement the platform-specific interface */
4332
4333#if CAIRO_HAS_FC_FONT1
4334static cairo_status_t
4335_cairo_ft_font_options_substitute (const cairo_font_options_t *options,
4336 FcPattern *pattern)
4337{
4338 FcValue v;
4339
4340 if (options->antialias != CAIRO_ANTIALIAS_DEFAULT)
4341 {
4342 if (FcPatternGet (pattern, FC_ANTIALIAS"antialias", 0, &v) == FcResultNoMatch)
4343 {
4344 if (! FcPatternAddBool (pattern,
4345 FC_ANTIALIAS"antialias",
4346 options->antialias != CAIRO_ANTIALIAS_NONE))
4347 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
4348
4349 if (options->antialias != CAIRO_ANTIALIAS_SUBPIXEL) {
4350 FcPatternDel (pattern, FC_RGBA"rgba");
4351 if (! FcPatternAddInteger (pattern, FC_RGBA"rgba", FC_RGBA_NONE5))
4352 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
4353 }
4354 }
4355 }
4356
4357 if (options->antialias != CAIRO_ANTIALIAS_DEFAULT)
4358 {
4359 if (FcPatternGet (pattern, FC_RGBA"rgba", 0, &v) == FcResultNoMatch)
4360 {
4361 int rgba;
4362
4363 if (options->antialias == CAIRO_ANTIALIAS_SUBPIXEL) {
4364 switch (options->subpixel_order) {
4365 case CAIRO_SUBPIXEL_ORDER_DEFAULT:
4366 case CAIRO_SUBPIXEL_ORDER_RGB:
4367 default:
4368 rgba = FC_RGBA_RGB1;
4369 break;
4370 case CAIRO_SUBPIXEL_ORDER_BGR:
4371 rgba = FC_RGBA_BGR2;
4372 break;
4373 case CAIRO_SUBPIXEL_ORDER_VRGB:
4374 rgba = FC_RGBA_VRGB3;
4375 break;
4376 case CAIRO_SUBPIXEL_ORDER_VBGR:
4377 rgba = FC_RGBA_VBGR4;
4378 break;
4379 }
4380 } else {
4381 rgba = FC_RGBA_NONE5;
4382 }
4383
4384 if (! FcPatternAddInteger (pattern, FC_RGBA"rgba", rgba))
4385 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
4386 }
4387 }
4388
4389 if (options->lcd_filter != CAIRO_LCD_FILTER_DEFAULT)
4390 {
4391 if (FcPatternGet (pattern, FC_LCD_FILTER"lcdfilter", 0, &v) == FcResultNoMatch)
4392 {
4393 int lcd_filter;
4394
4395 switch (options->lcd_filter) {
4396 case CAIRO_LCD_FILTER_NONE:
4397 lcd_filter = FT_LCD_FILTER_NONE;
4398 break;
4399 case CAIRO_LCD_FILTER_INTRA_PIXEL:
4400 lcd_filter = FT_LCD_FILTER_LEGACY;
4401 break;
4402 case CAIRO_LCD_FILTER_FIR3:
4403 lcd_filter = FT_LCD_FILTER_LIGHT;
4404 break;
4405 default:
4406 case CAIRO_LCD_FILTER_DEFAULT:
4407 case CAIRO_LCD_FILTER_FIR5:
4408 lcd_filter = FT_LCD_FILTER_DEFAULT;
4409 break;
4410 }
4411
4412 if (! FcPatternAddInteger (pattern, FC_LCD_FILTER"lcdfilter", lcd_filter))
4413 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
4414 }
4415 }
4416
4417 if (options->hint_style != CAIRO_HINT_STYLE_DEFAULT)
4418 {
4419 if (FcPatternGet (pattern, FC_HINTING"hinting", 0, &v) == FcResultNoMatch)
4420 {
4421 if (! FcPatternAddBool (pattern,
4422 FC_HINTING"hinting",
4423 options->hint_style != CAIRO_HINT_STYLE_NONE))
4424 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
4425 }
4426
4427 if (FcPatternGet (pattern, FC_HINT_STYLE"hintstyle", 0, &v) == FcResultNoMatch)
4428 {
4429 int hint_style;
4430
4431 switch (options->hint_style) {
4432 case CAIRO_HINT_STYLE_NONE:
4433 hint_style = FC_HINT_NONE0;
4434 break;
4435 case CAIRO_HINT_STYLE_SLIGHT:
4436 hint_style = FC_HINT_SLIGHT1;
4437 break;
4438 case CAIRO_HINT_STYLE_MEDIUM:
4439 hint_style = FC_HINT_MEDIUM2;
4440 break;
4441 case CAIRO_HINT_STYLE_FULL:
4442 case CAIRO_HINT_STYLE_DEFAULT:
4443 default:
4444 hint_style = FC_HINT_FULL3;
4445 break;
4446 }
4447
4448 if (! FcPatternAddInteger (pattern, FC_HINT_STYLE"hintstyle", hint_style))
4449 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
4450 }
4451 }
4452
4453 return CAIRO_STATUS_SUCCESS;
4454}
4455
4456/**
4457 * cairo_ft_font_options_substitute:
4458 * @options: a #cairo_font_options_t object
4459 * @pattern: an existing #FcPattern
4460 *
4461 * Add options to a #FcPattern based on a #cairo_font_options_t font
4462 * options object. Options that are already in the pattern, are not overridden,
4463 * so you should call this function after calling FcConfigSubstitute() (the
4464 * user's settings should override options based on the surface type), but
4465 * before calling FcDefaultSubstitute().
4466 *
4467 * Since: 1.0
4468 **/
4469void
4470cairo_ft_font_options_substitute_moz_cairo_ft_font_options_substitute (const cairo_font_options_t *options,
4471 FcPattern *pattern)
4472{
4473 if (cairo_font_options_status_moz_cairo_font_options_status ((cairo_font_options_t *) options))
4474 return;
4475
4476 _cairo_ft_font_options_substitute (options, pattern);
4477}
4478
4479static cairo_font_face_t *
4480_cairo_ft_resolve_pattern (FcPattern *pattern,
4481 const cairo_matrix_t *font_matrix,
4482 const cairo_matrix_t *ctm,
4483 const cairo_font_options_t *font_options)
4484{
4485 cairo_status_t status;
4486
4487 cairo_matrix_t scale;
4488 FcPattern *resolved;
4489 cairo_ft_font_transform_t sf;
4490 FcResult result;
4491 cairo_ft_unscaled_font_t *unscaled;
4492 cairo_ft_options_t ft_options;
4493 cairo_font_face_t *font_face;
4494
4495 scale = *ctm;
4496 scale.x0 = scale.y0 = 0;
4497 cairo_matrix_multiply_moz_cairo_matrix_multiply (&scale,
4498 font_matrix,
4499 &scale);
4500
4501 status = _compute_transform (&sf, &scale, NULL((void*)0));
4502 if (unlikely (status)(__builtin_expect (!!(status), 0)))
4503 return (cairo_font_face_t *)&_cairo_font_face_nil;
4504
4505 pattern = FcPatternDuplicate (pattern);
4506 if (pattern == NULL((void*)0))
4507 return (cairo_font_face_t *)&_cairo_font_face_nil;
4508
4509 if (! FcPatternAddDouble (pattern, FC_PIXEL_SIZE"pixelsize", sf.y_scale)) {
4510 font_face = (cairo_font_face_t *)&_cairo_font_face_nil;
4511 goto FREE_PATTERN;
4512 }
4513
4514 if (! FcConfigSubstitute (NULL((void*)0), pattern, FcMatchPattern)) {
4515 font_face = (cairo_font_face_t *)&_cairo_font_face_nil;
4516 goto FREE_PATTERN;
4517 }
4518
4519 status = _cairo_ft_font_options_substitute (font_options, pattern);
4520 if (status) {
4521 font_face = (cairo_font_face_t *)&_cairo_font_face_nil;
4522 goto FREE_PATTERN;
4523 }
4524
4525 FcDefaultSubstitute (pattern);
4526
4527 status = _cairo_ft_unscaled_font_create_for_pattern (pattern, &unscaled);
4528 if (unlikely (status)(__builtin_expect (!!(status), 0))) {
4529 font_face = (cairo_font_face_t *)&_cairo_font_face_nil;
4530 goto FREE_PATTERN;
4531 }
4532
4533 if (unscaled == NULL((void*)0)) {
4534 resolved = FcFontMatch (NULL((void*)0), pattern, &result);
4535 if (!resolved) {
4536 /* We failed to find any font. Substitute twin so that the user can
4537 * see something (and hopefully recognise that the font is missing)
4538 * and not just receive a NO_MEMORY error during rendering.
4539 */
4540 font_face = _cairo_font_face_twin_create_fallback ();
4541 goto FREE_PATTERN;
4542 }
4543
4544 status = _cairo_ft_unscaled_font_create_for_pattern (resolved, &unscaled);
4545 if (unlikely (status || unscaled == NULL)(__builtin_expect (!!(status || unscaled == ((void*)0)), 0))) {
4546 font_face = (cairo_font_face_t *)&_cairo_font_face_nil;
4547 goto FREE_RESOLVED;
4548 }
4549 } else
4550 resolved = pattern;
4551
4552 _get_pattern_ft_options (resolved, &ft_options);
4553 font_face = _cairo_ft_font_face_create (unscaled, &ft_options);
4554 _cairo_ft_options_fini (&ft_options);
4555 _cairo_unscaled_font_destroy (&unscaled->base);
4556
4557FREE_RESOLVED:
4558 if (resolved != pattern)
4559 FcPatternDestroy (resolved);
4560
4561FREE_PATTERN:
4562 FcPatternDestroy (pattern);
4563
4564 return font_face;
4565}
4566
4567/**
4568 * cairo_ft_font_face_create_for_pattern:
4569 * @pattern: A fontconfig pattern. Cairo makes a copy of the pattern
4570 * if it needs to. You are free to modify or free @pattern after this call.
4571 *
4572 * Creates a new font face for the FreeType font backend based on a
4573 * fontconfig pattern. This font can then be used with
4574 * cairo_set_font_face() or cairo_scaled_font_create(). The
4575 * #cairo_scaled_font_t returned from cairo_scaled_font_create() is
4576 * also for the FreeType backend and can be used with functions such
4577 * as cairo_ft_scaled_font_lock_face().
4578 *
4579 * Font rendering options are represented both here and when you
4580 * call cairo_scaled_font_create(). Font options that have a representation
4581 * in a #FcPattern must be passed in here; to modify #FcPattern
4582 * appropriately to reflect the options in a #cairo_font_options_t, call
4583 * cairo_ft_font_options_substitute().
4584 *
4585 * The pattern's FC_FT_FACE element is inspected first and if that is set,
4586 * that will be the FreeType font face associated with the returned cairo
4587 * font face. Otherwise the FC_FILE element is checked. If it's set,
4588 * that and the value of the FC_INDEX element (defaults to zero) of @pattern
4589 * are used to load a font face from file.
4590 *
4591 * If both steps from the previous paragraph fails, @pattern will be passed
4592 * to FcConfigSubstitute, FcDefaultSubstitute, and finally FcFontMatch,
4593 * and the resulting font pattern is used.
4594 *
4595 * If the FC_FT_FACE element of @pattern is set, the user is responsible
4596 * for making sure that the referenced FT_Face remains valid for the life
4597 * time of the returned #cairo_font_face_t. See
4598 * cairo_ft_font_face_create_for_ft_face() for an example of how to couple
4599 * the life time of the FT_Face to that of the cairo font-face.
4600 *
4601 * Return value: a newly created #cairo_font_face_t. Free with
4602 * cairo_font_face_destroy() when you are done using it.
4603 *
4604 * Since: 1.0
4605 **/
4606cairo_font_face_t *
4607cairo_ft_font_face_create_for_pattern_moz_cairo_ft_font_face_create_for_pattern (FcPattern *pattern)
4608{
4609 cairo_ft_unscaled_font_t *unscaled;
4610 cairo_font_face_t *font_face;
4611 cairo_ft_options_t ft_options;
4612 cairo_status_t status;
4613
4614 status = _cairo_ft_unscaled_font_create_for_pattern (pattern, &unscaled);
1
Calling '_cairo_ft_unscaled_font_create_for_pattern'
4615 if (unlikely (status)(__builtin_expect (!!(status), 0))) {
4616 if (status == CAIRO_STATUS_FILE_NOT_FOUND)
4617 return (cairo_font_face_t *) &_cairo_font_face_nil_file_not_found;
4618 else
4619 return (cairo_font_face_t *) &_cairo_font_face_nil;
4620 }
4621 if (unlikely (unscaled == NULL)(__builtin_expect (!!(unscaled == ((void*)0)), 0))) {
4622 /* Store the pattern. We will resolve it and create unscaled
4623 * font when creating scaled fonts */
4624 return _cairo_ft_font_face_create_for_pattern (pattern);
4625 }
4626
4627 _get_pattern_ft_options (pattern, &ft_options);
4628 font_face = _cairo_ft_font_face_create (unscaled, &ft_options);
4629 _cairo_ft_options_fini (&ft_options);
4630 _cairo_unscaled_font_destroy (&unscaled->base);
4631
4632 return font_face;
4633}
4634#endif
4635
4636/**
4637 * cairo_ft_font_face_create_for_ft_face:
4638 * @face: A FreeType face object, already opened. This must
4639 * be kept around until the face's ref_count drops to
4640 * zero and it is freed. Since the face may be referenced
4641 * internally to Cairo, the best way to determine when it
4642 * is safe to free the face is to pass a
4643 * #cairo_destroy_func_t to cairo_font_face_set_user_data()
4644 * @load_flags: flags to pass to FT_Load_Glyph when loading
4645 * glyphs from the font. These flags are OR'ed together with
4646 * the flags derived from the #cairo_font_options_t passed
4647 * to cairo_scaled_font_create(), so only a few values such
4648 * as %FT_LOAD_VERTICAL_LAYOUT, and %FT_LOAD_FORCE_AUTOHINT
4649 * are useful. You should not pass any of the flags affecting
4650 * the load target, such as %FT_LOAD_TARGET_LIGHT.
4651 *
4652 * Creates a new font face for the FreeType font backend from a
4653 * pre-opened FreeType face. This font can then be used with
4654 * cairo_set_font_face() or cairo_scaled_font_create(). The
4655 * #cairo_scaled_font_t returned from cairo_scaled_font_create() is
4656 * also for the FreeType backend and can be used with functions such
4657 * as cairo_ft_scaled_font_lock_face(). Note that Cairo may keep a reference
4658 * to the FT_Face alive in a font-cache and the exact lifetime of the reference
4659 * depends highly upon the exact usage pattern and is subject to external
4660 * factors. You must not call FT_Done_Face() before the last reference to the
4661 * #cairo_font_face_t has been dropped.
4662 *
4663 * As an example, below is how one might correctly couple the lifetime of
4664 * the FreeType face object to the #cairo_font_face_t.
4665 *
4666 * <informalexample><programlisting>
4667 * static const cairo_user_data_key_t key;
4668 *
4669 * font_face = cairo_ft_font_face_create_for_ft_face (ft_face, 0);
4670 * status = cairo_font_face_set_user_data (font_face, &key,
4671 * ft_face, (cairo_destroy_func_t) FT_Done_Face);
4672 * if (status) {
4673 * cairo_font_face_destroy (font_face);
4674 * FT_Done_Face (ft_face);
4675 * return ERROR;
4676 * }
4677 * </programlisting></informalexample>
4678 *
4679 * Return value: a newly created #cairo_font_face_t. Free with
4680 * cairo_font_face_destroy() when you are done using it.
4681 *
4682 * Since: 1.0
4683 **/
4684cairo_font_face_t *
4685cairo_ft_font_face_create_for_ft_face_moz_cairo_ft_font_face_create_for_ft_face (FT_Face face,
4686 int load_flags,
4687 unsigned int synth_flags,
4688 void *face_context)
4689{
4690 cairo_ft_unscaled_font_t *unscaled;
4691 cairo_font_face_t *font_face;
4692 cairo_ft_options_t ft_options;
4693 cairo_status_t status;
4694
4695 status = _cairo_ft_unscaled_font_create_from_face (face, face_context,
4696 &unscaled);
4697 if (unlikely (status)(__builtin_expect (!!(status), 0)))
4698 return (cairo_font_face_t *)&_cairo_font_face_nil;
4699
4700 ft_options.load_flags = load_flags;
4701 ft_options.synth_flags = synth_flags;
4702 _cairo_font_options_init_default (&ft_options.base);
4703
4704 font_face = _cairo_ft_font_face_create (unscaled, &ft_options);
4705 _cairo_unscaled_font_destroy (&unscaled->base);
4706
4707 return font_face;
4708}
4709
4710/**
4711 * cairo_ft_font_face_set_synthesize:
4712 * @font_face: The #cairo_ft_font_face_t object to modify
4713 * @synth_flags: the set of synthesis options to enable
4714 *
4715 * FreeType provides the ability to synthesize different glyphs from a base
4716 * font, which is useful if you lack those glyphs from a true bold or oblique
4717 * font. See also #cairo_ft_synthesize_t.
4718 *
4719 * Since: 1.12
4720 **/
4721void
4722cairo_ft_font_face_set_synthesize_moz_cairo_ft_font_face_set_synthesize (cairo_font_face_t *font_face,
4723 unsigned int synth_flags)
4724{
4725 cairo_ft_font_face_t *ft;
4726
4727 if (font_face->backend->type != CAIRO_FONT_TYPE_FT)
4728 return;
4729
4730 ft = (cairo_ft_font_face_t *) font_face;
4731 ft->ft_options.synth_flags |= synth_flags;
4732}
4733
4734/**
4735 * cairo_ft_font_face_unset_synthesize:
4736 * @font_face: The #cairo_ft_font_face_t object to modify
4737 * @synth_flags: the set of synthesis options to disable
4738 *
4739 * See cairo_ft_font_face_set_synthesize().
4740 *
4741 * Since: 1.12
4742 **/
4743void
4744cairo_ft_font_face_unset_synthesize (cairo_font_face_t *font_face,
4745 unsigned int synth_flags)
4746{
4747 cairo_ft_font_face_t *ft;
4748
4749 if (font_face->backend->type != CAIRO_FONT_TYPE_FT)
4750 return;
4751
4752 ft = (cairo_ft_font_face_t *) font_face;
4753 ft->ft_options.synth_flags &= ~synth_flags;
4754}
4755
4756/**
4757 * cairo_ft_font_face_get_synthesize:
4758 * @font_face: The #cairo_ft_font_face_t object to query
4759 *
4760 * See #cairo_ft_synthesize_t.
4761 *
4762 * Returns: the current set of synthesis options.
4763 *
4764 * Since: 1.12
4765 **/
4766unsigned int
4767cairo_ft_font_face_get_synthesize (cairo_font_face_t *font_face)
4768{
4769 cairo_ft_font_face_t *ft;
4770
4771 if (font_face->backend->type != CAIRO_FONT_TYPE_FT)
4772 return 0;
4773
4774 ft = (cairo_ft_font_face_t *) font_face;
4775 return ft->ft_options.synth_flags;
4776}
4777
4778/**
4779 * cairo_ft_scaled_font_lock_face:
4780 * @scaled_font: A #cairo_scaled_font_t from the FreeType font backend. Such an
4781 * object can be created by calling cairo_scaled_font_create() on a
4782 * FreeType backend font face (see cairo_ft_font_face_create_for_pattern(),
4783 * cairo_ft_font_face_create_for_ft_face()).
4784 *
4785 * cairo_ft_scaled_font_lock_face() gets the #FT_Face object from a FreeType
4786 * backend font and scales it appropriately for the font and applies OpenType
4787 * font variations if applicable. You must
4788 * release the face with cairo_ft_scaled_font_unlock_face()
4789 * when you are done using it. Since the #FT_Face object can be
4790 * shared between multiple #cairo_scaled_font_t objects, you must not
4791 * lock any other font objects until you unlock this one. A count is
4792 * kept of the number of times cairo_ft_scaled_font_lock_face() is
4793 * called. cairo_ft_scaled_font_unlock_face() must be called the same number
4794 * of times.
4795 *
4796 * You must be careful when using this function in a library or in a
4797 * threaded application, because freetype's design makes it unsafe to
4798 * call freetype functions simultaneously from multiple threads, (even
4799 * if using distinct FT_Face objects). Because of this, application
4800 * code that acquires an FT_Face object with this call must add its
4801 * own locking to protect any use of that object, (and which also must
4802 * protect any other calls into cairo as almost any cairo function
4803 * might result in a call into the freetype library).
4804 *
4805 * Return value: The #FT_Face object for @font, scaled appropriately,
4806 * or %NULL if @scaled_font is in an error state (see
4807 * cairo_scaled_font_status()) or there is insufficient memory.
4808 *
4809 * Since: 1.0
4810 **/
4811FT_Face
4812cairo_ft_scaled_font_lock_face_moz_cairo_ft_scaled_font_lock_face (cairo_scaled_font_t *abstract_font)
4813{
4814 cairo_ft_scaled_font_t *scaled_font = (cairo_ft_scaled_font_t *) abstract_font;
4815 FT_Face face;
4816 cairo_status_t status;
4817
4818 if (! _cairo_scaled_font_is_ft (abstract_font)) {
4819 _cairo_error_throw (CAIRO_STATUS_FONT_TYPE_MISMATCH)do { cairo_status_t status__ = _cairo_error (CAIRO_STATUS_FONT_TYPE_MISMATCH
); (void) status__; } while (0)
;
4820 return NULL((void*)0);
4821 }
4822
4823 if (scaled_font->base.status)
4824 return NULL((void*)0);
4825
4826 face = _cairo_ft_unscaled_font_lock_face (scaled_font->unscaled);
4827 if (unlikely (face == NULL)(__builtin_expect (!!(face == ((void*)0)), 0))) {
4828 status = _cairo_scaled_font_set_error (&scaled_font->base, CAIRO_STATUS_NO_MEMORY);
4829 return NULL((void*)0);
4830 }
4831
4832 status = _cairo_ft_unscaled_font_set_scale (scaled_font->unscaled,
4833 &scaled_font->base.scale);
4834 if (unlikely (status)(__builtin_expect (!!(status), 0))) {
4835 _cairo_ft_unscaled_font_unlock_face (scaled_font->unscaled);
4836 status = _cairo_scaled_font_set_error (&scaled_font->base, status);
4837 return NULL((void*)0);
4838 }
4839
4840 cairo_ft_apply_variations (face, scaled_font);
4841
4842 /* Note: We deliberately release the unscaled font's mutex here,
4843 * so that we are not holding a lock across two separate calls to
4844 * cairo function, (which would give the application some
4845 * opportunity for creating deadlock. This is obviously unsafe,
4846 * but as documented, the user must add manual locking when using
4847 * this function. */
4848 CAIRO_FT_UNLOCK (scaled_font->unscaled)((scaled_font->unscaled)->face_context ? mozilla_UnlockSharedFTFace
((scaled_font->unscaled)->face_context) : (void)pthread_mutex_unlock
(&((scaled_font->unscaled)->mutex)))
;
4849
4850 return face;
4851}
4852
4853/**
4854 * cairo_ft_scaled_font_unlock_face:
4855 * @scaled_font: A #cairo_scaled_font_t from the FreeType font backend. Such an
4856 * object can be created by calling cairo_scaled_font_create() on a
4857 * FreeType backend font face (see cairo_ft_font_face_create_for_pattern(),
4858 * cairo_ft_font_face_create_for_ft_face()).
4859 *
4860 * Releases a face obtained with cairo_ft_scaled_font_lock_face().
4861 *
4862 * Since: 1.0
4863 **/
4864void
4865cairo_ft_scaled_font_unlock_face_moz_cairo_ft_scaled_font_unlock_face (cairo_scaled_font_t *abstract_font)
4866{
4867 cairo_ft_scaled_font_t *scaled_font = (cairo_ft_scaled_font_t *) abstract_font;
4868
4869 if (! _cairo_scaled_font_is_ft (abstract_font)) {
4870 _cairo_error_throw (CAIRO_STATUS_FONT_TYPE_MISMATCH)do { cairo_status_t status__ = _cairo_error (CAIRO_STATUS_FONT_TYPE_MISMATCH
); (void) status__; } while (0)
;
4871 return;
4872 }
4873
4874 if (scaled_font->base.status)
4875 return;
4876
4877 /* Note: We released the unscaled font's mutex at the end of
4878 * cairo_ft_scaled_font_lock_face, so we have to acquire it again
4879 * as _cairo_ft_unscaled_font_unlock_face expects it to be held
4880 * when we call into it. */
4881 CAIRO_FT_LOCK (scaled_font->unscaled)((scaled_font->unscaled)->face_context ? (void)mozilla_LockSharedFTFace
((scaled_font->unscaled)->face_context, ((void*)0)) : (
void)pthread_mutex_lock (&((scaled_font->unscaled)->
mutex)))
;
4882
4883 _cairo_ft_unscaled_font_unlock_face (scaled_font->unscaled);
4884}
4885
4886static cairo_bool_t
4887_cairo_ft_scaled_font_is_vertical (cairo_scaled_font_t *scaled_font)
4888{
4889 cairo_ft_scaled_font_t *ft_scaled_font;
4890
4891 if (!_cairo_scaled_font_is_ft (scaled_font))
4892 return FALSE0;
4893
4894 ft_scaled_font = (cairo_ft_scaled_font_t *) scaled_font;
4895 if (ft_scaled_font->ft_options.load_flags & FT_LOAD_VERTICAL_LAYOUT( 1L << 4 ))
4896 return TRUE1;
4897 return FALSE0;
4898}
4899
4900unsigned int
4901_cairo_ft_scaled_font_get_load_flags (cairo_scaled_font_t *scaled_font)
4902{
4903 cairo_ft_scaled_font_t *ft_scaled_font;
4904
4905 if (! _cairo_scaled_font_is_ft (scaled_font))
4906 return 0;
4907
4908 ft_scaled_font = (cairo_ft_scaled_font_t *) scaled_font;
4909 return ft_scaled_font->ft_options.load_flags;
4910}
4911
4912void
4913_cairo_ft_font_reset_static_data (void)
4914{
4915 _cairo_ft_unscaled_font_map_destroy ();
4916}