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