File: | gfx/cairo/cairo/src/cairo-ft-font.c |
Location: | line 602, column 31 |
Description: | Access to field 'hash_table' results in a dereference of a null pointer (loaded from variable 'font_map') |
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 _BSD_SOURCE1 /* for strdup() */ | |||
42 | #include "cairoint.h" | |||
43 | ||||
44 | #include "cairo-error-private.h" | |||
45 | #include "cairo-ft-private.h" | |||
46 | ||||
47 | #include <float.h> | |||
48 | ||||
49 | #include "cairo-fontconfig-private.h" | |||
50 | ||||
51 | #include <ft2build.h> | |||
52 | #include FT_FREETYPE_H<freetype.h> | |||
53 | #include FT_OUTLINE_H<ftoutln.h> | |||
54 | #include FT_IMAGE_H<ftimage.h> | |||
55 | #include FT_TRUETYPE_TABLES_H<tttables.h> | |||
56 | #if HAVE_FT_GLYPHSLOT_EMBOLDEN1 | |||
57 | #include FT_SYNTHESIS_H<ftsynth.h> | |||
58 | #endif | |||
59 | ||||
60 | #if HAVE_FT_LIBRARY_SETLCDFILTER | |||
61 | #include FT_LCD_FILTER_H<ftlcdfil.h> | |||
62 | #endif | |||
63 | ||||
64 | #define _GNU_SOURCE /* for RTLD_DEFAULT */ | |||
65 | #include <dlfcn.h> | |||
66 | ||||
67 | #ifndef RTLD_DEFAULT((void *) 0) | |||
68 | #define RTLD_DEFAULT((void *) 0) ((void *) 0) | |||
69 | #endif | |||
70 | ||||
71 | /* Fontconfig version older than 2.6 didn't have these options */ | |||
72 | #ifndef FC_LCD_FILTER"lcdfilter" | |||
73 | #define FC_LCD_FILTER"lcdfilter" "lcdfilter" | |||
74 | #endif | |||
75 | /* Some Ubuntu versions defined FC_LCD_FILTER without defining the following */ | |||
76 | #ifndef FC_LCD_NONE0 | |||
77 | #define FC_LCD_NONE0 0 | |||
78 | #define FC_LCD_DEFAULT1 1 | |||
79 | #define FC_LCD_LIGHT2 2 | |||
80 | #define FC_LCD_LEGACY3 3 | |||
81 | #endif | |||
82 | ||||
83 | /* FreeType version older than 2.3.5(?) didn't have these options */ | |||
84 | #ifndef FT_LCD_FILTER_NONE0 | |||
85 | #define FT_LCD_FILTER_NONE0 0 | |||
86 | #define FT_LCD_FILTER_DEFAULT1 1 | |||
87 | #define FT_LCD_FILTER_LIGHT2 2 | |||
88 | #define FT_LCD_FILTER_LEGACY16 16 | |||
89 | #endif | |||
90 | ||||
91 | typedef FT_Error (*setLcdFilterFunc)(FT_Library, int); | |||
92 | static setLcdFilterFunc setLcdFilter; | |||
93 | ||||
94 | #define DOUBLE_TO_26_6(d)((FT_F26Dot6)((d) * 64.0)) ((FT_F26Dot6)((d) * 64.0)) | |||
95 | #define DOUBLE_FROM_26_6(t)((double)(t) / 64.0) ((double)(t) / 64.0) | |||
96 | #define DOUBLE_TO_16_16(d)((FT_Fixed)((d) * 65536.0)) ((FT_Fixed)((d) * 65536.0)) | |||
97 | #define DOUBLE_FROM_16_16(t)((double)(t) / 65536.0) ((double)(t) / 65536.0) | |||
98 | ||||
99 | /* This is the max number of FT_face objects we keep open at once | |||
100 | */ | |||
101 | #define MAX_OPEN_FACES10 10 | |||
102 | /* This is the maximum font size we allow to be passed to FT_Set_Char_Size | |||
103 | */ | |||
104 | #define MAX_FONT_SIZE1000 1000 | |||
105 | ||||
106 | /** | |||
107 | * SECTION:cairo-ft | |||
108 | * @Title: FreeType Fonts | |||
109 | * @Short_Description: Font support for FreeType | |||
110 | * @See_Also: #cairo_font_face_t | |||
111 | * | |||
112 | * The FreeType font backend is primarily used to render text on GNU/Linux | |||
113 | * systems, but can be used on other platforms too. | |||
114 | */ | |||
115 | ||||
116 | /** | |||
117 | * CAIRO_HAS_FT_FONT: | |||
118 | * | |||
119 | * Defined if the FreeType font backend is available. | |||
120 | * This macro can be used to conditionally compile backend-specific code. | |||
121 | */ | |||
122 | ||||
123 | /** | |||
124 | * CAIRO_HAS_FC_FONT: | |||
125 | * | |||
126 | * Defined if the Fontconfig-specific functions of the FreeType font backend | |||
127 | * are available. | |||
128 | * This macro can be used to conditionally compile backend-specific code. | |||
129 | */ | |||
130 | ||||
131 | /* | |||
132 | * The simple 2x2 matrix is converted into separate scale and shape | |||
133 | * factors so that hinting works right | |||
134 | */ | |||
135 | ||||
136 | typedef struct _cairo_ft_font_transform { | |||
137 | double x_scale, y_scale; | |||
138 | double shape[2][2]; | |||
139 | } cairo_ft_font_transform_t; | |||
140 | ||||
141 | /* | |||
142 | * We create an object that corresponds to a single font on the disk; | |||
143 | * (identified by a filename/id pair) these are shared between all | |||
144 | * fonts using that file. For cairo_ft_font_face_create_for_ft_face(), we | |||
145 | * just create a one-off version with a permanent face value. | |||
146 | */ | |||
147 | ||||
148 | typedef struct _cairo_ft_font_face cairo_ft_font_face_t; | |||
149 | ||||
150 | struct _cairo_ft_unscaled_font { | |||
151 | cairo_unscaled_font_t base; | |||
152 | ||||
153 | cairo_bool_t from_face; /* was the FT_Face provided by user? */ | |||
154 | FT_Face face; /* provided or cached face */ | |||
155 | ||||
156 | /* only set if from_face is false */ | |||
157 | char *filename; | |||
158 | int id; | |||
159 | ||||
160 | /* We temporarily scale the unscaled font as needed */ | |||
161 | cairo_bool_t have_scale; | |||
162 | cairo_matrix_t current_scale; | |||
163 | double x_scale; /* Extracted X scale factor */ | |||
164 | double y_scale; /* Extracted Y scale factor */ | |||
165 | cairo_bool_t have_shape; /* true if the current scale has a non-scale component*/ | |||
166 | cairo_matrix_t current_shape; | |||
167 | FT_Matrix Current_Shape; | |||
168 | ||||
169 | cairo_mutex_t mutex; | |||
170 | int lock_count; | |||
171 | ||||
172 | cairo_ft_font_face_t *faces; /* Linked list of faces for this font */ | |||
173 | }; | |||
174 | ||||
175 | static int | |||
176 | _cairo_ft_unscaled_font_keys_equal (const void *key_a, | |||
177 | const void *key_b); | |||
178 | ||||
179 | static void | |||
180 | _cairo_ft_unscaled_font_fini (cairo_ft_unscaled_font_t *unscaled); | |||
181 | ||||
182 | typedef enum _cairo_ft_extra_flags { | |||
183 | CAIRO_FT_OPTIONS_HINT_METRICS = (1 << 0), | |||
184 | CAIRO_FT_OPTIONS_EMBOLDEN = (1 << 1) | |||
185 | } cairo_ft_extra_flags_t; | |||
186 | ||||
187 | typedef struct _cairo_ft_options { | |||
188 | cairo_font_options_t base; | |||
189 | int load_flags; /* flags for FT_Load_Glyph */ | |||
190 | cairo_ft_extra_flags_t extra_flags; /* other flags that affect results */ | |||
191 | } cairo_ft_options_t; | |||
192 | ||||
193 | struct _cairo_ft_font_face { | |||
194 | cairo_font_face_t base; | |||
195 | ||||
196 | cairo_ft_unscaled_font_t *unscaled; | |||
197 | cairo_ft_options_t ft_options; | |||
198 | cairo_ft_font_face_t *next; | |||
199 | ||||
200 | #if CAIRO_HAS_FC_FONT1 | |||
201 | FcPattern *pattern; /* if pattern is set, the above fields will be NULL */ | |||
202 | cairo_font_face_t *resolved_font_face; | |||
203 | FcConfig *resolved_config; | |||
204 | #endif | |||
205 | }; | |||
206 | ||||
207 | static const cairo_unscaled_font_backend_t cairo_ft_unscaled_font_backend; | |||
208 | ||||
209 | #if CAIRO_HAS_FC_FONT1 | |||
210 | static cairo_status_t | |||
211 | _cairo_ft_font_options_substitute (const cairo_font_options_t *options, | |||
212 | FcPattern *pattern); | |||
213 | ||||
214 | static cairo_font_face_t * | |||
215 | _cairo_ft_resolve_pattern (FcPattern *pattern, | |||
216 | const cairo_matrix_t *font_matrix, | |||
217 | const cairo_matrix_t *ctm, | |||
218 | const cairo_font_options_t *options); | |||
219 | ||||
220 | #endif | |||
221 | ||||
222 | /* | |||
223 | * We maintain a hash table to map file/id => #cairo_ft_unscaled_font_t. | |||
224 | * The hash table itself isn't limited in size. However, we limit the | |||
225 | * number of FT_Face objects we keep around; when we've exceeded that | |||
226 | * limit and need to create a new FT_Face, we dump the FT_Face from a | |||
227 | * random #cairo_ft_unscaled_font_t which has an unlocked FT_Face, (if | |||
228 | * there are any). | |||
229 | */ | |||
230 | ||||
231 | typedef struct _cairo_ft_unscaled_font_map { | |||
232 | cairo_hash_table_t *hash_table; | |||
233 | FT_Library ft_library; | |||
234 | int num_open_faces; | |||
235 | } cairo_ft_unscaled_font_map_t; | |||
236 | ||||
237 | static cairo_ft_unscaled_font_map_t *cairo_ft_unscaled_font_map = NULL((void*)0); | |||
238 | ||||
239 | ||||
240 | static void | |||
241 | _font_map_release_face_lock_held (cairo_ft_unscaled_font_map_t *font_map, | |||
242 | cairo_ft_unscaled_font_t *unscaled) | |||
243 | { | |||
244 | if (unscaled->face) { | |||
245 | FT_Done_Face (unscaled->face); | |||
246 | unscaled->face = NULL((void*)0); | |||
247 | unscaled->have_scale = FALSE0; | |||
248 | ||||
249 | font_map->num_open_faces--; | |||
250 | } | |||
251 | } | |||
252 | ||||
253 | static cairo_status_t | |||
254 | _cairo_ft_unscaled_font_map_create (void) | |||
255 | { | |||
256 | cairo_ft_unscaled_font_map_t *font_map; | |||
257 | ||||
258 | /* This function is only intended to be called from | |||
259 | * _cairo_ft_unscaled_font_map_lock. So we'll crash if we can | |||
260 | * detect some other call path. */ | |||
261 | assert (cairo_ft_unscaled_font_map == NULL)do { if (!(cairo_ft_unscaled_font_map == ((void*)0))) fprintf (stderr, "Assertion failed at %s:%d: %s\n", "/home/sylvestre/dev/mozilla/ff/firefox.hg/gfx/cairo/cairo/src/cairo-ft-font.c" , 261, "cairo_ft_unscaled_font_map == NULL"); } while (0); | |||
262 | ||||
263 | font_map = malloc (sizeof (cairo_ft_unscaled_font_map_t)); | |||
264 | if (unlikely (font_map == NULL)(__builtin_expect (__extension__ ({ int _cairo_boolean_var_; if (font_map == ((void*)0)) _cairo_boolean_var_ = 1; else _cairo_boolean_var_ = 0; _cairo_boolean_var_; }), 0))) | |||
265 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); | |||
266 | ||||
267 | font_map->hash_table = | |||
268 | _cairo_hash_table_create (_cairo_ft_unscaled_font_keys_equal); | |||
269 | ||||
270 | if (unlikely (font_map->hash_table == NULL)(__builtin_expect (__extension__ ({ int _cairo_boolean_var_; if (font_map->hash_table == ((void*)0)) _cairo_boolean_var_ = 1; else _cairo_boolean_var_ = 0; _cairo_boolean_var_; }), 0) )) | |||
271 | goto FAIL; | |||
272 | ||||
273 | if (unlikely (FT_Init_FreeType (&font_map->ft_library))(__builtin_expect (__extension__ ({ int _cairo_boolean_var_; if (FT_Init_FreeType (&font_map->ft_library)) _cairo_boolean_var_ = 1; else _cairo_boolean_var_ = 0; _cairo_boolean_var_; }), 0 ))) | |||
274 | goto FAIL; | |||
275 | ||||
276 | font_map->num_open_faces = 0; | |||
277 | ||||
278 | cairo_ft_unscaled_font_map = font_map; | |||
279 | return CAIRO_STATUS_SUCCESS; | |||
280 | ||||
281 | FAIL: | |||
282 | if (font_map->hash_table) | |||
283 | _cairo_hash_table_destroy (font_map->hash_table); | |||
284 | free (font_map); | |||
285 | ||||
286 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); | |||
287 | } | |||
288 | ||||
289 | ||||
290 | static void | |||
291 | _cairo_ft_unscaled_font_map_pluck_entry (void *entry, void *closure) | |||
292 | { | |||
293 | cairo_ft_unscaled_font_t *unscaled = entry; | |||
294 | cairo_ft_unscaled_font_map_t *font_map = closure; | |||
295 | ||||
296 | _cairo_hash_table_remove (font_map->hash_table, | |||
297 | &unscaled->base.hash_entry); | |||
298 | ||||
299 | if (! unscaled->from_face) | |||
300 | _font_map_release_face_lock_held (font_map, unscaled); | |||
301 | ||||
302 | _cairo_ft_unscaled_font_fini (unscaled); | |||
303 | free (unscaled); | |||
304 | } | |||
305 | ||||
306 | static void | |||
307 | _cairo_ft_unscaled_font_map_destroy (void) | |||
308 | { | |||
309 | cairo_ft_unscaled_font_map_t *font_map; | |||
310 | ||||
311 | CAIRO_MUTEX_LOCK (_cairo_ft_unscaled_font_map_mutex)pthread_mutex_lock (&(_cairo_ft_unscaled_font_map_mutex)); | |||
312 | font_map = cairo_ft_unscaled_font_map; | |||
313 | cairo_ft_unscaled_font_map = NULL((void*)0); | |||
314 | CAIRO_MUTEX_UNLOCK (_cairo_ft_unscaled_font_map_mutex)pthread_mutex_unlock (&(_cairo_ft_unscaled_font_map_mutex )); | |||
315 | ||||
316 | if (font_map != NULL((void*)0)) { | |||
317 | _cairo_hash_table_foreach (font_map->hash_table, | |||
318 | _cairo_ft_unscaled_font_map_pluck_entry, | |||
319 | font_map); | |||
320 | assert (font_map->num_open_faces == 0)do { if (!(font_map->num_open_faces == 0)) fprintf(stderr, "Assertion failed at %s:%d: %s\n", "/home/sylvestre/dev/mozilla/ff/firefox.hg/gfx/cairo/cairo/src/cairo-ft-font.c" , 320, "font_map->num_open_faces == 0"); } while (0); | |||
321 | ||||
322 | FT_Done_FreeType (font_map->ft_library); | |||
323 | ||||
324 | _cairo_hash_table_destroy (font_map->hash_table); | |||
325 | ||||
326 | free (font_map); | |||
327 | } | |||
328 | } | |||
329 | ||||
330 | static cairo_ft_unscaled_font_map_t * | |||
331 | _cairo_ft_unscaled_font_map_lock (void) | |||
332 | { | |||
333 | CAIRO_MUTEX_LOCK (_cairo_ft_unscaled_font_map_mutex)pthread_mutex_lock (&(_cairo_ft_unscaled_font_map_mutex)); | |||
334 | ||||
335 | if (unlikely (cairo_ft_unscaled_font_map == NULL)(__builtin_expect (__extension__ ({ int _cairo_boolean_var_; if (cairo_ft_unscaled_font_map == ((void*)0)) _cairo_boolean_var_ = 1; else _cairo_boolean_var_ = 0; _cairo_boolean_var_; }), 0 ))) { | |||
336 | if (unlikely (_cairo_ft_unscaled_font_map_create ())(__builtin_expect (__extension__ ({ int _cairo_boolean_var_; if (_cairo_ft_unscaled_font_map_create ()) _cairo_boolean_var_ = 1; else _cairo_boolean_var_ = 0; _cairo_boolean_var_; }), 0) )) { | |||
337 | CAIRO_MUTEX_UNLOCK (_cairo_ft_unscaled_font_map_mutex)pthread_mutex_unlock (&(_cairo_ft_unscaled_font_map_mutex )); | |||
338 | return NULL((void*)0); | |||
339 | } | |||
340 | } | |||
341 | ||||
342 | return cairo_ft_unscaled_font_map; | |||
343 | } | |||
344 | ||||
345 | static void | |||
346 | _cairo_ft_unscaled_font_map_unlock (void) | |||
347 | { | |||
348 | CAIRO_MUTEX_UNLOCK (_cairo_ft_unscaled_font_map_mutex)pthread_mutex_unlock (&(_cairo_ft_unscaled_font_map_mutex )); | |||
349 | } | |||
350 | ||||
351 | static void | |||
352 | _cairo_ft_unscaled_font_init_key (cairo_ft_unscaled_font_t *key, | |||
353 | cairo_bool_t from_face, | |||
354 | char *filename, | |||
355 | int id, | |||
356 | FT_Face face) | |||
357 | { | |||
358 | unsigned long hash; | |||
359 | ||||
360 | key->from_face = from_face; | |||
361 | key->filename = filename; | |||
362 | key->id = id; | |||
363 | key->face = face; | |||
364 | ||||
365 | hash = _cairo_hash_string (filename); | |||
366 | /* the constants are just arbitrary primes */ | |||
367 | hash += ((unsigned long) id) * 1607; | |||
368 | hash += ((unsigned long) face) * 2137; | |||
369 | ||||
370 | key->base.hash_entry.hash = hash; | |||
371 | } | |||
372 | ||||
373 | /** | |||
374 | * _cairo_ft_unscaled_font_init: | |||
375 | * | |||
376 | * Initialize a #cairo_ft_unscaled_font_t. | |||
377 | * | |||
378 | * There are two basic flavors of #cairo_ft_unscaled_font_t, one | |||
379 | * created from an FT_Face and the other created from a filename/id | |||
380 | * pair. These two flavors are identified as from_face and !from_face. | |||
381 | * | |||
382 | * To initialize a from_face font, pass filename==%NULL, id=0 and the | |||
383 | * desired face. | |||
384 | * | |||
385 | * To initialize a !from_face font, pass the filename/id as desired | |||
386 | * and face==%NULL. | |||
387 | * | |||
388 | * Note that the code handles these two flavors in very distinct | |||
389 | * ways. For example there is a hash_table mapping | |||
390 | * filename/id->#cairo_unscaled_font_t in the !from_face case, but no | |||
391 | * parallel in the from_face case, (where the calling code would have | |||
392 | * to do its own mapping to ensure similar sharing). | |||
393 | **/ | |||
394 | static cairo_status_t | |||
395 | _cairo_ft_unscaled_font_init (cairo_ft_unscaled_font_t *unscaled, | |||
396 | cairo_bool_t from_face, | |||
397 | const char *filename, | |||
398 | int id, | |||
399 | FT_Face face) | |||
400 | { | |||
401 | _cairo_unscaled_font_init (&unscaled->base, | |||
402 | &cairo_ft_unscaled_font_backend); | |||
403 | ||||
404 | if (from_face) { | |||
405 | unscaled->from_face = TRUE1; | |||
406 | _cairo_ft_unscaled_font_init_key (unscaled, TRUE1, NULL((void*)0), 0, face); | |||
407 | } else { | |||
408 | char *filename_copy; | |||
409 | ||||
410 | unscaled->from_face = FALSE0; | |||
411 | unscaled->face = NULL((void*)0); | |||
412 | ||||
413 | filename_copy = strdup (filename); | |||
414 | if (unlikely (filename_copy == NULL)(__builtin_expect (__extension__ ({ int _cairo_boolean_var_; if (filename_copy == ((void*)0)) _cairo_boolean_var_ = 1; else _cairo_boolean_var_ = 0; _cairo_boolean_var_; }), 0))) | |||
415 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); | |||
416 | ||||
417 | _cairo_ft_unscaled_font_init_key (unscaled, FALSE0, filename_copy, id, NULL((void*)0)); | |||
418 | } | |||
419 | ||||
420 | unscaled->have_scale = FALSE0; | |||
421 | CAIRO_MUTEX_INIT (unscaled->mutex)do { cairo_mutex_t _tmp_mutex = { { 0, 0, 0, 0, 0, 0, { 0, 0 } } }; memcpy (&(unscaled->mutex), &_tmp_mutex, sizeof (_tmp_mutex)); } while (0); | |||
422 | unscaled->lock_count = 0; | |||
423 | ||||
424 | unscaled->faces = NULL((void*)0); | |||
425 | ||||
426 | return CAIRO_STATUS_SUCCESS; | |||
427 | } | |||
428 | ||||
429 | /** | |||
430 | * _cairo_ft_unscaled_font_fini: | |||
431 | * | |||
432 | * Free all data associated with a #cairo_ft_unscaled_font_t. | |||
433 | * | |||
434 | * CAUTION: The unscaled->face field must be %NULL before calling this | |||
435 | * function. This is because the #cairo_ft_unscaled_font_t_map keeps a | |||
436 | * count of these faces (font_map->num_open_faces) so it maintains the | |||
437 | * unscaled->face field while it has its lock held. See | |||
438 | * _font_map_release_face_lock_held(). | |||
439 | **/ | |||
440 | static void | |||
441 | _cairo_ft_unscaled_font_fini (cairo_ft_unscaled_font_t *unscaled) | |||
442 | { | |||
443 | assert (unscaled->face == NULL)do { if (!(unscaled->face == ((void*)0))) fprintf(stderr, "Assertion failed at %s:%d: %s\n" , "/home/sylvestre/dev/mozilla/ff/firefox.hg/gfx/cairo/cairo/src/cairo-ft-font.c" , 443, "unscaled->face == NULL"); } while (0); | |||
444 | ||||
445 | if (unscaled->filename) { | |||
446 | free (unscaled->filename); | |||
447 | unscaled->filename = NULL((void*)0); | |||
448 | } | |||
449 | ||||
450 | CAIRO_MUTEX_FINI (unscaled->mutex)pthread_mutex_destroy (&(unscaled->mutex)); | |||
451 | } | |||
452 | ||||
453 | static int | |||
454 | _cairo_ft_unscaled_font_keys_equal (const void *key_a, | |||
455 | const void *key_b) | |||
456 | { | |||
457 | const cairo_ft_unscaled_font_t *unscaled_a = key_a; | |||
458 | const cairo_ft_unscaled_font_t *unscaled_b = key_b; | |||
459 | ||||
460 | if (unscaled_a->id == unscaled_b->id && | |||
461 | unscaled_a->from_face == unscaled_b->from_face) | |||
462 | { | |||
463 | if (unscaled_a->from_face) | |||
464 | return unscaled_a->face == unscaled_b->face; | |||
465 | ||||
466 | if (unscaled_a->filename == NULL((void*)0) && unscaled_b->filename == NULL((void*)0)) | |||
467 | return TRUE1; | |||
468 | else if (unscaled_a->filename == NULL((void*)0) || unscaled_b->filename == NULL((void*)0)) | |||
469 | return FALSE0; | |||
470 | else | |||
471 | return (strcmp (unscaled_a->filename, unscaled_b->filename) == 0); | |||
472 | } | |||
473 | ||||
474 | return FALSE0; | |||
475 | } | |||
476 | ||||
477 | /* Finds or creates a #cairo_ft_unscaled_font_t for the filename/id from | |||
478 | * pattern. Returns a new reference to the unscaled font. | |||
479 | */ | |||
480 | static cairo_status_t | |||
481 | _cairo_ft_unscaled_font_create_internal (cairo_bool_t from_face, | |||
482 | char *filename, | |||
483 | int id, | |||
484 | FT_Face font_face, | |||
485 | cairo_ft_unscaled_font_t **out) | |||
486 | { | |||
487 | cairo_ft_unscaled_font_t key, *unscaled; | |||
488 | cairo_ft_unscaled_font_map_t *font_map; | |||
489 | cairo_status_t status; | |||
490 | ||||
491 | font_map = _cairo_ft_unscaled_font_map_lock (); | |||
492 | if (unlikely (font_map == NULL)(__builtin_expect (__extension__ ({ int _cairo_boolean_var_; if (font_map == ((void*)0)) _cairo_boolean_var_ = 1; else _cairo_boolean_var_ = 0; _cairo_boolean_var_; }), 0))) | |||
493 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); | |||
494 | ||||
495 | _cairo_ft_unscaled_font_init_key (&key, from_face, filename, id, font_face); | |||
496 | ||||
497 | /* Return existing unscaled font if it exists in the hash table. */ | |||
498 | unscaled = _cairo_hash_table_lookup (font_map->hash_table, | |||
499 | &key.base.hash_entry); | |||
500 | if (unscaled != NULL((void*)0)) { | |||
501 | _cairo_unscaled_font_reference (&unscaled->base); | |||
502 | goto DONE; | |||
503 | } | |||
504 | ||||
505 | /* Otherwise create it and insert into hash table. */ | |||
506 | unscaled = malloc (sizeof (cairo_ft_unscaled_font_t)); | |||
507 | if (unlikely (unscaled == NULL)(__builtin_expect (__extension__ ({ int _cairo_boolean_var_; if (unscaled == ((void*)0)) _cairo_boolean_var_ = 1; else _cairo_boolean_var_ = 0; _cairo_boolean_var_; }), 0))) { | |||
508 | status = _cairo_error (CAIRO_STATUS_NO_MEMORY); | |||
509 | goto UNWIND_FONT_MAP_LOCK; | |||
510 | } | |||
511 | ||||
512 | status = _cairo_ft_unscaled_font_init (unscaled, from_face, filename, id, font_face); | |||
513 | if (unlikely (status)(__builtin_expect (__extension__ ({ int _cairo_boolean_var_; if (status) _cairo_boolean_var_ = 1; else _cairo_boolean_var_ = 0; _cairo_boolean_var_; }), 0))) | |||
514 | goto UNWIND_UNSCALED_MALLOC; | |||
515 | ||||
516 | assert (unscaled->base.hash_entry.hash == key.base.hash_entry.hash)do { if (!(unscaled->base.hash_entry.hash == key.base.hash_entry .hash)) fprintf(stderr, "Assertion failed at %s:%d: %s\n", "/home/sylvestre/dev/mozilla/ff/firefox.hg/gfx/cairo/cairo/src/cairo-ft-font.c" , 516, "unscaled->base.hash_entry.hash == key.base.hash_entry.hash" ); } while (0); | |||
517 | status = _cairo_hash_table_insert (font_map->hash_table, | |||
518 | &unscaled->base.hash_entry); | |||
519 | if (unlikely (status)(__builtin_expect (__extension__ ({ int _cairo_boolean_var_; if (status) _cairo_boolean_var_ = 1; else _cairo_boolean_var_ = 0; _cairo_boolean_var_; }), 0))) | |||
520 | goto UNWIND_UNSCALED_FONT_INIT; | |||
521 | ||||
522 | DONE: | |||
523 | _cairo_ft_unscaled_font_map_unlock (); | |||
524 | *out = unscaled; | |||
525 | return CAIRO_STATUS_SUCCESS; | |||
526 | ||||
527 | UNWIND_UNSCALED_FONT_INIT: | |||
528 | _cairo_ft_unscaled_font_fini (unscaled); | |||
529 | UNWIND_UNSCALED_MALLOC: | |||
530 | free (unscaled); | |||
531 | UNWIND_FONT_MAP_LOCK: | |||
532 | _cairo_ft_unscaled_font_map_unlock (); | |||
533 | return status; | |||
534 | } | |||
535 | ||||
536 | ||||
537 | #if CAIRO_HAS_FC_FONT1 | |||
538 | static cairo_status_t | |||
539 | _cairo_ft_unscaled_font_create_for_pattern (FcPattern *pattern, | |||
540 | cairo_ft_unscaled_font_t **out) | |||
541 | { | |||
542 | FT_Face font_face = NULL((void*)0); | |||
543 | char *filename = NULL((void*)0); | |||
544 | int id = 0; | |||
545 | FcResult ret; | |||
546 | ||||
547 | ret = FcPatternGetFTFace (pattern, FC_FT_FACE"ftface", 0, &font_face); | |||
548 | if (ret == FcResultMatch) | |||
549 | goto DONE; | |||
550 | if (ret == FcResultOutOfMemory) | |||
551 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); | |||
552 | ||||
553 | ret = FcPatternGetString (pattern, FC_FILE"file", 0, (FcChar8 **) &filename); | |||
554 | if (ret == FcResultOutOfMemory) | |||
555 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); | |||
556 | if (ret == FcResultMatch) { | |||
557 | /* If FC_INDEX is not set, we just use 0 */ | |||
558 | ret = FcPatternGetInteger (pattern, FC_INDEX"index", 0, &id); | |||
559 | if (ret == FcResultOutOfMemory) | |||
560 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); | |||
561 | ||||
562 | goto DONE; | |||
563 | } | |||
564 | ||||
565 | /* The pattern contains neither a face nor a filename, resolve it later. */ | |||
566 | *out = NULL((void*)0); | |||
567 | return CAIRO_STATUS_SUCCESS; | |||
568 | ||||
569 | DONE: | |||
570 | return _cairo_ft_unscaled_font_create_internal (font_face != NULL((void*)0), | |||
571 | filename, id, font_face, | |||
572 | out); | |||
573 | } | |||
574 | #endif | |||
575 | ||||
576 | static cairo_status_t | |||
577 | _cairo_ft_unscaled_font_create_from_face (FT_Face face, | |||
578 | cairo_ft_unscaled_font_t **out) | |||
579 | { | |||
580 | return _cairo_ft_unscaled_font_create_internal (TRUE1, NULL((void*)0), 0, face, out); | |||
581 | } | |||
582 | ||||
583 | static void | |||
584 | _cairo_ft_unscaled_font_destroy (void *abstract_font) | |||
585 | { | |||
586 | cairo_ft_unscaled_font_t *unscaled = abstract_font; | |||
587 | cairo_ft_unscaled_font_map_t *font_map; | |||
588 | ||||
589 | if (unscaled == NULL((void*)0)) | |||
| ||||
590 | return; | |||
591 | ||||
592 | font_map = _cairo_ft_unscaled_font_map_lock (); | |||
593 | /* All created objects must have been mapped in the font map. */ | |||
594 | assert (font_map != NULL)do { if (!(font_map != ((void*)0))) fprintf(stderr, "Assertion failed at %s:%d: %s\n" , "/home/sylvestre/dev/mozilla/ff/firefox.hg/gfx/cairo/cairo/src/cairo-ft-font.c" , 594, "font_map != NULL"); } while (0); | |||
595 | ||||
596 | if (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&unscaled->base.ref_count)((*&(&unscaled->base.ref_count)->ref_count) > 0)) { | |||
597 | /* somebody recreated the font whilst we waited for the lock */ | |||
598 | _cairo_ft_unscaled_font_map_unlock (); | |||
599 | return; | |||
600 | } | |||
601 | ||||
602 | _cairo_hash_table_remove (font_map->hash_table, | |||
| ||||
603 | &unscaled->base.hash_entry); | |||
604 | ||||
605 | if (unscaled->from_face) { | |||
606 | /* See comments in _ft_font_face_destroy about the "zombie" state | |||
607 | * for a _ft_font_face. | |||
608 | */ | |||
609 | if (unscaled->faces && unscaled->faces->unscaled == NULL((void*)0)) { | |||
610 | assert (unscaled->faces->next == NULL)do { if (!(unscaled->faces->next == ((void*)0))) fprintf (stderr, "Assertion failed at %s:%d: %s\n", "/home/sylvestre/dev/mozilla/ff/firefox.hg/gfx/cairo/cairo/src/cairo-ft-font.c" , 610, "unscaled->faces->next == NULL"); } while (0); | |||
611 | cairo_font_face_destroy_moz_cairo_font_face_destroy (&unscaled->faces->base); | |||
612 | } | |||
613 | } else { | |||
614 | _font_map_release_face_lock_held (font_map, unscaled); | |||
615 | } | |||
616 | unscaled->face = NULL((void*)0); | |||
617 | ||||
618 | _cairo_ft_unscaled_font_map_unlock (); | |||
619 | ||||
620 | _cairo_ft_unscaled_font_fini (unscaled); | |||
621 | } | |||
622 | ||||
623 | static cairo_bool_t | |||
624 | _has_unlocked_face (const void *entry) | |||
625 | { | |||
626 | const cairo_ft_unscaled_font_t *unscaled = entry; | |||
627 | ||||
628 | return (!unscaled->from_face && unscaled->lock_count == 0 && unscaled->face); | |||
629 | } | |||
630 | ||||
631 | /* Ensures that an unscaled font has a face object. If we exceed | |||
632 | * MAX_OPEN_FACES, try to close some. | |||
633 | * | |||
634 | * This differs from _cairo_ft_scaled_font_lock_face in that it doesn't | |||
635 | * set the scale on the face, but just returns it at the last scale. | |||
636 | */ | |||
637 | cairo_warn FT_Face | |||
638 | _cairo_ft_unscaled_font_lock_face (cairo_ft_unscaled_font_t *unscaled) | |||
639 | { | |||
640 | cairo_ft_unscaled_font_map_t *font_map; | |||
641 | FT_Face face = NULL((void*)0); | |||
642 | ||||
643 | CAIRO_MUTEX_LOCK (unscaled->mutex)pthread_mutex_lock (&(unscaled->mutex)); | |||
644 | unscaled->lock_count++; | |||
645 | ||||
646 | if (unscaled->face) | |||
647 | return unscaled->face; | |||
648 | ||||
649 | /* If this unscaled font was created from an FT_Face then we just | |||
650 | * returned it above. */ | |||
651 | assert (!unscaled->from_face)do { if (!(!unscaled->from_face)) fprintf(stderr, "Assertion failed at %s:%d: %s\n" , "/home/sylvestre/dev/mozilla/ff/firefox.hg/gfx/cairo/cairo/src/cairo-ft-font.c" , 651, "!unscaled->from_face"); } while (0); | |||
652 | ||||
653 | font_map = _cairo_ft_unscaled_font_map_lock (); | |||
654 | { | |||
655 | assert (font_map != NULL)do { if (!(font_map != ((void*)0))) fprintf(stderr, "Assertion failed at %s:%d: %s\n" , "/home/sylvestre/dev/mozilla/ff/firefox.hg/gfx/cairo/cairo/src/cairo-ft-font.c" , 655, "font_map != NULL"); } while (0); | |||
656 | ||||
657 | while (font_map->num_open_faces >= MAX_OPEN_FACES10) | |||
658 | { | |||
659 | cairo_ft_unscaled_font_t *entry; | |||
660 | ||||
661 | entry = _cairo_hash_table_random_entry (font_map->hash_table, | |||
662 | _has_unlocked_face); | |||
663 | if (entry == NULL((void*)0)) | |||
664 | break; | |||
665 | ||||
666 | _font_map_release_face_lock_held (font_map, entry); | |||
667 | } | |||
668 | } | |||
669 | _cairo_ft_unscaled_font_map_unlock (); | |||
670 | ||||
671 | if (FT_New_Face (font_map->ft_library, | |||
672 | unscaled->filename, | |||
673 | unscaled->id, | |||
674 | &face) != FT_Err_Ok) | |||
675 | { | |||
676 | unscaled->lock_count--; | |||
677 | CAIRO_MUTEX_UNLOCK (unscaled->mutex)pthread_mutex_unlock (&(unscaled->mutex)); | |||
678 | _cairo_error_throw (CAIRO_STATUS_NO_MEMORY)do { cairo_status_t status__ = _cairo_error (CAIRO_STATUS_NO_MEMORY ); (void) status__; } while (0); | |||
679 | return NULL((void*)0); | |||
680 | } | |||
681 | ||||
682 | unscaled->face = face; | |||
683 | ||||
684 | font_map->num_open_faces++; | |||
685 | ||||
686 | return face; | |||
687 | } | |||
688 | ||||
689 | ||||
690 | /* Unlock unscaled font locked with _cairo_ft_unscaled_font_lock_face | |||
691 | */ | |||
692 | void | |||
693 | _cairo_ft_unscaled_font_unlock_face (cairo_ft_unscaled_font_t *unscaled) | |||
694 | { | |||
695 | assert (unscaled->lock_count > 0)do { if (!(unscaled->lock_count > 0)) fprintf(stderr, "Assertion failed at %s:%d: %s\n" , "/home/sylvestre/dev/mozilla/ff/firefox.hg/gfx/cairo/cairo/src/cairo-ft-font.c" , 695, "unscaled->lock_count > 0"); } while (0); | |||
696 | ||||
697 | unscaled->lock_count--; | |||
698 | ||||
699 | CAIRO_MUTEX_UNLOCK (unscaled->mutex)pthread_mutex_unlock (&(unscaled->mutex)); | |||
700 | } | |||
701 | ||||
702 | ||||
703 | static cairo_status_t | |||
704 | _compute_transform (cairo_ft_font_transform_t *sf, | |||
705 | cairo_matrix_t *scale) | |||
706 | { | |||
707 | cairo_status_t status; | |||
708 | double x_scale, y_scale; | |||
709 | cairo_matrix_t normalized = *scale; | |||
710 | ||||
711 | /* The font matrix has x and y "scale" components which we extract and | |||
712 | * use as character scale values. These influence the way freetype | |||
713 | * chooses hints, as well as selecting different bitmaps in | |||
714 | * hand-rendered fonts. We also copy the normalized matrix to | |||
715 | * freetype's transformation. | |||
716 | */ | |||
717 | ||||
718 | status = _cairo_matrix_compute_basis_scale_factors (scale, | |||
719 | &x_scale, &y_scale, | |||
720 | 1); | |||
721 | if (unlikely (status)(__builtin_expect (__extension__ ({ int _cairo_boolean_var_; if (status) _cairo_boolean_var_ = 1; else _cairo_boolean_var_ = 0; _cairo_boolean_var_; }), 0))) | |||
722 | return status; | |||
723 | ||||
724 | /* FreeType docs say this about x_scale and y_scale: | |||
725 | * "A character width or height smaller than 1pt is set to 1pt;" | |||
726 | * So, we cap them from below at 1.0 and let the FT transform | |||
727 | * take care of sub-1.0 scaling. */ | |||
728 | if (x_scale < 1.0) | |||
729 | x_scale = 1.0; | |||
730 | if (y_scale < 1.0) | |||
731 | y_scale = 1.0; | |||
732 | ||||
733 | sf->x_scale = x_scale; | |||
734 | sf->y_scale = y_scale; | |||
735 | ||||
736 | cairo_matrix_scale_moz_cairo_matrix_scale (&normalized, 1.0 / x_scale, 1.0 / y_scale); | |||
737 | ||||
738 | _cairo_matrix_get_affine (&normalized, | |||
739 | &sf->shape[0][0], &sf->shape[0][1], | |||
740 | &sf->shape[1][0], &sf->shape[1][1], | |||
741 | NULL((void*)0), NULL((void*)0)); | |||
742 | ||||
743 | return CAIRO_STATUS_SUCCESS; | |||
744 | } | |||
745 | ||||
746 | /* Temporarily scales an unscaled font to the give scale. We catch | |||
747 | * scaling to the same size, since changing a FT_Face is expensive. | |||
748 | */ | |||
749 | static cairo_status_t | |||
750 | _cairo_ft_unscaled_font_set_scale (cairo_ft_unscaled_font_t *unscaled, | |||
751 | cairo_matrix_t *scale) | |||
752 | { | |||
753 | cairo_status_t status; | |||
754 | cairo_ft_font_transform_t sf; | |||
755 | FT_Matrix mat; | |||
756 | FT_Error error; | |||
757 | ||||
758 | assert (unscaled->face != NULL)do { if (!(unscaled->face != ((void*)0))) fprintf(stderr, "Assertion failed at %s:%d: %s\n" , "/home/sylvestre/dev/mozilla/ff/firefox.hg/gfx/cairo/cairo/src/cairo-ft-font.c" , 758, "unscaled->face != NULL"); } while (0); | |||
759 | ||||
760 | if (unscaled->have_scale && | |||
761 | scale->xx == unscaled->current_scale.xx && | |||
762 | scale->yx == unscaled->current_scale.yx && | |||
763 | scale->xy == unscaled->current_scale.xy && | |||
764 | scale->yy == unscaled->current_scale.yy) | |||
765 | return CAIRO_STATUS_SUCCESS; | |||
766 | ||||
767 | unscaled->have_scale = TRUE1; | |||
768 | unscaled->current_scale = *scale; | |||
769 | ||||
770 | status = _compute_transform (&sf, scale); | |||
771 | if (unlikely (status)(__builtin_expect (__extension__ ({ int _cairo_boolean_var_; if (status) _cairo_boolean_var_ = 1; else _cairo_boolean_var_ = 0; _cairo_boolean_var_; }), 0))) | |||
772 | return status; | |||
773 | ||||
774 | unscaled->x_scale = sf.x_scale; | |||
775 | unscaled->y_scale = sf.y_scale; | |||
776 | ||||
777 | mat.xx = DOUBLE_TO_16_16(sf.shape[0][0])((FT_Fixed)((sf.shape[0][0]) * 65536.0)); | |||
778 | mat.yx = - DOUBLE_TO_16_16(sf.shape[0][1])((FT_Fixed)((sf.shape[0][1]) * 65536.0)); | |||
779 | mat.xy = - DOUBLE_TO_16_16(sf.shape[1][0])((FT_Fixed)((sf.shape[1][0]) * 65536.0)); | |||
780 | mat.yy = DOUBLE_TO_16_16(sf.shape[1][1])((FT_Fixed)((sf.shape[1][1]) * 65536.0)); | |||
781 | ||||
782 | unscaled->have_shape = (mat.xx != 0x10000 || | |||
783 | mat.yx != 0x00000 || | |||
784 | mat.xy != 0x00000 || | |||
785 | mat.yy != 0x10000); | |||
786 | ||||
787 | unscaled->Current_Shape = mat; | |||
788 | cairo_matrix_init_moz_cairo_matrix_init (&unscaled->current_shape, | |||
789 | sf.shape[0][0], sf.shape[0][1], | |||
790 | sf.shape[1][0], sf.shape[1][1], | |||
791 | 0.0, 0.0); | |||
792 | ||||
793 | FT_Set_Transform(unscaled->face, &mat, NULL((void*)0)); | |||
794 | ||||
795 | if ((unscaled->face->face_flags & FT_FACE_FLAG_SCALABLE( 1L << 0 )) != 0) { | |||
796 | double x_scale = MIN(sf.x_scale, MAX_FONT_SIZE)((sf.x_scale) < (1000) ? (sf.x_scale) : (1000)); | |||
797 | double y_scale = MIN(sf.y_scale, MAX_FONT_SIZE)((sf.y_scale) < (1000) ? (sf.y_scale) : (1000)); | |||
798 | error = FT_Set_Char_Size (unscaled->face, | |||
799 | x_scale * 64.0 + .5, | |||
800 | y_scale * 64.0 + .5, | |||
801 | 0, 0); | |||
802 | if (error) | |||
803 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); | |||
804 | } else { | |||
805 | double min_distance = DBL_MAX1.7976931348623157e+308; | |||
806 | int i; | |||
807 | int best_i = 0; | |||
808 | ||||
809 | for (i = 0; i < unscaled->face->num_fixed_sizes; i++) { | |||
810 | #if HAVE_FT_BITMAP_SIZE_Y_PPEM1 | |||
811 | double size = unscaled->face->available_sizes[i].y_ppem / 64.; | |||
812 | #else | |||
813 | double size = unscaled->face->available_sizes[i].height; | |||
814 | #endif | |||
815 | double distance = fabs (size - sf.y_scale); | |||
816 | ||||
817 | if (distance <= min_distance) { | |||
818 | min_distance = distance; | |||
819 | best_i = i; | |||
820 | } | |||
821 | } | |||
822 | #if HAVE_FT_BITMAP_SIZE_Y_PPEM1 | |||
823 | error = FT_Set_Char_Size (unscaled->face, | |||
824 | unscaled->face->available_sizes[best_i].x_ppem, | |||
825 | unscaled->face->available_sizes[best_i].y_ppem, | |||
826 | 0, 0); | |||
827 | if (error) | |||
828 | #endif | |||
829 | error = FT_Set_Pixel_Sizes (unscaled->face, | |||
830 | unscaled->face->available_sizes[best_i].width, | |||
831 | unscaled->face->available_sizes[best_i].height); | |||
832 | if (error) | |||
833 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); | |||
834 | } | |||
835 | ||||
836 | return CAIRO_STATUS_SUCCESS; | |||
837 | } | |||
838 | ||||
839 | /* we sometimes need to convert the glyph bitmap in a FT_GlyphSlot | |||
840 | * into a different format. For example, we want to convert a | |||
841 | * FT_PIXEL_MODE_LCD or FT_PIXEL_MODE_LCD_V bitmap into a 32-bit | |||
842 | * ARGB or ABGR bitmap. | |||
843 | * | |||
844 | * this function prepares a target descriptor for this operation. | |||
845 | * | |||
846 | * input :: target bitmap descriptor. The function will set its | |||
847 | * 'width', 'rows' and 'pitch' fields, and only these | |||
848 | * | |||
849 | * slot :: the glyph slot containing the source bitmap. this | |||
850 | * function assumes that slot->format == FT_GLYPH_FORMAT_BITMAP | |||
851 | * | |||
852 | * mode :: the requested final rendering mode. supported values are | |||
853 | * MONO, NORMAL (i.e. gray), LCD and LCD_V | |||
854 | * | |||
855 | * the function returns the size in bytes of the corresponding buffer, | |||
856 | * it's up to the caller to allocate the corresponding memory block | |||
857 | * before calling _fill_xrender_bitmap | |||
858 | * | |||
859 | * it also returns -1 in case of error (e.g. incompatible arguments, | |||
860 | * like trying to convert a gray bitmap into a monochrome one) | |||
861 | */ | |||
862 | static int | |||
863 | _compute_xrender_bitmap_size(FT_Bitmap *target, | |||
864 | FT_GlyphSlot slot, | |||
865 | FT_Render_Mode mode) | |||
866 | { | |||
867 | FT_Bitmap *ftbit; | |||
868 | int width, height, pitch; | |||
869 | ||||
870 | if (slot->format != FT_GLYPH_FORMAT_BITMAP) | |||
871 | return -1; | |||
872 | ||||
873 | /* compute the size of the final bitmap */ | |||
874 | ftbit = &slot->bitmap; | |||
875 | ||||
876 | width = ftbit->width; | |||
877 | height = ftbit->rows; | |||
878 | pitch = (width + 3) & ~3; | |||
879 | ||||
880 | switch (ftbit->pixel_mode) { | |||
881 | case FT_PIXEL_MODE_MONO: | |||
882 | if (mode == FT_RENDER_MODE_MONO) { | |||
883 | pitch = (((width + 31) & ~31) >> 3); | |||
884 | break; | |||
885 | } | |||
886 | /* fall-through */ | |||
887 | ||||
888 | case FT_PIXEL_MODE_GRAY: | |||
889 | if (mode == FT_RENDER_MODE_LCD || | |||
890 | mode == FT_RENDER_MODE_LCD_V) | |||
891 | { | |||
892 | /* each pixel is replicated into a 32-bit ARGB value */ | |||
893 | pitch = width * 4; | |||
894 | } | |||
895 | break; | |||
896 | ||||
897 | case FT_PIXEL_MODE_LCD: | |||
898 | if (mode != FT_RENDER_MODE_LCD) | |||
899 | return -1; | |||
900 | ||||
901 | /* horz pixel triplets are packed into 32-bit ARGB values */ | |||
902 | width /= 3; | |||
903 | pitch = width * 4; | |||
904 | break; | |||
905 | ||||
906 | case FT_PIXEL_MODE_LCD_V: | |||
907 | if (mode != FT_RENDER_MODE_LCD_V) | |||
908 | return -1; | |||
909 | ||||
910 | /* vert pixel triplets are packed into 32-bit ARGB values */ | |||
911 | height /= 3; | |||
912 | pitch = width * 4; | |||
913 | break; | |||
914 | ||||
915 | default: /* unsupported source format */ | |||
916 | return -1; | |||
917 | } | |||
918 | ||||
919 | target->width = width; | |||
920 | target->rows = height; | |||
921 | target->pitch = pitch; | |||
922 | target->buffer = NULL((void*)0); | |||
923 | ||||
924 | return pitch * height; | |||
925 | } | |||
926 | ||||
927 | /* this functions converts the glyph bitmap found in a FT_GlyphSlot | |||
928 | * into a different format (see _compute_xrender_bitmap_size) | |||
929 | * | |||
930 | * you should call this function after _compute_xrender_bitmap_size | |||
931 | * | |||
932 | * target :: target bitmap descriptor. Note that its 'buffer' pointer | |||
933 | * must point to memory allocated by the caller | |||
934 | * | |||
935 | * slot :: the glyph slot containing the source bitmap | |||
936 | * | |||
937 | * mode :: the requested final rendering mode | |||
938 | * | |||
939 | * bgr :: boolean, set if BGR or VBGR pixel ordering is needed | |||
940 | */ | |||
941 | static void | |||
942 | _fill_xrender_bitmap(FT_Bitmap *target, | |||
943 | FT_GlyphSlot slot, | |||
944 | FT_Render_Mode mode, | |||
945 | int bgr) | |||
946 | { | |||
947 | FT_Bitmap *ftbit = &slot->bitmap; | |||
948 | unsigned char *srcLine = ftbit->buffer; | |||
949 | unsigned char *dstLine = target->buffer; | |||
950 | int src_pitch = ftbit->pitch; | |||
951 | int width = target->width; | |||
952 | int height = target->rows; | |||
953 | int pitch = target->pitch; | |||
954 | int subpixel; | |||
955 | int h; | |||
956 | ||||
957 | subpixel = (mode == FT_RENDER_MODE_LCD || | |||
958 | mode == FT_RENDER_MODE_LCD_V); | |||
959 | ||||
960 | if (src_pitch < 0) | |||
961 | srcLine -= src_pitch * (ftbit->rows - 1); | |||
962 | ||||
963 | target->pixel_mode = ftbit->pixel_mode; | |||
964 | ||||
965 | switch (ftbit->pixel_mode) { | |||
966 | case FT_PIXEL_MODE_MONO: | |||
967 | if (subpixel) { | |||
968 | /* convert mono to ARGB32 values */ | |||
969 | ||||
970 | for (h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch) { | |||
971 | int x; | |||
972 | ||||
973 | for (x = 0; x < width; x++) { | |||
974 | if (srcLine[(x >> 3)] & (0x80 >> (x & 7))) | |||
975 | ((unsigned int *) dstLine)[x] = 0xffffffffU; | |||
976 | } | |||
977 | } | |||
978 | target->pixel_mode = FT_PIXEL_MODE_LCD; | |||
979 | ||||
980 | } else if (mode == FT_RENDER_MODE_NORMAL) { | |||
981 | /* convert mono to 8-bit gray */ | |||
982 | ||||
983 | for (h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch) { | |||
984 | int x; | |||
985 | ||||
986 | for (x = 0; x < width; x++) { | |||
987 | if (srcLine[(x >> 3)] & (0x80 >> (x & 7))) | |||
988 | dstLine[x] = 0xff; | |||
989 | } | |||
990 | } | |||
991 | target->pixel_mode = FT_PIXEL_MODE_GRAY; | |||
992 | ||||
993 | } else { | |||
994 | /* copy mono to mono */ | |||
995 | ||||
996 | int bytes = (width + 7) >> 3; | |||
997 | ||||
998 | for (h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch) | |||
999 | memcpy (dstLine, srcLine, bytes); | |||
1000 | } | |||
1001 | break; | |||
1002 | ||||
1003 | case FT_PIXEL_MODE_GRAY: | |||
1004 | if (subpixel) { | |||
1005 | /* convert gray to ARGB32 values */ | |||
1006 | ||||
1007 | for (h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch) { | |||
1008 | int x; | |||
1009 | unsigned int *dst = (unsigned int *) dstLine; | |||
1010 | ||||
1011 | for (x = 0; x < width; x++) { | |||
1012 | unsigned int pix = srcLine[x]; | |||
1013 | ||||
1014 | pix |= (pix << 8); | |||
1015 | pix |= (pix << 16); | |||
1016 | ||||
1017 | dst[x] = pix; | |||
1018 | } | |||
1019 | } | |||
1020 | target->pixel_mode = FT_PIXEL_MODE_LCD; | |||
1021 | } else { | |||
1022 | /* copy gray into gray */ | |||
1023 | ||||
1024 | for (h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch) | |||
1025 | memcpy (dstLine, srcLine, width); | |||
1026 | } | |||
1027 | break; | |||
1028 | ||||
1029 | case FT_PIXEL_MODE_LCD: | |||
1030 | if (!bgr) { | |||
1031 | /* convert horizontal RGB into ARGB32 */ | |||
1032 | ||||
1033 | for (h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch) { | |||
1034 | int x; | |||
1035 | unsigned char *src = srcLine; | |||
1036 | unsigned int *dst = (unsigned int *) dstLine; | |||
1037 | ||||
1038 | for (x = 0; x < width; x++, src += 3) { | |||
1039 | unsigned int pix; | |||
1040 | ||||
1041 | pix = ((unsigned int)src[0] << 16) | | |||
1042 | ((unsigned int)src[1] << 8) | | |||
1043 | ((unsigned int)src[2] ) | | |||
1044 | ((unsigned int)src[1] << 24) ; | |||
1045 | ||||
1046 | dst[x] = pix; | |||
1047 | } | |||
1048 | } | |||
1049 | } else { | |||
1050 | /* convert horizontal BGR into ARGB32 */ | |||
1051 | ||||
1052 | for (h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch) { | |||
1053 | ||||
1054 | int x; | |||
1055 | unsigned char *src = srcLine; | |||
1056 | unsigned int *dst = (unsigned int *) dstLine; | |||
1057 | ||||
1058 | for (x = 0; x < width; x++, src += 3) { | |||
1059 | unsigned int pix; | |||
1060 | ||||
1061 | pix = ((unsigned int)src[2] << 16) | | |||
1062 | ((unsigned int)src[1] << 8) | | |||
1063 | ((unsigned int)src[0] ) | | |||
1064 | ((unsigned int)src[1] << 24) ; | |||
1065 | ||||
1066 | dst[x] = pix; | |||
1067 | } | |||
1068 | } | |||
1069 | } | |||
1070 | break; | |||
1071 | ||||
1072 | default: /* FT_PIXEL_MODE_LCD_V */ | |||
1073 | /* convert vertical RGB into ARGB32 */ | |||
1074 | if (!bgr) { | |||
1075 | ||||
1076 | for (h = height; h > 0; h--, srcLine += 3 * src_pitch, dstLine += pitch) { | |||
1077 | int x; | |||
1078 | unsigned char* src = srcLine; | |||
1079 | unsigned int* dst = (unsigned int *) dstLine; | |||
1080 | ||||
1081 | for (x = 0; x < width; x++, src += 1) { | |||
1082 | unsigned int pix; | |||
1083 | pix = ((unsigned int)src[0] << 16) | | |||
1084 | ((unsigned int)src[src_pitch] << 8) | | |||
1085 | ((unsigned int)src[src_pitch*2] ) | | |||
1086 | ((unsigned int)src[src_pitch] << 24) ; | |||
1087 | dst[x] = pix; | |||
1088 | } | |||
1089 | } | |||
1090 | } else { | |||
1091 | ||||
1092 | for (h = height; h > 0; h--, srcLine += 3*src_pitch, dstLine += pitch) { | |||
1093 | int x; | |||
1094 | unsigned char *src = srcLine; | |||
1095 | unsigned int *dst = (unsigned int *) dstLine; | |||
1096 | ||||
1097 | for (x = 0; x < width; x++, src += 1) { | |||
1098 | unsigned int pix; | |||
1099 | ||||
1100 | pix = ((unsigned int)src[src_pitch * 2] << 16) | | |||
1101 | ((unsigned int)src[src_pitch] << 8) | | |||
1102 | ((unsigned int)src[0] ) | | |||
1103 | ((unsigned int)src[src_pitch] << 24) ; | |||
1104 | ||||
1105 | dst[x] = pix; | |||
1106 | } | |||
1107 | } | |||
1108 | } | |||
1109 | } | |||
1110 | } | |||
1111 | ||||
1112 | ||||
1113 | /* Fills in val->image with an image surface created from @bitmap | |||
1114 | */ | |||
1115 | static cairo_status_t | |||
1116 | _get_bitmap_surface (FT_Bitmap *bitmap, | |||
1117 | cairo_bool_t own_buffer, | |||
1118 | cairo_font_options_t *font_options, | |||
1119 | cairo_image_surface_t **surface) | |||
1120 | { | |||
1121 | int width, height, stride; | |||
1122 | unsigned char *data; | |||
1123 | int format = CAIRO_FORMAT_A8; | |||
1124 | cairo_image_surface_t *image; | |||
1125 | ||||
1126 | width = bitmap->width; | |||
1127 | height = bitmap->rows; | |||
1128 | ||||
1129 | if (width == 0 || height == 0) { | |||
1130 | *surface = (cairo_image_surface_t *) | |||
1131 | cairo_image_surface_create_for_data_moz_cairo_image_surface_create_for_data (NULL((void*)0), format, 0, 0, 0); | |||
1132 | return (*surface)->base.status; | |||
1133 | } | |||
1134 | ||||
1135 | switch (bitmap->pixel_mode) { | |||
1136 | case FT_PIXEL_MODE_MONO: | |||
1137 | stride = (((width + 31) & ~31) >> 3); | |||
1138 | if (own_buffer) { | |||
1139 | data = bitmap->buffer; | |||
1140 | assert (stride == bitmap->pitch)do { if (!(stride == bitmap->pitch)) fprintf(stderr, "Assertion failed at %s:%d: %s\n" , "/home/sylvestre/dev/mozilla/ff/firefox.hg/gfx/cairo/cairo/src/cairo-ft-font.c" , 1140, "stride == bitmap->pitch"); } while (0); | |||
1141 | } else { | |||
1142 | data = _cairo_malloc_ab (height, stride)((stride) && (unsigned) (height) >= (2147483647) / (unsigned) (stride) ? ((void*)0) : (((unsigned) (height) * ( unsigned) (stride)) ? malloc((unsigned) ((unsigned) (height) * (unsigned) (stride))) : ((void*)0))); | |||
1143 | if (!data) | |||
1144 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); | |||
1145 | ||||
1146 | if (stride == bitmap->pitch) { | |||
1147 | memcpy (data, bitmap->buffer, stride * height); | |||
1148 | } else { | |||
1149 | int i; | |||
1150 | unsigned char *source, *dest; | |||
1151 | ||||
1152 | source = bitmap->buffer; | |||
1153 | dest = data; | |||
1154 | for (i = height; i; i--) { | |||
1155 | memcpy (dest, source, bitmap->pitch); | |||
1156 | memset (dest + bitmap->pitch, '\0', stride - bitmap->pitch); | |||
1157 | ||||
1158 | source += bitmap->pitch; | |||
1159 | dest += stride; | |||
1160 | } | |||
1161 | } | |||
1162 | } | |||
1163 | ||||
1164 | #ifndef WORDS_BIGENDIAN | |||
1165 | { | |||
1166 | uint8_t *d = data; | |||
1167 | int count = stride * height; | |||
1168 | ||||
1169 | while (count--) { | |||
1170 | *d = CAIRO_BITSWAP8 (*d)((((*d) * 0x0802LU & 0x22110LU) | ((*d) * 0x8020LU & 0x88440LU )) * 0x10101LU >> 16); | |||
1171 | d++; | |||
1172 | } | |||
1173 | } | |||
1174 | #endif | |||
1175 | format = CAIRO_FORMAT_A1; | |||
1176 | break; | |||
1177 | ||||
1178 | case FT_PIXEL_MODE_LCD: | |||
1179 | case FT_PIXEL_MODE_LCD_V: | |||
1180 | case FT_PIXEL_MODE_GRAY: | |||
1181 | if (font_options->antialias != CAIRO_ANTIALIAS_SUBPIXEL) { | |||
1182 | stride = bitmap->pitch; | |||
1183 | if (own_buffer) { | |||
1184 | data = bitmap->buffer; | |||
1185 | } else { | |||
1186 | data = _cairo_malloc_ab (height, stride)((stride) && (unsigned) (height) >= (2147483647) / (unsigned) (stride) ? ((void*)0) : (((unsigned) (height) * ( unsigned) (stride)) ? malloc((unsigned) ((unsigned) (height) * (unsigned) (stride))) : ((void*)0))); | |||
1187 | if (!data) | |||
1188 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); | |||
1189 | ||||
1190 | memcpy (data, bitmap->buffer, stride * height); | |||
1191 | } | |||
1192 | ||||
1193 | format = CAIRO_FORMAT_A8; | |||
1194 | } else { | |||
1195 | /* if we get there, the data from the source bitmap | |||
1196 | * really comes from _fill_xrender_bitmap, and is | |||
1197 | * made of 32-bit ARGB or ABGR values */ | |||
1198 | assert (own_buffer != 0)do { if (!(own_buffer != 0)) fprintf(stderr, "Assertion failed at %s:%d: %s\n" , "/home/sylvestre/dev/mozilla/ff/firefox.hg/gfx/cairo/cairo/src/cairo-ft-font.c" , 1198, "own_buffer != 0"); } while (0); | |||
1199 | assert (bitmap->pixel_mode != FT_PIXEL_MODE_GRAY)do { if (!(bitmap->pixel_mode != FT_PIXEL_MODE_GRAY)) fprintf (stderr, "Assertion failed at %s:%d: %s\n", "/home/sylvestre/dev/mozilla/ff/firefox.hg/gfx/cairo/cairo/src/cairo-ft-font.c" , 1199, "bitmap->pixel_mode != FT_PIXEL_MODE_GRAY"); } while (0); | |||
1200 | ||||
1201 | data = bitmap->buffer; | |||
1202 | stride = bitmap->pitch; | |||
1203 | format = CAIRO_FORMAT_ARGB32; | |||
1204 | } | |||
1205 | break; | |||
1206 | case FT_PIXEL_MODE_GRAY2: | |||
1207 | case FT_PIXEL_MODE_GRAY4: | |||
1208 | /* These could be triggered by very rare types of TrueType fonts */ | |||
1209 | default: | |||
1210 | if (own_buffer) | |||
1211 | free (bitmap->buffer); | |||
1212 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); | |||
1213 | } | |||
1214 | ||||
1215 | /* XXX */ | |||
1216 | *surface = image = (cairo_image_surface_t *) | |||
1217 | cairo_image_surface_create_for_data_moz_cairo_image_surface_create_for_data (data, | |||
1218 | format, | |||
1219 | width, height, stride); | |||
1220 | if (image->base.status) { | |||
1221 | free (data); | |||
1222 | return (*surface)->base.status; | |||
1223 | } | |||
1224 | ||||
1225 | if (format == CAIRO_FORMAT_ARGB32) | |||
1226 | pixman_image_set_component_alpha_moz_pixman_image_set_component_alpha (image->pixman_image, TRUE1); | |||
1227 | ||||
1228 | _cairo_image_surface_assume_ownership_of_data (image); | |||
1229 | ||||
1230 | _cairo_debug_check_image_surface_is_defined (&image->base); | |||
1231 | ||||
1232 | return CAIRO_STATUS_SUCCESS; | |||
1233 | } | |||
1234 | ||||
1235 | /* Converts an outline FT_GlyphSlot into an image | |||
1236 | * | |||
1237 | * This could go through _render_glyph_bitmap as well, letting | |||
1238 | * FreeType convert the outline to a bitmap, but doing it ourselves | |||
1239 | * has two minor advantages: first, we save a copy of the bitmap | |||
1240 | * buffer: we can directly use the buffer that FreeType renders | |||
1241 | * into. | |||
1242 | * | |||
1243 | * Second, it may help when we add support for subpixel | |||
1244 | * rendering: the Xft code does it this way. (Keith thinks that | |||
1245 | * it may also be possible to get the subpixel rendering with | |||
1246 | * FT_Render_Glyph: something worth looking into in more detail | |||
1247 | * when we add subpixel support. If so, we may want to eliminate | |||
1248 | * this version of the code path entirely. | |||
1249 | */ | |||
1250 | static cairo_status_t | |||
1251 | _render_glyph_outline (FT_Face face, | |||
1252 | cairo_font_options_t *font_options, | |||
1253 | cairo_image_surface_t **surface) | |||
1254 | { | |||
1255 | int rgba = FC_RGBA_UNKNOWN0; | |||
1256 | int lcd_filter = FT_LCD_FILTER_LEGACY16; | |||
1257 | FT_GlyphSlot glyphslot = face->glyph; | |||
1258 | FT_Outline *outline = &glyphslot->outline; | |||
1259 | FT_Bitmap bitmap; | |||
1260 | FT_BBox cbox; | |||
1261 | unsigned int width, height; | |||
1262 | cairo_status_t status; | |||
1263 | FT_Error fterror; | |||
1264 | FT_Library library = glyphslot->library; | |||
1265 | FT_Render_Mode render_mode = FT_RENDER_MODE_NORMAL; | |||
1266 | ||||
1267 | switch (font_options->antialias) { | |||
1268 | case CAIRO_ANTIALIAS_NONE: | |||
1269 | render_mode = FT_RENDER_MODE_MONO; | |||
1270 | break; | |||
1271 | ||||
1272 | case CAIRO_ANTIALIAS_SUBPIXEL: | |||
1273 | switch (font_options->subpixel_order) { | |||
1274 | case CAIRO_SUBPIXEL_ORDER_DEFAULT: | |||
1275 | case CAIRO_SUBPIXEL_ORDER_RGB: | |||
1276 | case CAIRO_SUBPIXEL_ORDER_BGR: | |||
1277 | render_mode = FT_RENDER_MODE_LCD; | |||
1278 | break; | |||
1279 | ||||
1280 | case CAIRO_SUBPIXEL_ORDER_VRGB: | |||
1281 | case CAIRO_SUBPIXEL_ORDER_VBGR: | |||
1282 | render_mode = FT_RENDER_MODE_LCD_V; | |||
1283 | break; | |||
1284 | } | |||
1285 | ||||
1286 | switch (font_options->lcd_filter) { | |||
1287 | case CAIRO_LCD_FILTER_NONE: | |||
1288 | lcd_filter = FT_LCD_FILTER_NONE0; | |||
1289 | break; | |||
1290 | case CAIRO_LCD_FILTER_DEFAULT: | |||
1291 | case CAIRO_LCD_FILTER_INTRA_PIXEL: | |||
1292 | lcd_filter = FT_LCD_FILTER_LEGACY16; | |||
1293 | break; | |||
1294 | case CAIRO_LCD_FILTER_FIR3: | |||
1295 | lcd_filter = FT_LCD_FILTER_LIGHT2; | |||
1296 | break; | |||
1297 | case CAIRO_LCD_FILTER_FIR5: | |||
1298 | lcd_filter = FT_LCD_FILTER_DEFAULT1; | |||
1299 | break; | |||
1300 | } | |||
1301 | ||||
1302 | break; | |||
1303 | ||||
1304 | case CAIRO_ANTIALIAS_DEFAULT: | |||
1305 | case CAIRO_ANTIALIAS_GRAY: | |||
1306 | render_mode = FT_RENDER_MODE_NORMAL; | |||
1307 | } | |||
1308 | ||||
1309 | FT_Outline_Get_CBox (outline, &cbox); | |||
1310 | ||||
1311 | cbox.xMin &= -64; | |||
1312 | cbox.yMin &= -64; | |||
1313 | cbox.xMax = (cbox.xMax + 63) & -64; | |||
1314 | cbox.yMax = (cbox.yMax + 63) & -64; | |||
1315 | ||||
1316 | width = (unsigned int) ((cbox.xMax - cbox.xMin) >> 6); | |||
1317 | height = (unsigned int) ((cbox.yMax - cbox.yMin) >> 6); | |||
1318 | ||||
1319 | if (width * height == 0) { | |||
1320 | cairo_format_t format; | |||
1321 | /* Looks like fb handles zero-sized images just fine */ | |||
1322 | switch (render_mode) { | |||
1323 | case FT_RENDER_MODE_MONO: | |||
1324 | format = CAIRO_FORMAT_A1; | |||
1325 | break; | |||
1326 | case FT_RENDER_MODE_LCD: | |||
1327 | case FT_RENDER_MODE_LCD_V: | |||
1328 | format= CAIRO_FORMAT_ARGB32; | |||
1329 | break; | |||
1330 | case FT_RENDER_MODE_LIGHT: | |||
1331 | case FT_RENDER_MODE_NORMAL: | |||
1332 | case FT_RENDER_MODE_MAX: | |||
1333 | default: | |||
1334 | format = CAIRO_FORMAT_A8; | |||
1335 | break; | |||
1336 | } | |||
1337 | ||||
1338 | (*surface) = (cairo_image_surface_t *) | |||
1339 | cairo_image_surface_create_for_data_moz_cairo_image_surface_create_for_data (NULL((void*)0), format, 0, 0, 0); | |||
1340 | if ((*surface)->base.status) | |||
1341 | return (*surface)->base.status; | |||
1342 | } else { | |||
1343 | ||||
1344 | int bitmap_size; | |||
1345 | static int initialized_setLcdFilter = 0; | |||
1346 | ||||
1347 | switch (render_mode) { | |||
1348 | case FT_RENDER_MODE_LCD: | |||
1349 | if (font_options->subpixel_order == CAIRO_SUBPIXEL_ORDER_BGR) { | |||
1350 | rgba = FC_RGBA_BGR2; | |||
1351 | } else { | |||
1352 | rgba = FC_RGBA_RGB1; | |||
1353 | } | |||
1354 | break; | |||
1355 | case FT_RENDER_MODE_LCD_V: | |||
1356 | if (font_options->subpixel_order == CAIRO_SUBPIXEL_ORDER_VBGR) { | |||
1357 | rgba = FC_RGBA_VBGR4; | |||
1358 | } else { | |||
1359 | rgba = FC_RGBA_VRGB3; | |||
1360 | } | |||
1361 | break; | |||
1362 | case FT_RENDER_MODE_MONO: | |||
1363 | case FT_RENDER_MODE_LIGHT: | |||
1364 | case FT_RENDER_MODE_NORMAL: | |||
1365 | case FT_RENDER_MODE_MAX: | |||
1366 | default: | |||
1367 | break; | |||
1368 | } | |||
1369 | ||||
1370 | if (!initialized_setLcdFilter) { | |||
1371 | initialized_setLcdFilter = 1; | |||
1372 | #ifdef HAVE_FT_LIBRARY_SETLCDFILTER | |||
1373 | setLcdFilter = &FT_Library_SetLcdFilter; | |||
1374 | #else | |||
1375 | setLcdFilter = (setLcdFilterFunc) dlsym(RTLD_DEFAULT((void *) 0), "FT_Library_SetLcdFilter"); | |||
1376 | #endif | |||
1377 | } | |||
1378 | ||||
1379 | if (setLcdFilter) | |||
1380 | setLcdFilter (library, lcd_filter); | |||
1381 | ||||
1382 | fterror = FT_Render_Glyph (face->glyph, render_mode); | |||
1383 | ||||
1384 | if (setLcdFilter) | |||
1385 | setLcdFilter (library, FT_LCD_FILTER_NONE0); | |||
1386 | ||||
1387 | if (fterror != 0) | |||
1388 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); | |||
1389 | ||||
1390 | bitmap_size = _compute_xrender_bitmap_size (&bitmap, | |||
1391 | face->glyph, | |||
1392 | render_mode); | |||
1393 | if (bitmap_size < 0) | |||
1394 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); | |||
1395 | ||||
1396 | bitmap.buffer = calloc (1, bitmap_size); | |||
1397 | if (bitmap.buffer == NULL((void*)0)) | |||
1398 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); | |||
1399 | ||||
1400 | _fill_xrender_bitmap (&bitmap, face->glyph, render_mode, | |||
1401 | (rgba == FC_RGBA_BGR2 || rgba == FC_RGBA_VBGR4)); | |||
1402 | ||||
1403 | /* Note: | |||
1404 | * _get_bitmap_surface will free bitmap.buffer if there is an error | |||
1405 | */ | |||
1406 | status = _get_bitmap_surface (&bitmap, TRUE1, font_options, surface); | |||
1407 | if (unlikely (status)(__builtin_expect (__extension__ ({ int _cairo_boolean_var_; if (status) _cairo_boolean_var_ = 1; else _cairo_boolean_var_ = 0; _cairo_boolean_var_; }), 0))) | |||
1408 | return status; | |||
1409 | ||||
1410 | /* Note: the font's coordinate system is upside down from ours, so the | |||
1411 | * Y coordinate of the control box needs to be negated. Moreover, device | |||
1412 | * offsets are position of glyph origin relative to top left while xMin | |||
1413 | * and yMax are offsets of top left relative to origin. Another negation. | |||
1414 | */ | |||
1415 | cairo_surface_set_device_offset_moz_cairo_surface_set_device_offset (&(*surface)->base, | |||
1416 | (double)-glyphslot->bitmap_left, | |||
1417 | (double)+glyphslot->bitmap_top); | |||
1418 | } | |||
1419 | ||||
1420 | return CAIRO_STATUS_SUCCESS; | |||
1421 | } | |||
1422 | ||||
1423 | /* Converts a bitmap (or other) FT_GlyphSlot into an image */ | |||
1424 | static cairo_status_t | |||
1425 | _render_glyph_bitmap (FT_Face face, | |||
1426 | cairo_font_options_t *font_options, | |||
1427 | cairo_image_surface_t **surface) | |||
1428 | { | |||
1429 | FT_GlyphSlot glyphslot = face->glyph; | |||
1430 | cairo_status_t status; | |||
1431 | FT_Error error; | |||
1432 | ||||
1433 | /* According to the FreeType docs, glyphslot->format could be | |||
1434 | * something other than FT_GLYPH_FORMAT_OUTLINE or | |||
1435 | * FT_GLYPH_FORMAT_BITMAP. Calling FT_Render_Glyph gives FreeType | |||
1436 | * the opportunity to convert such to | |||
1437 | * bitmap. FT_GLYPH_FORMAT_COMPOSITE will not be encountered since | |||
1438 | * we avoid the FT_LOAD_NO_RECURSE flag. | |||
1439 | */ | |||
1440 | error = FT_Render_Glyph (glyphslot, FT_RENDER_MODE_NORMAL); | |||
1441 | /* XXX ignoring all other errors for now. They are not fatal, typically | |||
1442 | * just a glyph-not-found. */ | |||
1443 | if (error == FT_Err_Out_Of_Memory) | |||
1444 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); | |||
1445 | ||||
1446 | status = _get_bitmap_surface (&glyphslot->bitmap, | |||
1447 | FALSE0, font_options, | |||
1448 | surface); | |||
1449 | if (unlikely (status)(__builtin_expect (__extension__ ({ int _cairo_boolean_var_; if (status) _cairo_boolean_var_ = 1; else _cairo_boolean_var_ = 0; _cairo_boolean_var_; }), 0))) | |||
1450 | return status; | |||
1451 | ||||
1452 | /* | |||
1453 | * Note: the font's coordinate system is upside down from ours, so the | |||
1454 | * Y coordinate of the control box needs to be negated. Moreover, device | |||
1455 | * offsets are position of glyph origin relative to top left while | |||
1456 | * bitmap_left and bitmap_top are offsets of top left relative to origin. | |||
1457 | * Another negation. | |||
1458 | */ | |||
1459 | cairo_surface_set_device_offset_moz_cairo_surface_set_device_offset (&(*surface)->base, | |||
1460 | -glyphslot->bitmap_left, | |||
1461 | +glyphslot->bitmap_top); | |||
1462 | ||||
1463 | return CAIRO_STATUS_SUCCESS; | |||
1464 | } | |||
1465 | ||||
1466 | static cairo_status_t | |||
1467 | _transform_glyph_bitmap (cairo_matrix_t * shape, | |||
1468 | cairo_image_surface_t ** surface) | |||
1469 | { | |||
1470 | cairo_matrix_t original_to_transformed; | |||
1471 | cairo_matrix_t transformed_to_original; | |||
1472 | cairo_image_surface_t *old_image; | |||
1473 | cairo_surface_t *image; | |||
1474 | double x[4], y[4]; | |||
1475 | double origin_x, origin_y; | |||
1476 | int orig_width, orig_height; | |||
1477 | int i; | |||
1478 | int x_min, y_min, x_max, y_max; | |||
1479 | int width, height; | |||
1480 | cairo_status_t status; | |||
1481 | cairo_surface_pattern_t pattern; | |||
1482 | ||||
1483 | /* We want to compute a transform that takes the origin | |||
1484 | * (device_x_offset, device_y_offset) to 0,0, then applies | |||
1485 | * the "shape" portion of the font transform | |||
1486 | */ | |||
1487 | original_to_transformed = *shape; | |||
1488 | ||||
1489 | cairo_surface_get_device_offset_moz_cairo_surface_get_device_offset (&(*surface)->base, &origin_x, &origin_y); | |||
1490 | orig_width = (*surface)->width; | |||
1491 | orig_height = (*surface)->height; | |||
1492 | ||||
1493 | cairo_matrix_translate_moz_cairo_matrix_translate (&original_to_transformed, | |||
1494 | -origin_x, -origin_y); | |||
1495 | ||||
1496 | /* Find the bounding box of the original bitmap under that | |||
1497 | * transform | |||
1498 | */ | |||
1499 | x[0] = 0; y[0] = 0; | |||
1500 | x[1] = orig_width; y[1] = 0; | |||
1501 | x[2] = orig_width; y[2] = orig_height; | |||
1502 | x[3] = 0; y[3] = orig_height; | |||
1503 | ||||
1504 | for (i = 0; i < 4; i++) | |||
1505 | cairo_matrix_transform_point_moz_cairo_matrix_transform_point (&original_to_transformed, | |||
1506 | &x[i], &y[i]); | |||
1507 | ||||
1508 | x_min = floor (x[0]); y_min = floor (y[0]); | |||
1509 | x_max = ceil (x[0]); y_max = ceil (y[0]); | |||
1510 | ||||
1511 | for (i = 1; i < 4; i++) { | |||
1512 | if (x[i] < x_min) | |||
1513 | x_min = floor (x[i]); | |||
1514 | else if (x[i] > x_max) | |||
1515 | x_max = ceil (x[i]); | |||
1516 | if (y[i] < y_min) | |||
1517 | y_min = floor (y[i]); | |||
1518 | else if (y[i] > y_max) | |||
1519 | y_max = ceil (y[i]); | |||
1520 | } | |||
1521 | ||||
1522 | /* Adjust the transform so that the bounding box starts at 0,0 ... | |||
1523 | * this gives our final transform from original bitmap to transformed | |||
1524 | * bitmap. | |||
1525 | */ | |||
1526 | original_to_transformed.x0 -= x_min; | |||
1527 | original_to_transformed.y0 -= y_min; | |||
1528 | ||||
1529 | /* Create the transformed bitmap */ | |||
1530 | width = x_max - x_min; | |||
1531 | height = y_max - y_min; | |||
1532 | ||||
1533 | transformed_to_original = original_to_transformed; | |||
1534 | status = cairo_matrix_invert_moz_cairo_matrix_invert (&transformed_to_original); | |||
1535 | if (unlikely (status)(__builtin_expect (__extension__ ({ int _cairo_boolean_var_; if (status) _cairo_boolean_var_ = 1; else _cairo_boolean_var_ = 0; _cairo_boolean_var_; }), 0))) | |||
1536 | return status; | |||
1537 | ||||
1538 | image = cairo_image_surface_create_moz_cairo_image_surface_create (CAIRO_FORMAT_A8, width, height); | |||
1539 | if (unlikely (image->status)(__builtin_expect (__extension__ ({ int _cairo_boolean_var_; if (image->status) _cairo_boolean_var_ = 1; else _cairo_boolean_var_ = 0; _cairo_boolean_var_; }), 0))) | |||
1540 | return image->status; | |||
1541 | ||||
1542 | /* Draw the original bitmap transformed into the new bitmap | |||
1543 | */ | |||
1544 | _cairo_pattern_init_for_surface (&pattern, &(*surface)->base); | |||
1545 | cairo_pattern_set_matrix_moz_cairo_pattern_set_matrix (&pattern.base, &transformed_to_original); | |||
1546 | ||||
1547 | status = _cairo_surface_paint (image, | |||
1548 | CAIRO_OPERATOR_SOURCE, | |||
1549 | &pattern.base, | |||
1550 | NULL((void*)0)); | |||
1551 | ||||
1552 | _cairo_pattern_fini (&pattern.base); | |||
1553 | ||||
1554 | if (unlikely (status)(__builtin_expect (__extension__ ({ int _cairo_boolean_var_; if (status) _cairo_boolean_var_ = 1; else _cairo_boolean_var_ = 0; _cairo_boolean_var_; }), 0))) { | |||
1555 | cairo_surface_destroy_moz_cairo_surface_destroy (image); | |||
1556 | return status; | |||
1557 | } | |||
1558 | ||||
1559 | /* Now update the cache entry for the new bitmap, recomputing | |||
1560 | * the origin based on the final transform. | |||
1561 | */ | |||
1562 | cairo_matrix_transform_point_moz_cairo_matrix_transform_point (&original_to_transformed, | |||
1563 | &origin_x, &origin_y); | |||
1564 | ||||
1565 | old_image = (*surface); | |||
1566 | (*surface) = (cairo_image_surface_t *)image; | |||
1567 | cairo_surface_destroy_moz_cairo_surface_destroy (&old_image->base); | |||
1568 | ||||
1569 | cairo_surface_set_device_offset_moz_cairo_surface_set_device_offset (&(*surface)->base, | |||
1570 | _cairo_lroundlround (origin_x), | |||
1571 | _cairo_lroundlround (origin_y)); | |||
1572 | return CAIRO_STATUS_SUCCESS; | |||
1573 | } | |||
1574 | ||||
1575 | static const cairo_unscaled_font_backend_t cairo_ft_unscaled_font_backend = { | |||
1576 | _cairo_ft_unscaled_font_destroy, | |||
1577 | #if 0 | |||
1578 | _cairo_ft_unscaled_font_create_glyph | |||
1579 | #endif | |||
1580 | }; | |||
1581 | ||||
1582 | /* #cairo_ft_scaled_font_t */ | |||
1583 | ||||
1584 | typedef struct _cairo_ft_scaled_font { | |||
1585 | cairo_scaled_font_t base; | |||
1586 | cairo_ft_unscaled_font_t *unscaled; | |||
1587 | cairo_ft_options_t ft_options; | |||
1588 | } cairo_ft_scaled_font_t; | |||
1589 | ||||
1590 | static const cairo_scaled_font_backend_t _cairo_ft_scaled_font_backend; | |||
1591 | ||||
1592 | #if CAIRO_HAS_FC_FONT1 | |||
1593 | /* The load flags passed to FT_Load_Glyph control aspects like hinting and | |||
1594 | * antialiasing. Here we compute them from the fields of a FcPattern. | |||
1595 | */ | |||
1596 | static void | |||
1597 | _get_pattern_ft_options (FcPattern *pattern, cairo_ft_options_t *ret) | |||
1598 | { | |||
1599 | FcBool antialias, vertical_layout, hinting, autohint, bitmap, embolden; | |||
1600 | cairo_ft_options_t ft_options; | |||
1601 | int rgba; | |||
1602 | #ifdef FC_HINT_STYLE"hintstyle" | |||
1603 | int hintstyle; | |||
1604 | #endif | |||
1605 | ||||
1606 | _cairo_font_options_init_default (&ft_options.base); | |||
1607 | ft_options.load_flags = FT_LOAD_DEFAULT0x0; | |||
1608 | ft_options.extra_flags = 0; | |||
1609 | ||||
1610 | #ifndef FC_EMBEDDED_BITMAP"embeddedbitmap" | |||
1611 | #define FC_EMBEDDED_BITMAP"embeddedbitmap" "embeddedbitmap" | |||
1612 | #endif | |||
1613 | ||||
1614 | /* Check whether to force use of embedded bitmaps */ | |||
1615 | if (FcPatternGetBool (pattern, | |||
1616 | FC_EMBEDDED_BITMAP"embeddedbitmap", 0, &bitmap) != FcResultMatch) | |||
1617 | bitmap = FcFalse0; | |||
1618 | ||||
1619 | /* disable antialiasing if requested */ | |||
1620 | if (FcPatternGetBool (pattern, | |||
1621 | FC_ANTIALIAS"antialias", 0, &antialias) != FcResultMatch) | |||
1622 | antialias = FcTrue1; | |||
1623 | ||||
1624 | if (antialias) { | |||
1625 | cairo_subpixel_order_t subpixel_order; | |||
1626 | int lcd_filter; | |||
1627 | ||||
1628 | /* disable hinting if requested */ | |||
1629 | if (FcPatternGetBool (pattern, | |||
1630 | FC_HINTING"hinting", 0, &hinting) != FcResultMatch) | |||
1631 | hinting = FcTrue1; | |||
1632 | ||||
1633 | if (FcPatternGetInteger (pattern, | |||
1634 | FC_RGBA"rgba", 0, &rgba) != FcResultMatch) | |||
1635 | rgba = FC_RGBA_UNKNOWN0; | |||
1636 | ||||
1637 | switch (rgba) { | |||
1638 | case FC_RGBA_RGB1: | |||
1639 | subpixel_order = CAIRO_SUBPIXEL_ORDER_RGB; | |||
1640 | break; | |||
1641 | case FC_RGBA_BGR2: | |||
1642 | subpixel_order = CAIRO_SUBPIXEL_ORDER_BGR; | |||
1643 | break; | |||
1644 | case FC_RGBA_VRGB3: | |||
1645 | subpixel_order = CAIRO_SUBPIXEL_ORDER_VRGB; | |||
1646 | break; | |||
1647 | case FC_RGBA_VBGR4: | |||
1648 | subpixel_order = CAIRO_SUBPIXEL_ORDER_VBGR; | |||
1649 | break; | |||
1650 | case FC_RGBA_UNKNOWN0: | |||
1651 | case FC_RGBA_NONE5: | |||
1652 | default: | |||
1653 | subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT; | |||
1654 | break; | |||
1655 | } | |||
1656 | ||||
1657 | if (subpixel_order != CAIRO_SUBPIXEL_ORDER_DEFAULT) { | |||
1658 | ft_options.base.subpixel_order = subpixel_order; | |||
1659 | ft_options.base.antialias = CAIRO_ANTIALIAS_SUBPIXEL; | |||
1660 | } | |||
1661 | ||||
1662 | if (FcPatternGetInteger (pattern, | |||
1663 | FC_LCD_FILTER"lcdfilter", 0, &lcd_filter) == FcResultMatch) | |||
1664 | { | |||
1665 | switch (lcd_filter) { | |||
1666 | case FC_LCD_NONE0: | |||
1667 | ft_options.base.lcd_filter = CAIRO_LCD_FILTER_NONE; | |||
1668 | break; | |||
1669 | case FC_LCD_DEFAULT1: | |||
1670 | ft_options.base.lcd_filter = CAIRO_LCD_FILTER_FIR5; | |||
1671 | break; | |||
1672 | case FC_LCD_LIGHT2: | |||
1673 | ft_options.base.lcd_filter = CAIRO_LCD_FILTER_FIR3; | |||
1674 | break; | |||
1675 | case FC_LCD_LEGACY3: | |||
1676 | ft_options.base.lcd_filter = CAIRO_LCD_FILTER_INTRA_PIXEL; | |||
1677 | break; | |||
1678 | } | |||
1679 | } | |||
1680 | ||||
1681 | #ifdef FC_HINT_STYLE"hintstyle" | |||
1682 | if (FcPatternGetInteger (pattern, | |||
1683 | FC_HINT_STYLE"hintstyle", 0, &hintstyle) != FcResultMatch) | |||
1684 | hintstyle = FC_HINT_FULL3; | |||
1685 | ||||
1686 | if (!hinting) | |||
1687 | hintstyle = FC_HINT_NONE0; | |||
1688 | ||||
1689 | switch (hintstyle) { | |||
1690 | case FC_HINT_NONE0: | |||
1691 | ft_options.base.hint_style = CAIRO_HINT_STYLE_NONE; | |||
1692 | break; | |||
1693 | case FC_HINT_SLIGHT1: | |||
1694 | ft_options.base.hint_style = CAIRO_HINT_STYLE_SLIGHT; | |||
1695 | break; | |||
1696 | case FC_HINT_MEDIUM2: | |||
1697 | default: | |||
1698 | ft_options.base.hint_style = CAIRO_HINT_STYLE_MEDIUM; | |||
1699 | break; | |||
1700 | case FC_HINT_FULL3: | |||
1701 | ft_options.base.hint_style = CAIRO_HINT_STYLE_FULL; | |||
1702 | break; | |||
1703 | } | |||
1704 | #else /* !FC_HINT_STYLE */ | |||
1705 | if (!hinting) { | |||
1706 | ft_options.base.hint_style = CAIRO_HINT_STYLE_NONE; | |||
1707 | } | |||
1708 | #endif /* FC_HINT_STYLE */ | |||
1709 | ||||
1710 | /* Force embedded bitmaps off if no hinting requested */ | |||
1711 | if (ft_options.base.hint_style == CAIRO_HINT_STYLE_NONE) | |||
1712 | bitmap = FcFalse0; | |||
1713 | ||||
1714 | if (!bitmap) | |||
1715 | ft_options.load_flags |= FT_LOAD_NO_BITMAP( 1L << 3 ); | |||
1716 | ||||
1717 | } else { | |||
1718 | ft_options.base.antialias = CAIRO_ANTIALIAS_NONE; | |||
1719 | } | |||
1720 | ||||
1721 | /* force autohinting if requested */ | |||
1722 | if (FcPatternGetBool (pattern, | |||
1723 | FC_AUTOHINT"autohint", 0, &autohint) != FcResultMatch) | |||
1724 | autohint = FcFalse0; | |||
1725 | ||||
1726 | if (autohint) | |||
1727 | ft_options.load_flags |= FT_LOAD_FORCE_AUTOHINT( 1L << 5 ); | |||
1728 | ||||
1729 | if (FcPatternGetBool (pattern, | |||
1730 | FC_VERTICAL_LAYOUT"verticallayout", 0, &vertical_layout) != FcResultMatch) | |||
1731 | vertical_layout = FcFalse0; | |||
1732 | ||||
1733 | if (vertical_layout) | |||
1734 | ft_options.load_flags |= FT_LOAD_VERTICAL_LAYOUT( 1L << 4 ); | |||
1735 | ||||
1736 | #ifndef FC_EMBOLDEN"embolden" | |||
1737 | #define FC_EMBOLDEN"embolden" "embolden" | |||
1738 | #endif | |||
1739 | if (FcPatternGetBool (pattern, | |||
1740 | FC_EMBOLDEN"embolden", 0, &embolden) != FcResultMatch) | |||
1741 | embolden = FcFalse0; | |||
1742 | ||||
1743 | if (embolden) | |||
1744 | ft_options.extra_flags |= CAIRO_FT_OPTIONS_EMBOLDEN; | |||
1745 | ||||
1746 | *ret = ft_options; | |||
1747 | } | |||
1748 | #endif | |||
1749 | ||||
1750 | static void | |||
1751 | _cairo_ft_options_merge (cairo_ft_options_t *options, | |||
1752 | cairo_ft_options_t *other) | |||
1753 | { | |||
1754 | int load_flags = other->load_flags; | |||
1755 | int load_target = FT_LOAD_TARGET_NORMAL( (FT_Int32)( (FT_RENDER_MODE_NORMAL) & 15 ) << 16 ); | |||
1756 | ||||
1757 | /* clear load target mode */ | |||
1758 | load_flags &= ~(FT_LOAD_TARGET_(FT_LOAD_TARGET_MODE(other->load_flags))( (FT_Int32)( (( (FT_Render_Mode)( ( (other->load_flags) >> 16 ) & 15 ) )) & 15 ) << 16 )); | |||
1759 | ||||
1760 | if (load_flags & FT_LOAD_NO_HINTING( 1L << 1 )) | |||
1761 | other->base.hint_style = CAIRO_HINT_STYLE_NONE; | |||
1762 | ||||
1763 | if (other->base.antialias == CAIRO_ANTIALIAS_NONE || | |||
1764 | options->base.antialias == CAIRO_ANTIALIAS_NONE) { | |||
1765 | options->base.antialias = CAIRO_ANTIALIAS_NONE; | |||
1766 | options->base.subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT; | |||
1767 | } else if (options->base.antialias != CAIRO_ANTIALIAS_GRAY) { | |||
1768 | /* The surface supports subpixel aa, so let the font face options | |||
1769 | * choose whether to use subpixel aa. If the surface has | |||
1770 | * CAIRO_ANTIALIAS_GRAY (e.g. PS, PDF, SVG, translucent part of a | |||
1771 | * CONTENT_COLOR_ALPHA surface), then don't accept subpixel aa. */ | |||
1772 | if (other->base.antialias != CAIRO_ANTIALIAS_DEFAULT) | |||
1773 | options->base.antialias = other->base.antialias; | |||
1774 | /* If the surface knows the subpixel order then use that. */ | |||
1775 | if (options->base.subpixel_order == CAIRO_SUBPIXEL_ORDER_DEFAULT) | |||
1776 | options->base.subpixel_order = other->base.subpixel_order; | |||
1777 | } | |||
1778 | ||||
1779 | if (options->base.hint_style == CAIRO_HINT_STYLE_DEFAULT) | |||
1780 | options->base.hint_style = other->base.hint_style; | |||
1781 | ||||
1782 | if (other->base.hint_style == CAIRO_HINT_STYLE_NONE) | |||
1783 | options->base.hint_style = CAIRO_HINT_STYLE_NONE; | |||
1784 | ||||
1785 | if (options->base.lcd_filter == CAIRO_LCD_FILTER_DEFAULT) | |||
1786 | options->base.lcd_filter = other->base.lcd_filter; | |||
1787 | ||||
1788 | if (other->base.lcd_filter == CAIRO_LCD_FILTER_NONE) | |||
1789 | options->base.lcd_filter = CAIRO_LCD_FILTER_NONE; | |||
1790 | ||||
1791 | if (options->base.antialias == CAIRO_ANTIALIAS_NONE) { | |||
1792 | if (options->base.hint_style == CAIRO_HINT_STYLE_NONE) | |||
1793 | load_flags |= FT_LOAD_NO_HINTING( 1L << 1 ); | |||
1794 | else | |||
1795 | load_target = FT_LOAD_TARGET_MONO( (FT_Int32)( (FT_RENDER_MODE_MONO) & 15 ) << 16 ); | |||
1796 | load_flags |= FT_LOAD_MONOCHROME( 1L << 12 ); | |||
1797 | } else { | |||
1798 | switch (options->base.hint_style) { | |||
1799 | case CAIRO_HINT_STYLE_NONE: | |||
1800 | load_flags |= FT_LOAD_NO_HINTING( 1L << 1 ); | |||
1801 | break; | |||
1802 | case CAIRO_HINT_STYLE_SLIGHT: | |||
1803 | load_target = FT_LOAD_TARGET_LIGHT( (FT_Int32)( (FT_RENDER_MODE_LIGHT) & 15 ) << 16 ); | |||
1804 | break; | |||
1805 | case CAIRO_HINT_STYLE_MEDIUM: | |||
1806 | break; | |||
1807 | case CAIRO_HINT_STYLE_FULL: | |||
1808 | case CAIRO_HINT_STYLE_DEFAULT: | |||
1809 | if (options->base.antialias == CAIRO_ANTIALIAS_SUBPIXEL) { | |||
1810 | switch (options->base.subpixel_order) { | |||
1811 | case CAIRO_SUBPIXEL_ORDER_DEFAULT: | |||
1812 | case CAIRO_SUBPIXEL_ORDER_RGB: | |||
1813 | case CAIRO_SUBPIXEL_ORDER_BGR: | |||
1814 | load_target = FT_LOAD_TARGET_LCD( (FT_Int32)( (FT_RENDER_MODE_LCD) & 15 ) << 16 ); | |||
1815 | break; | |||
1816 | case CAIRO_SUBPIXEL_ORDER_VRGB: | |||
1817 | case CAIRO_SUBPIXEL_ORDER_VBGR: | |||
1818 | load_target = FT_LOAD_TARGET_LCD_V( (FT_Int32)( (FT_RENDER_MODE_LCD_V) & 15 ) << 16 ); | |||
1819 | break; | |||
1820 | } | |||
1821 | } | |||
1822 | break; | |||
1823 | } | |||
1824 | } | |||
1825 | ||||
1826 | options->load_flags = load_flags | load_target; | |||
1827 | options->extra_flags = other->extra_flags; | |||
1828 | if (options->base.hint_metrics != CAIRO_HINT_METRICS_OFF) | |||
1829 | options->extra_flags |= CAIRO_FT_OPTIONS_HINT_METRICS; | |||
1830 | } | |||
1831 | ||||
1832 | static cairo_status_t | |||
1833 | _cairo_ft_font_face_scaled_font_create (void *abstract_font_face, | |||
1834 | const cairo_matrix_t *font_matrix, | |||
1835 | const cairo_matrix_t *ctm, | |||
1836 | const cairo_font_options_t *options, | |||
1837 | cairo_scaled_font_t **font_out) | |||
1838 | { | |||
1839 | cairo_ft_font_face_t *font_face = abstract_font_face; | |||
1840 | cairo_ft_scaled_font_t *scaled_font; | |||
1841 | FT_Face face; | |||
1842 | FT_Size_Metrics *metrics; | |||
1843 | cairo_font_extents_t fs_metrics; | |||
1844 | cairo_status_t status; | |||
1845 | cairo_ft_unscaled_font_t *unscaled; | |||
1846 | ||||
1847 | assert (font_face->unscaled)do { if (!(font_face->unscaled)) fprintf(stderr, "Assertion failed at %s:%d: %s\n" , "/home/sylvestre/dev/mozilla/ff/firefox.hg/gfx/cairo/cairo/src/cairo-ft-font.c" , 1847, "font_face->unscaled"); } while (0); | |||
1848 | ||||
1849 | face = _cairo_ft_unscaled_font_lock_face (font_face->unscaled); | |||
1850 | if (unlikely (face == NULL)(__builtin_expect (__extension__ ({ int _cairo_boolean_var_; if (face == ((void*)0)) _cairo_boolean_var_ = 1; else _cairo_boolean_var_ = 0; _cairo_boolean_var_; }), 0))) /* backend error */ | |||
1851 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); | |||
1852 | ||||
1853 | scaled_font = malloc (sizeof (cairo_ft_scaled_font_t)); | |||
1854 | if (unlikely (scaled_font == NULL)(__builtin_expect (__extension__ ({ int _cairo_boolean_var_; if (scaled_font == ((void*)0)) _cairo_boolean_var_ = 1; else _cairo_boolean_var_ = 0; _cairo_boolean_var_; }), 0))) { | |||
1855 | status = _cairo_error (CAIRO_STATUS_NO_MEMORY); | |||
1856 | goto FAIL; | |||
1857 | } | |||
1858 | ||||
1859 | scaled_font->unscaled = unscaled = font_face->unscaled; | |||
1860 | _cairo_unscaled_font_reference (&unscaled->base); | |||
1861 | ||||
1862 | _cairo_font_options_init_copy (&scaled_font->ft_options.base, options); | |||
1863 | _cairo_ft_options_merge (&scaled_font->ft_options, &font_face->ft_options); | |||
1864 | ||||
1865 | status = _cairo_scaled_font_init (&scaled_font->base, | |||
1866 | &font_face->base, | |||
1867 | font_matrix, ctm, options, | |||
1868 | &_cairo_ft_scaled_font_backend); | |||
1869 | if (unlikely (status)(__builtin_expect (__extension__ ({ int _cairo_boolean_var_; if (status) _cairo_boolean_var_ = 1; else _cairo_boolean_var_ = 0; _cairo_boolean_var_; }), 0))) | |||
1870 | goto CLEANUP_SCALED_FONT; | |||
1871 | ||||
1872 | status = _cairo_ft_unscaled_font_set_scale (unscaled, | |||
1873 | &scaled_font->base.scale); | |||
1874 | if (unlikely (status)(__builtin_expect (__extension__ ({ int _cairo_boolean_var_; if (status) _cairo_boolean_var_ = 1; else _cairo_boolean_var_ = 0; _cairo_boolean_var_; }), 0))) { | |||
1875 | /* This can only fail if we encounter an error with the underlying | |||
1876 | * font, so propagate the error back to the font-face. */ | |||
1877 | _cairo_ft_unscaled_font_unlock_face (unscaled); | |||
1878 | _cairo_unscaled_font_destroy (&unscaled->base); | |||
1879 | free (scaled_font); | |||
1880 | return status; | |||
1881 | } | |||
1882 | ||||
1883 | ||||
1884 | metrics = &face->size->metrics; | |||
1885 | ||||
1886 | /* | |||
1887 | * Get to unscaled metrics so that the upper level can get back to | |||
1888 | * user space | |||
1889 | * | |||
1890 | * Also use this path for bitmap-only fonts. The other branch uses | |||
1891 | * face members that are only relevant for scalable fonts. This is | |||
1892 | * detected by simply checking for units_per_EM==0. | |||
1893 | */ | |||
1894 | if (scaled_font->base.options.hint_metrics != CAIRO_HINT_METRICS_OFF || | |||
1895 | face->units_per_EM == 0) { | |||
1896 | double x_factor, y_factor; | |||
1897 | ||||
1898 | if (unscaled->x_scale == 0) | |||
1899 | x_factor = 0; | |||
1900 | else | |||
1901 | x_factor = 1 / unscaled->x_scale; | |||
1902 | ||||
1903 | if (unscaled->y_scale == 0) | |||
1904 | y_factor = 0; | |||
1905 | else | |||
1906 | y_factor = 1 / unscaled->y_scale; | |||
1907 | ||||
1908 | fs_metrics.ascent = DOUBLE_FROM_26_6(metrics->ascender)((double)(metrics->ascender) / 64.0) * y_factor; | |||
1909 | fs_metrics.descent = DOUBLE_FROM_26_6(- metrics->descender)((double)(- metrics->descender) / 64.0) * y_factor; | |||
1910 | fs_metrics.height = DOUBLE_FROM_26_6(metrics->height)((double)(metrics->height) / 64.0) * y_factor; | |||
1911 | if (!_cairo_ft_scaled_font_is_vertical (&scaled_font->base)) { | |||
1912 | fs_metrics.max_x_advance = DOUBLE_FROM_26_6(metrics->max_advance)((double)(metrics->max_advance) / 64.0) * x_factor; | |||
1913 | fs_metrics.max_y_advance = 0; | |||
1914 | } else { | |||
1915 | fs_metrics.max_x_advance = 0; | |||
1916 | fs_metrics.max_y_advance = DOUBLE_FROM_26_6(metrics->max_advance)((double)(metrics->max_advance) / 64.0) * y_factor; | |||
1917 | } | |||
1918 | } else { | |||
1919 | double scale = face->units_per_EM; | |||
1920 | ||||
1921 | fs_metrics.ascent = face->ascender / scale; | |||
1922 | fs_metrics.descent = - face->descender / scale; | |||
1923 | fs_metrics.height = face->height / scale; | |||
1924 | if (!_cairo_ft_scaled_font_is_vertical (&scaled_font->base)) { | |||
1925 | fs_metrics.max_x_advance = face->max_advance_width / scale; | |||
1926 | fs_metrics.max_y_advance = 0; | |||
1927 | } else { | |||
1928 | fs_metrics.max_x_advance = 0; | |||
1929 | fs_metrics.max_y_advance = face->max_advance_height / scale; | |||
1930 | } | |||
1931 | } | |||
1932 | ||||
1933 | status = _cairo_scaled_font_set_metrics (&scaled_font->base, &fs_metrics); | |||
1934 | if (unlikely (status)(__builtin_expect (__extension__ ({ int _cairo_boolean_var_; if (status) _cairo_boolean_var_ = 1; else _cairo_boolean_var_ = 0; _cairo_boolean_var_; }), 0))) | |||
1935 | goto CLEANUP_SCALED_FONT; | |||
1936 | ||||
1937 | _cairo_ft_unscaled_font_unlock_face (unscaled); | |||
1938 | ||||
1939 | *font_out = &scaled_font->base; | |||
1940 | return CAIRO_STATUS_SUCCESS; | |||
1941 | ||||
1942 | CLEANUP_SCALED_FONT: | |||
1943 | _cairo_unscaled_font_destroy (&unscaled->base); | |||
1944 | free (scaled_font); | |||
1945 | FAIL: | |||
1946 | _cairo_ft_unscaled_font_unlock_face (font_face->unscaled); | |||
1947 | *font_out = _cairo_scaled_font_create_in_error (status); | |||
1948 | return CAIRO_STATUS_SUCCESS; /* non-backend error */ | |||
1949 | } | |||
1950 | ||||
1951 | cairo_bool_t | |||
1952 | _cairo_scaled_font_is_ft (cairo_scaled_font_t *scaled_font) | |||
1953 | { | |||
1954 | return scaled_font->backend == &_cairo_ft_scaled_font_backend; | |||
1955 | } | |||
1956 | ||||
1957 | static void | |||
1958 | _cairo_ft_scaled_font_fini (void *abstract_font) | |||
1959 | { | |||
1960 | cairo_ft_scaled_font_t *scaled_font = abstract_font; | |||
1961 | ||||
1962 | if (scaled_font == NULL((void*)0)) | |||
1963 | return; | |||
1964 | ||||
1965 | _cairo_unscaled_font_destroy (&scaled_font->unscaled->base); | |||
1966 | } | |||
1967 | ||||
1968 | static int | |||
1969 | _move_to (FT_Vector *to, void *closure) | |||
1970 | { | |||
1971 | cairo_path_fixed_t *path = closure; | |||
1972 | cairo_fixed_t x, y; | |||
1973 | ||||
1974 | x = _cairo_fixed_from_26_6 (to->x); | |||
1975 | y = _cairo_fixed_from_26_6 (to->y); | |||
1976 | ||||
1977 | if (_cairo_path_fixed_close_path (path) != CAIRO_STATUS_SUCCESS) | |||
1978 | return 1; | |||
1979 | if (_cairo_path_fixed_move_to (path, x, y) != CAIRO_STATUS_SUCCESS) | |||
1980 | return 1; | |||
1981 | ||||
1982 | return 0; | |||
1983 | } | |||
1984 | ||||
1985 | static int | |||
1986 | _line_to (FT_Vector *to, void *closure) | |||
1987 | { | |||
1988 | cairo_path_fixed_t *path = closure; | |||
1989 | cairo_fixed_t x, y; | |||
1990 | ||||
1991 | x = _cairo_fixed_from_26_6 (to->x); | |||
1992 | y = _cairo_fixed_from_26_6 (to->y); | |||
1993 | ||||
1994 | if (_cairo_path_fixed_line_to (path, x, y) != CAIRO_STATUS_SUCCESS) | |||
1995 | return 1; | |||
1996 | ||||
1997 | return 0; | |||
1998 | } | |||
1999 | ||||
2000 | static int | |||
2001 | _conic_to (FT_Vector *control, FT_Vector *to, void *closure) | |||
2002 | { | |||
2003 | cairo_path_fixed_t *path = closure; | |||
2004 | ||||
2005 | cairo_fixed_t x0, y0; | |||
2006 | cairo_fixed_t x1, y1; | |||
2007 | cairo_fixed_t x2, y2; | |||
2008 | cairo_fixed_t x3, y3; | |||
2009 | cairo_point_t conic; | |||
2010 | ||||
2011 | if (! _cairo_path_fixed_get_current_point (path, &x0, &y0)) | |||
2012 | return 1; | |||
2013 | ||||
2014 | conic.x = _cairo_fixed_from_26_6 (control->x); | |||
2015 | conic.y = _cairo_fixed_from_26_6 (control->y); | |||
2016 | ||||
2017 | x3 = _cairo_fixed_from_26_6 (to->x); | |||
2018 | y3 = _cairo_fixed_from_26_6 (to->y); | |||
2019 | ||||
2020 | x1 = x0 + 2.0/3.0 * (conic.x - x0); | |||
2021 | y1 = y0 + 2.0/3.0 * (conic.y - y0); | |||
2022 | ||||
2023 | x2 = x3 + 2.0/3.0 * (conic.x - x3); | |||
2024 | y2 = y3 + 2.0/3.0 * (conic.y - y3); | |||
2025 | ||||
2026 | if (_cairo_path_fixed_curve_to (path, | |||
2027 | x1, y1, | |||
2028 | x2, y2, | |||
2029 | x3, y3) != CAIRO_STATUS_SUCCESS) | |||
2030 | return 1; | |||
2031 | ||||
2032 | return 0; | |||
2033 | } | |||
2034 | ||||
2035 | static int | |||
2036 | _cubic_to (FT_Vector *control1, FT_Vector *control2, | |||
2037 | FT_Vector *to, void *closure) | |||
2038 | { | |||
2039 | cairo_path_fixed_t *path = closure; | |||
2040 | cairo_fixed_t x0, y0; | |||
2041 | cairo_fixed_t x1, y1; | |||
2042 | cairo_fixed_t x2, y2; | |||
2043 | ||||
2044 | x0 = _cairo_fixed_from_26_6 (control1->x); | |||
2045 | y0 = _cairo_fixed_from_26_6 (control1->y); | |||
2046 | ||||
2047 | x1 = _cairo_fixed_from_26_6 (control2->x); | |||
2048 | y1 = _cairo_fixed_from_26_6 (control2->y); | |||
2049 | ||||
2050 | x2 = _cairo_fixed_from_26_6 (to->x); | |||
2051 | y2 = _cairo_fixed_from_26_6 (to->y); | |||
2052 | ||||
2053 | if (_cairo_path_fixed_curve_to (path, | |||
2054 | x0, y0, | |||
2055 | x1, y1, | |||
2056 | x2, y2) != CAIRO_STATUS_SUCCESS) | |||
2057 | return 1; | |||
2058 | ||||
2059 | return 0; | |||
2060 | } | |||
2061 | ||||
2062 | static cairo_status_t | |||
2063 | _decompose_glyph_outline (FT_Face face, | |||
2064 | cairo_font_options_t *options, | |||
2065 | cairo_path_fixed_t **pathp) | |||
2066 | { | |||
2067 | static const FT_Outline_Funcs outline_funcs = { | |||
2068 | (FT_Outline_MoveToFunc)_move_to, | |||
2069 | (FT_Outline_LineToFunc)_line_to, | |||
2070 | (FT_Outline_ConicToFunc)_conic_to, | |||
2071 | (FT_Outline_CubicToFunc)_cubic_to, | |||
2072 | 0, /* shift */ | |||
2073 | 0, /* delta */ | |||
2074 | }; | |||
2075 | static const FT_Matrix invert_y = { | |||
2076 | DOUBLE_TO_16_16 (1.0)((FT_Fixed)((1.0) * 65536.0)), 0, | |||
2077 | 0, DOUBLE_TO_16_16 (-1.0)((FT_Fixed)((-1.0) * 65536.0)), | |||
2078 | }; | |||
2079 | ||||
2080 | FT_GlyphSlot glyph; | |||
2081 | cairo_path_fixed_t *path; | |||
2082 | cairo_status_t status; | |||
2083 | ||||
2084 | path = _cairo_path_fixed_create (); | |||
2085 | if (!path) | |||
2086 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); | |||
2087 | ||||
2088 | glyph = face->glyph; | |||
2089 | ||||
2090 | /* Font glyphs have an inverted Y axis compared to cairo. */ | |||
2091 | FT_Outline_Transform (&glyph->outline, &invert_y); | |||
2092 | if (FT_Outline_Decompose (&glyph->outline, &outline_funcs, path)) { | |||
2093 | _cairo_path_fixed_destroy (path); | |||
2094 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); | |||
2095 | } | |||
2096 | ||||
2097 | status = _cairo_path_fixed_close_path (path); | |||
2098 | if (unlikely (status)(__builtin_expect (__extension__ ({ int _cairo_boolean_var_; if (status) _cairo_boolean_var_ = 1; else _cairo_boolean_var_ = 0; _cairo_boolean_var_; }), 0))) { | |||
2099 | _cairo_path_fixed_destroy (path); | |||
2100 | return status; | |||
2101 | } | |||
2102 | ||||
2103 | *pathp = path; | |||
2104 | ||||
2105 | return CAIRO_STATUS_SUCCESS; | |||
2106 | } | |||
2107 | ||||
2108 | /* | |||
2109 | * Translate glyph to match its metrics. | |||
2110 | */ | |||
2111 | static void | |||
2112 | _cairo_ft_scaled_glyph_vertical_layout_bearing_fix (void *abstract_font, | |||
2113 | FT_GlyphSlot glyph) | |||
2114 | { | |||
2115 | cairo_ft_scaled_font_t *scaled_font = abstract_font; | |||
2116 | FT_Vector vector; | |||
2117 | ||||
2118 | vector.x = glyph->metrics.vertBearingX - glyph->metrics.horiBearingX; | |||
2119 | vector.y = -glyph->metrics.vertBearingY - glyph->metrics.horiBearingY; | |||
2120 | ||||
2121 | if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) { | |||
2122 | FT_Vector_Transform (&vector, &scaled_font->unscaled->Current_Shape); | |||
2123 | FT_Outline_Translate(&glyph->outline, vector.x, vector.y); | |||
2124 | } else if (glyph->format == FT_GLYPH_FORMAT_BITMAP) { | |||
2125 | glyph->bitmap_left += vector.x / 64; | |||
2126 | glyph->bitmap_top += vector.y / 64; | |||
2127 | } | |||
2128 | } | |||
2129 | ||||
2130 | static cairo_int_status_t | |||
2131 | _cairo_ft_scaled_glyph_init (void *abstract_font, | |||
2132 | cairo_scaled_glyph_t *scaled_glyph, | |||
2133 | cairo_scaled_glyph_info_t info) | |||
2134 | { | |||
2135 | cairo_text_extents_t fs_metrics; | |||
2136 | cairo_ft_scaled_font_t *scaled_font = abstract_font; | |||
2137 | cairo_ft_unscaled_font_t *unscaled = scaled_font->unscaled; | |||
2138 | FT_GlyphSlot glyph; | |||
2139 | FT_Face face; | |||
2140 | FT_Error error; | |||
2141 | int load_flags = scaled_font->ft_options.load_flags; | |||
2142 | FT_Glyph_Metrics *metrics; | |||
2143 | double x_factor, y_factor; | |||
2144 | cairo_bool_t vertical_layout = FALSE0; | |||
2145 | cairo_status_t status; | |||
2146 | ||||
2147 | face = _cairo_ft_unscaled_font_lock_face (unscaled); | |||
2148 | if (!face) | |||
2149 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); | |||
2150 | ||||
2151 | status = _cairo_ft_unscaled_font_set_scale (scaled_font->unscaled, | |||
2152 | &scaled_font->base.scale); | |||
2153 | if (unlikely (status)(__builtin_expect (__extension__ ({ int _cairo_boolean_var_; if (status) _cairo_boolean_var_ = 1; else _cairo_boolean_var_ = 0; _cairo_boolean_var_; }), 0))) | |||
2154 | goto FAIL; | |||
2155 | ||||
2156 | /* Ignore global advance unconditionally */ | |||
2157 | load_flags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH( 1L << 9 ); | |||
2158 | ||||
2159 | if ((info & CAIRO_SCALED_GLYPH_INFO_PATH) != 0 && | |||
2160 | (info & CAIRO_SCALED_GLYPH_INFO_SURFACE) == 0) | |||
2161 | load_flags |= FT_LOAD_NO_BITMAP( 1L << 3 ); | |||
2162 | ||||
2163 | /* | |||
2164 | * Don't pass FT_LOAD_VERTICAL_LAYOUT to FT_Load_Glyph here as | |||
2165 | * suggested by freetype people. | |||
2166 | */ | |||
2167 | if (load_flags & FT_LOAD_VERTICAL_LAYOUT( 1L << 4 )) { | |||
2168 | load_flags &= ~FT_LOAD_VERTICAL_LAYOUT( 1L << 4 ); | |||
2169 | vertical_layout = TRUE1; | |||
2170 | } | |||
2171 | ||||
2172 | error = FT_Load_Glyph (scaled_font->unscaled->face, | |||
2173 | _cairo_scaled_glyph_index(scaled_glyph)((scaled_glyph)->hash_entry.hash), | |||
2174 | load_flags); | |||
2175 | /* XXX ignoring all other errors for now. They are not fatal, typically | |||
2176 | * just a glyph-not-found. */ | |||
2177 | if (error == FT_Err_Out_Of_Memory) { | |||
2178 | status = _cairo_error (CAIRO_STATUS_NO_MEMORY); | |||
2179 | goto FAIL; | |||
2180 | } | |||
2181 | ||||
2182 | glyph = face->glyph; | |||
2183 | ||||
2184 | #if HAVE_FT_GLYPHSLOT_EMBOLDEN1 | |||
2185 | /* | |||
2186 | * embolden glyphs if requested | |||
2187 | */ | |||
2188 | if (scaled_font->ft_options.extra_flags & CAIRO_FT_OPTIONS_EMBOLDEN) | |||
2189 | FT_GlyphSlot_Embolden (glyph); | |||
2190 | #endif | |||
2191 | ||||
2192 | if (vertical_layout) | |||
2193 | _cairo_ft_scaled_glyph_vertical_layout_bearing_fix (scaled_font, glyph); | |||
2194 | ||||
2195 | if (info & CAIRO_SCALED_GLYPH_INFO_METRICS) { | |||
2196 | ||||
2197 | cairo_bool_t hint_metrics = scaled_font->base.options.hint_metrics != CAIRO_HINT_METRICS_OFF; | |||
2198 | /* | |||
2199 | * Compute font-space metrics | |||
2200 | */ | |||
2201 | metrics = &glyph->metrics; | |||
2202 | ||||
2203 | if (unscaled->x_scale == 0) | |||
2204 | x_factor = 0; | |||
2205 | else | |||
2206 | x_factor = 1 / unscaled->x_scale; | |||
2207 | ||||
2208 | if (unscaled->y_scale == 0) | |||
2209 | y_factor = 0; | |||
2210 | else | |||
2211 | y_factor = 1 / unscaled->y_scale; | |||
2212 | ||||
2213 | /* | |||
2214 | * Note: Y coordinates of the horizontal bearing need to be negated. | |||
2215 | * | |||
2216 | * Scale metrics back to glyph space from the scaled glyph space returned | |||
2217 | * by FreeType | |||
2218 | * | |||
2219 | * If we want hinted metrics but aren't asking for hinted glyphs from | |||
2220 | * FreeType, then we need to do the metric hinting ourselves. | |||
2221 | */ | |||
2222 | ||||
2223 | if (hint_metrics && (load_flags & FT_LOAD_NO_HINTING( 1L << 1 ))) | |||
2224 | { | |||
2225 | FT_Pos x1, x2; | |||
2226 | FT_Pos y1, y2; | |||
2227 | FT_Pos advance; | |||
2228 | ||||
2229 | if (!vertical_layout) { | |||
2230 | x1 = (metrics->horiBearingX) & -64; | |||
2231 | x2 = (metrics->horiBearingX + metrics->width + 63) & -64; | |||
2232 | y1 = (-metrics->horiBearingY) & -64; | |||
2233 | y2 = (-metrics->horiBearingY + metrics->height + 63) & -64; | |||
2234 | ||||
2235 | advance = ((metrics->horiAdvance + 32) & -64); | |||
2236 | ||||
2237 | fs_metrics.x_bearing = DOUBLE_FROM_26_6 (x1)((double)(x1) / 64.0) * x_factor; | |||
2238 | fs_metrics.y_bearing = DOUBLE_FROM_26_6 (y1)((double)(y1) / 64.0) * y_factor; | |||
2239 | ||||
2240 | fs_metrics.width = DOUBLE_FROM_26_6 (x2 - x1)((double)(x2 - x1) / 64.0) * x_factor; | |||
2241 | fs_metrics.height = DOUBLE_FROM_26_6 (y2 - y1)((double)(y2 - y1) / 64.0) * y_factor; | |||
2242 | ||||
2243 | fs_metrics.x_advance = DOUBLE_FROM_26_6 (advance)((double)(advance) / 64.0) * x_factor; | |||
2244 | fs_metrics.y_advance = 0; | |||
2245 | } else { | |||
2246 | x1 = (metrics->vertBearingX) & -64; | |||
2247 | x2 = (metrics->vertBearingX + metrics->width + 63) & -64; | |||
2248 | y1 = (metrics->vertBearingY) & -64; | |||
2249 | y2 = (metrics->vertBearingY + metrics->height + 63) & -64; | |||
2250 | ||||
2251 | advance = ((metrics->vertAdvance + 32) & -64); | |||
2252 | ||||
2253 | fs_metrics.x_bearing = DOUBLE_FROM_26_6 (x1)((double)(x1) / 64.0) * x_factor; | |||
2254 | fs_metrics.y_bearing = DOUBLE_FROM_26_6 (y1)((double)(y1) / 64.0) * y_factor; | |||
2255 | ||||
2256 | fs_metrics.width = DOUBLE_FROM_26_6 (x2 - x1)((double)(x2 - x1) / 64.0) * x_factor; | |||
2257 | fs_metrics.height = DOUBLE_FROM_26_6 (y2 - y1)((double)(y2 - y1) / 64.0) * y_factor; | |||
2258 | ||||
2259 | fs_metrics.x_advance = 0; | |||
2260 | fs_metrics.y_advance = DOUBLE_FROM_26_6 (advance)((double)(advance) / 64.0) * y_factor; | |||
2261 | } | |||
2262 | } else { | |||
2263 | fs_metrics.width = DOUBLE_FROM_26_6 (metrics->width)((double)(metrics->width) / 64.0) * x_factor; | |||
2264 | fs_metrics.height = DOUBLE_FROM_26_6 (metrics->height)((double)(metrics->height) / 64.0) * y_factor; | |||
2265 | ||||
2266 | if (!vertical_layout) { | |||
2267 | fs_metrics.x_bearing = DOUBLE_FROM_26_6 (metrics->horiBearingX)((double)(metrics->horiBearingX) / 64.0) * x_factor; | |||
2268 | fs_metrics.y_bearing = DOUBLE_FROM_26_6 (-metrics->horiBearingY)((double)(-metrics->horiBearingY) / 64.0) * y_factor; | |||
2269 | ||||
2270 | if (hint_metrics || glyph->format != FT_GLYPH_FORMAT_OUTLINE) | |||
2271 | fs_metrics.x_advance = DOUBLE_FROM_26_6 (metrics->horiAdvance)((double)(metrics->horiAdvance) / 64.0) * x_factor; | |||
2272 | else | |||
2273 | fs_metrics.x_advance = DOUBLE_FROM_16_16 (glyph->linearHoriAdvance)((double)(glyph->linearHoriAdvance) / 65536.0) * x_factor; | |||
2274 | fs_metrics.y_advance = 0 * y_factor; | |||
2275 | } else { | |||
2276 | fs_metrics.x_bearing = DOUBLE_FROM_26_6 (metrics->vertBearingX)((double)(metrics->vertBearingX) / 64.0) * x_factor; | |||
2277 | fs_metrics.y_bearing = DOUBLE_FROM_26_6 (metrics->vertBearingY)((double)(metrics->vertBearingY) / 64.0) * y_factor; | |||
2278 | ||||
2279 | fs_metrics.x_advance = 0 * x_factor; | |||
2280 | if (hint_metrics || glyph->format != FT_GLYPH_FORMAT_OUTLINE) | |||
2281 | fs_metrics.y_advance = DOUBLE_FROM_26_6 (metrics->vertAdvance)((double)(metrics->vertAdvance) / 64.0) * y_factor; | |||
2282 | else | |||
2283 | fs_metrics.y_advance = DOUBLE_FROM_16_16 (glyph->linearVertAdvance)((double)(glyph->linearVertAdvance) / 65536.0) * y_factor; | |||
2284 | } | |||
2285 | } | |||
2286 | ||||
2287 | _cairo_scaled_glyph_set_metrics (scaled_glyph, | |||
2288 | &scaled_font->base, | |||
2289 | &fs_metrics); | |||
2290 | } | |||
2291 | ||||
2292 | if ((info & CAIRO_SCALED_GLYPH_INFO_SURFACE) != 0) { | |||
2293 | cairo_image_surface_t *surface; | |||
2294 | ||||
2295 | if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) { | |||
2296 | status = _render_glyph_outline (face, &scaled_font->ft_options.base, | |||
2297 | &surface); | |||
2298 | } else { | |||
2299 | status = _render_glyph_bitmap (face, &scaled_font->ft_options.base, | |||
2300 | &surface); | |||
2301 | if (likely (status == CAIRO_STATUS_SUCCESS)(__builtin_expect (__extension__ ({ int _cairo_boolean_var_; if (status == CAIRO_STATUS_SUCCESS) _cairo_boolean_var_ = 1; else _cairo_boolean_var_ = 0; _cairo_boolean_var_; }), 1)) && | |||
2302 | unscaled->have_shape) | |||
2303 | { | |||
2304 | status = _transform_glyph_bitmap (&unscaled->current_shape, | |||
2305 | &surface); | |||
2306 | if (unlikely (status)(__builtin_expect (__extension__ ({ int _cairo_boolean_var_; if (status) _cairo_boolean_var_ = 1; else _cairo_boolean_var_ = 0; _cairo_boolean_var_; }), 0))) | |||
2307 | cairo_surface_destroy_moz_cairo_surface_destroy (&surface->base); | |||
2308 | } | |||
2309 | } | |||
2310 | if (unlikely (status)(__builtin_expect (__extension__ ({ int _cairo_boolean_var_; if (status) _cairo_boolean_var_ = 1; else _cairo_boolean_var_ = 0; _cairo_boolean_var_; }), 0))) | |||
2311 | goto FAIL; | |||
2312 | ||||
2313 | _cairo_scaled_glyph_set_surface (scaled_glyph, | |||
2314 | &scaled_font->base, | |||
2315 | surface); | |||
2316 | } | |||
2317 | ||||
2318 | if (info & CAIRO_SCALED_GLYPH_INFO_PATH) { | |||
2319 | cairo_path_fixed_t *path = NULL((void*)0); /* hide compiler warning */ | |||
2320 | ||||
2321 | /* | |||
2322 | * A kludge -- the above code will trash the outline, | |||
2323 | * so reload it. This will probably never occur though | |||
2324 | */ | |||
2325 | if ((info & CAIRO_SCALED_GLYPH_INFO_SURFACE) != 0) { | |||
2326 | error = FT_Load_Glyph (face, | |||
2327 | _cairo_scaled_glyph_index(scaled_glyph)((scaled_glyph)->hash_entry.hash), | |||
2328 | load_flags | FT_LOAD_NO_BITMAP( 1L << 3 )); | |||
2329 | /* XXX ignoring all other errors for now. They are not fatal, typically | |||
2330 | * just a glyph-not-found. */ | |||
2331 | if (error == FT_Err_Out_Of_Memory) { | |||
2332 | status = _cairo_error (CAIRO_STATUS_NO_MEMORY); | |||
2333 | goto FAIL; | |||
2334 | } | |||
2335 | #if HAVE_FT_GLYPHSLOT_EMBOLDEN1 | |||
2336 | /* | |||
2337 | * embolden glyphs if requested | |||
2338 | */ | |||
2339 | if (scaled_font->ft_options.extra_flags & CAIRO_FT_OPTIONS_EMBOLDEN) | |||
2340 | FT_GlyphSlot_Embolden (glyph); | |||
2341 | #endif | |||
2342 | if (vertical_layout) | |||
2343 | _cairo_ft_scaled_glyph_vertical_layout_bearing_fix (scaled_font, glyph); | |||
2344 | ||||
2345 | } | |||
2346 | if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) | |||
2347 | status = _decompose_glyph_outline (face, &scaled_font->ft_options.base, | |||
2348 | &path); | |||
2349 | else | |||
2350 | status = CAIRO_INT_STATUS_UNSUPPORTED; | |||
2351 | ||||
2352 | if (unlikely (status)(__builtin_expect (__extension__ ({ int _cairo_boolean_var_; if (status) _cairo_boolean_var_ = 1; else _cairo_boolean_var_ = 0; _cairo_boolean_var_; }), 0))) | |||
2353 | goto FAIL; | |||
2354 | ||||
2355 | _cairo_scaled_glyph_set_path (scaled_glyph, | |||
2356 | &scaled_font->base, | |||
2357 | path); | |||
2358 | } | |||
2359 | FAIL: | |||
2360 | _cairo_ft_unscaled_font_unlock_face (unscaled); | |||
2361 | ||||
2362 | return status; | |||
2363 | } | |||
2364 | ||||
2365 | static unsigned long | |||
2366 | _cairo_ft_ucs4_to_index (void *abstract_font, | |||
2367 | uint32_t ucs4) | |||
2368 | { | |||
2369 | cairo_ft_scaled_font_t *scaled_font = abstract_font; | |||
2370 | cairo_ft_unscaled_font_t *unscaled = scaled_font->unscaled; | |||
2371 | FT_Face face; | |||
2372 | FT_UInt index; | |||
2373 | ||||
2374 | face = _cairo_ft_unscaled_font_lock_face (unscaled); | |||
2375 | if (!face) | |||
2376 | return 0; | |||
2377 | ||||
2378 | #if CAIRO_HAS_FC_FONT1 | |||
2379 | index = FcFreeTypeCharIndex (face, ucs4); | |||
2380 | #else | |||
2381 | index = FT_Get_Char_Index (face, ucs4); | |||
2382 | #endif | |||
2383 | ||||
2384 | _cairo_ft_unscaled_font_unlock_face (unscaled); | |||
2385 | return index; | |||
2386 | } | |||
2387 | ||||
2388 | static cairo_int_status_t | |||
2389 | _cairo_ft_load_truetype_table (void *abstract_font, | |||
2390 | unsigned long tag, | |||
2391 | long offset, | |||
2392 | unsigned char *buffer, | |||
2393 | unsigned long *length) | |||
2394 | { | |||
2395 | cairo_ft_scaled_font_t *scaled_font = abstract_font; | |||
2396 | cairo_ft_unscaled_font_t *unscaled = scaled_font->unscaled; | |||
2397 | FT_Face face; | |||
2398 | cairo_status_t status = CAIRO_INT_STATUS_UNSUPPORTED; | |||
2399 | ||||
2400 | if (_cairo_ft_scaled_font_is_vertical (&scaled_font->base)) | |||
2401 | return CAIRO_INT_STATUS_UNSUPPORTED; | |||
2402 | ||||
2403 | #if HAVE_FT_LOAD_SFNT_TABLE1 | |||
2404 | face = _cairo_ft_unscaled_font_lock_face (unscaled); | |||
2405 | if (!face) | |||
2406 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); | |||
2407 | ||||
2408 | if (FT_IS_SFNT (face)( face->face_flags & ( 1L << 3 ) ) && | |||
2409 | FT_Load_Sfnt_Table (face, tag, offset, buffer, length) == 0) | |||
2410 | status = CAIRO_STATUS_SUCCESS; | |||
2411 | ||||
2412 | _cairo_ft_unscaled_font_unlock_face (unscaled); | |||
2413 | #endif | |||
2414 | ||||
2415 | return status; | |||
2416 | } | |||
2417 | ||||
2418 | static cairo_int_status_t | |||
2419 | _cairo_ft_index_to_ucs4(void *abstract_font, | |||
2420 | unsigned long index, | |||
2421 | uint32_t *ucs4) | |||
2422 | { | |||
2423 | cairo_ft_scaled_font_t *scaled_font = abstract_font; | |||
2424 | cairo_ft_unscaled_font_t *unscaled = scaled_font->unscaled; | |||
2425 | FT_Face face; | |||
2426 | FT_ULong charcode; | |||
2427 | FT_UInt gindex; | |||
2428 | ||||
2429 | face = _cairo_ft_unscaled_font_lock_face (unscaled); | |||
2430 | if (!face) | |||
2431 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); | |||
2432 | ||||
2433 | *ucs4 = (uint32_t) -1; | |||
2434 | charcode = FT_Get_First_Char(face, &gindex); | |||
2435 | while (gindex != 0) { | |||
2436 | if (gindex == index) { | |||
2437 | *ucs4 = charcode; | |||
2438 | break; | |||
2439 | } | |||
2440 | charcode = FT_Get_Next_Char (face, charcode, &gindex); | |||
2441 | } | |||
2442 | ||||
2443 | _cairo_ft_unscaled_font_unlock_face (unscaled); | |||
2444 | ||||
2445 | return CAIRO_STATUS_SUCCESS; | |||
2446 | } | |||
2447 | ||||
2448 | static const cairo_scaled_font_backend_t _cairo_ft_scaled_font_backend = { | |||
2449 | CAIRO_FONT_TYPE_FT, | |||
2450 | _cairo_ft_scaled_font_fini, | |||
2451 | _cairo_ft_scaled_glyph_init, | |||
2452 | NULL((void*)0), /* text_to_glyphs */ | |||
2453 | _cairo_ft_ucs4_to_index, | |||
2454 | NULL((void*)0), /* show_glyphs */ | |||
2455 | _cairo_ft_load_truetype_table, | |||
2456 | _cairo_ft_index_to_ucs4 | |||
2457 | }; | |||
2458 | ||||
2459 | /* #cairo_ft_font_face_t */ | |||
2460 | ||||
2461 | #if CAIRO_HAS_FC_FONT1 | |||
2462 | static cairo_status_t | |||
2463 | _cairo_ft_font_face_create_for_pattern (FcPattern *pattern, | |||
2464 | cairo_font_face_t **out); | |||
2465 | ||||
2466 | static cairo_status_t | |||
2467 | _cairo_ft_font_face_create_for_toy (cairo_toy_font_face_t *toy_face, | |||
2468 | cairo_font_face_t **font_face) | |||
2469 | { | |||
2470 | FcPattern *pattern; | |||
2471 | int fcslant; | |||
2472 | int fcweight; | |||
2473 | cairo_status_t status = CAIRO_STATUS_SUCCESS; | |||
2474 | ||||
2475 | pattern = FcPatternCreate (); | |||
2476 | if (!pattern) | |||
2477 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); | |||
2478 | ||||
2479 | if (!FcPatternAddString (pattern, | |||
2480 | FC_FAMILY"family", (unsigned char *) toy_face->family)) | |||
2481 | { | |||
2482 | status = _cairo_error (CAIRO_STATUS_NO_MEMORY); | |||
2483 | goto FREE_PATTERN; | |||
2484 | } | |||
2485 | ||||
2486 | switch (toy_face->slant) | |||
2487 | { | |||
2488 | case CAIRO_FONT_SLANT_ITALIC: | |||
2489 | fcslant = FC_SLANT_ITALIC100; | |||
2490 | break; | |||
2491 | case CAIRO_FONT_SLANT_OBLIQUE: | |||
2492 | fcslant = FC_SLANT_OBLIQUE110; | |||
2493 | break; | |||
2494 | case CAIRO_FONT_SLANT_NORMAL: | |||
2495 | default: | |||
2496 | fcslant = FC_SLANT_ROMAN0; | |||
2497 | break; | |||
2498 | } | |||
2499 | ||||
2500 | if (!FcPatternAddInteger (pattern, FC_SLANT"slant", fcslant)) { | |||
2501 | status = _cairo_error (CAIRO_STATUS_NO_MEMORY); | |||
2502 | goto FREE_PATTERN; | |||
2503 | } | |||
2504 | ||||
2505 | switch (toy_face->weight) | |||
2506 | { | |||
2507 | case CAIRO_FONT_WEIGHT_BOLD: | |||
2508 | fcweight = FC_WEIGHT_BOLD200; | |||
2509 | break; | |||
2510 | case CAIRO_FONT_WEIGHT_NORMAL: | |||
2511 | default: | |||
2512 | fcweight = FC_WEIGHT_MEDIUM100; | |||
2513 | break; | |||
2514 | } | |||
2515 | ||||
2516 | if (!FcPatternAddInteger (pattern, FC_WEIGHT"weight", fcweight)) { | |||
2517 | status = _cairo_error (CAIRO_STATUS_NO_MEMORY); | |||
2518 | goto FREE_PATTERN; | |||
2519 | } | |||
2520 | ||||
2521 | status = _cairo_ft_font_face_create_for_pattern (pattern, font_face); | |||
2522 | ||||
2523 | FREE_PATTERN: | |||
2524 | FcPatternDestroy (pattern); | |||
2525 | ||||
2526 | return status; | |||
2527 | } | |||
2528 | #endif | |||
2529 | ||||
2530 | static void | |||
2531 | _cairo_ft_font_face_destroy (void *abstract_face) | |||
2532 | { | |||
2533 | cairo_ft_font_face_t *font_face = abstract_face; | |||
2534 | ||||
2535 | /* When destroying a face created by cairo_ft_font_face_create_for_ft_face, | |||
2536 | * we have a special "zombie" state for the face when the unscaled font | |||
2537 | * is still alive but there are no other references to a font face with | |||
2538 | * the same FT_Face. | |||
2539 | * | |||
2540 | * We go from: | |||
2541 | * | |||
2542 | * font_face ------> unscaled | |||
2543 | * <-....weak....../ | |||
2544 | * | |||
2545 | * To: | |||
2546 | * | |||
2547 | * font_face <------- unscaled | |||
2548 | */ | |||
2549 | ||||
2550 | if (font_face->unscaled && | |||
2551 | font_face->unscaled->from_face && | |||
2552 | font_face->next == NULL((void*)0) && | |||
2553 | font_face->unscaled->faces == font_face && | |||
2554 | CAIRO_REFERENCE_COUNT_GET_VALUE (&font_face->unscaled->base.ref_count)(*&(&font_face->unscaled->base.ref_count)->ref_count ) > 1) | |||
2555 | { | |||
2556 | cairo_font_face_reference_moz_cairo_font_face_reference (&font_face->base); | |||
2557 | ||||
2558 | _cairo_unscaled_font_destroy (&font_face->unscaled->base); | |||
2559 | font_face->unscaled = NULL((void*)0); | |||
2560 | ||||
2561 | return; | |||
2562 | } | |||
2563 | ||||
2564 | if (font_face->unscaled) { | |||
2565 | cairo_ft_font_face_t *tmp_face = NULL((void*)0); | |||
2566 | cairo_ft_font_face_t *last_face = NULL((void*)0); | |||
2567 | ||||
2568 | /* Remove face from linked list */ | |||
2569 | for (tmp_face = font_face->unscaled->faces; | |||
2570 | tmp_face; | |||
2571 | tmp_face = tmp_face->next) | |||
2572 | { | |||
2573 | if (tmp_face == font_face) { | |||
2574 | if (last_face) | |||
2575 | last_face->next = tmp_face->next; | |||
2576 | else | |||
2577 | font_face->unscaled->faces = tmp_face->next; | |||
2578 | } | |||
2579 | ||||
2580 | last_face = tmp_face; | |||
2581 | } | |||
2582 | ||||
2583 | _cairo_unscaled_font_destroy (&font_face->unscaled->base); | |||
2584 | font_face->unscaled = NULL((void*)0); | |||
2585 | } | |||
2586 | ||||
2587 | #if CAIRO_HAS_FC_FONT1 | |||
2588 | if (font_face->pattern) { | |||
2589 | FcPatternDestroy (font_face->pattern); | |||
2590 | cairo_font_face_destroy_moz_cairo_font_face_destroy (font_face->resolved_font_face); | |||
2591 | } | |||
2592 | #endif | |||
2593 | } | |||
2594 | ||||
2595 | static cairo_font_face_t * | |||
2596 | _cairo_ft_font_face_get_implementation (void *abstract_face, | |||
2597 | const cairo_matrix_t *font_matrix, | |||
2598 | const cairo_matrix_t *ctm, | |||
2599 | const cairo_font_options_t *options) | |||
2600 | { | |||
2601 | cairo_ft_font_face_t *font_face = abstract_face; | |||
2602 | ||||
2603 | /* The handling of font options is different depending on how the | |||
2604 | * font face was created. When the user creates a font face with | |||
2605 | * cairo_ft_font_face_create_for_ft_face(), then the load flags | |||
2606 | * passed in augment the load flags for the options. But for | |||
2607 | * cairo_ft_font_face_create_for_pattern(), the load flags are | |||
2608 | * derived from a pattern where the user has called | |||
2609 | * cairo_ft_font_options_substitute(), so *just* use those load | |||
2610 | * flags and ignore the options. | |||
2611 | */ | |||
2612 | ||||
2613 | #if CAIRO_HAS_FC_FONT1 | |||
2614 | /* If we have an unresolved pattern, resolve it and create | |||
2615 | * unscaled font. Otherwise, use the ones stored in font_face. | |||
2616 | */ | |||
2617 | if (font_face->pattern) { | |||
2618 | cairo_font_face_t *resolved; | |||
2619 | ||||
2620 | /* Cache the resolved font whilst the FcConfig remains consistent. */ | |||
2621 | resolved = font_face->resolved_font_face; | |||
2622 | if (resolved != NULL((void*)0)) { | |||
2623 | if (! FcInitBringUptoDate ()) { | |||
2624 | _cairo_error_throw (CAIRO_STATUS_NO_MEMORY)do { cairo_status_t status__ = _cairo_error (CAIRO_STATUS_NO_MEMORY ); (void) status__; } while (0); | |||
2625 | return (cairo_font_face_t *) &_cairo_font_face_nil; | |||
2626 | } | |||
2627 | ||||
2628 | if (font_face->resolved_config == FcConfigGetCurrent ()) | |||
2629 | return cairo_font_face_reference_moz_cairo_font_face_reference (resolved); | |||
2630 | ||||
2631 | cairo_font_face_destroy_moz_cairo_font_face_destroy (resolved); | |||
2632 | font_face->resolved_font_face = NULL((void*)0); | |||
2633 | } | |||
2634 | ||||
2635 | resolved = _cairo_ft_resolve_pattern (font_face->pattern, | |||
2636 | font_matrix, | |||
2637 | ctm, | |||
2638 | options); | |||
2639 | if (unlikely (resolved->status)(__builtin_expect (__extension__ ({ int _cairo_boolean_var_; if (resolved->status) _cairo_boolean_var_ = 1; else _cairo_boolean_var_ = 0; _cairo_boolean_var_; }), 0))) | |||
2640 | return resolved; | |||
2641 | ||||
2642 | font_face->resolved_font_face = cairo_font_face_reference_moz_cairo_font_face_reference (resolved); | |||
2643 | font_face->resolved_config = FcConfigGetCurrent (); | |||
2644 | ||||
2645 | return resolved; | |||
2646 | } | |||
2647 | #endif | |||
2648 | ||||
2649 | return abstract_face; | |||
2650 | } | |||
2651 | ||||
2652 | const cairo_font_face_backend_t _cairo_ft_font_face_backend = { | |||
2653 | CAIRO_FONT_TYPE_FT, | |||
2654 | #if CAIRO_HAS_FC_FONT1 | |||
2655 | _cairo_ft_font_face_create_for_toy, | |||
2656 | #else | |||
2657 | NULL((void*)0), | |||
2658 | #endif | |||
2659 | _cairo_ft_font_face_destroy, | |||
2660 | _cairo_ft_font_face_scaled_font_create, | |||
2661 | _cairo_ft_font_face_get_implementation | |||
2662 | }; | |||
2663 | ||||
2664 | #if CAIRO_HAS_FC_FONT1 | |||
2665 | static cairo_status_t | |||
2666 | _cairo_ft_font_face_create_for_pattern (FcPattern *pattern, | |||
2667 | cairo_font_face_t **out) | |||
2668 | { | |||
2669 | cairo_ft_font_face_t *font_face; | |||
2670 | ||||
2671 | font_face = malloc (sizeof (cairo_ft_font_face_t)); | |||
2672 | if (unlikely (font_face == NULL)(__builtin_expect (__extension__ ({ int _cairo_boolean_var_; if (font_face == ((void*)0)) _cairo_boolean_var_ = 1; else _cairo_boolean_var_ = 0; _cairo_boolean_var_; }), 0))) | |||
2673 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); | |||
2674 | ||||
2675 | font_face->unscaled = NULL((void*)0); | |||
2676 | font_face->next = NULL((void*)0); | |||
2677 | ||||
2678 | font_face->pattern = FcPatternDuplicate (pattern); | |||
2679 | if (unlikely (font_face->pattern == NULL)(__builtin_expect (__extension__ ({ int _cairo_boolean_var_; if (font_face->pattern == ((void*)0)) _cairo_boolean_var_ = 1 ; else _cairo_boolean_var_ = 0; _cairo_boolean_var_; }), 0))) { | |||
2680 | free (font_face); | |||
2681 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); | |||
2682 | } | |||
2683 | ||||
2684 | font_face->resolved_font_face = NULL((void*)0); | |||
2685 | font_face->resolved_config = NULL((void*)0); | |||
2686 | ||||
2687 | _cairo_font_face_init (&font_face->base, &_cairo_ft_font_face_backend); | |||
2688 | ||||
2689 | *out = &font_face->base; | |||
2690 | return CAIRO_STATUS_SUCCESS; | |||
2691 | } | |||
2692 | #endif | |||
2693 | ||||
2694 | static cairo_font_face_t * | |||
2695 | _cairo_ft_font_face_create (cairo_ft_unscaled_font_t *unscaled, | |||
2696 | cairo_ft_options_t *ft_options) | |||
2697 | { | |||
2698 | cairo_ft_font_face_t *font_face, **prev_font_face; | |||
2699 | ||||
2700 | /* Looked for an existing matching font face */ | |||
2701 | for (font_face = unscaled->faces, prev_font_face = &unscaled->faces; | |||
2702 | font_face; | |||
2703 | prev_font_face = &font_face->next, font_face = font_face->next) | |||
2704 | { | |||
2705 | if (font_face->ft_options.load_flags == ft_options->load_flags && | |||
2706 | font_face->ft_options.extra_flags == ft_options->extra_flags && | |||
2707 | cairo_font_options_equal_moz_cairo_font_options_equal (&font_face->ft_options.base, &ft_options->base)) | |||
2708 | { | |||
2709 | if (font_face->base.status) { | |||
2710 | /* The font_face has been left in an error state, abandon it. */ | |||
2711 | *prev_font_face = font_face->next; | |||
2712 | break; | |||
2713 | } | |||
2714 | ||||
2715 | if (font_face->unscaled == NULL((void*)0)) { | |||
2716 | /* Resurrect this "zombie" font_face (from | |||
2717 | * _cairo_ft_font_face_destroy), switching its unscaled_font | |||
2718 | * from owner to ownee. */ | |||
2719 | font_face->unscaled = unscaled; | |||
2720 | _cairo_unscaled_font_reference (&unscaled->base); | |||
2721 | return &font_face->base; | |||
2722 | } else | |||
2723 | return cairo_font_face_reference_moz_cairo_font_face_reference (&font_face->base); | |||
2724 | } | |||
2725 | } | |||
2726 | ||||
2727 | /* No match found, create a new one */ | |||
2728 | font_face = malloc (sizeof (cairo_ft_font_face_t)); | |||
2729 | if (unlikely (!font_face)(__builtin_expect (__extension__ ({ int _cairo_boolean_var_; if (!font_face) _cairo_boolean_var_ = 1; else _cairo_boolean_var_ = 0; _cairo_boolean_var_; }), 0))) { | |||
2730 | _cairo_error_throw (CAIRO_STATUS_NO_MEMORY)do { cairo_status_t status__ = _cairo_error (CAIRO_STATUS_NO_MEMORY ); (void) status__; } while (0); | |||
2731 | return (cairo_font_face_t *)&_cairo_font_face_nil; | |||
2732 | } | |||
2733 | ||||
2734 | font_face->unscaled = unscaled; | |||
2735 | _cairo_unscaled_font_reference (&unscaled->base); | |||
2736 | ||||
2737 | font_face->ft_options = *ft_options; | |||
2738 | ||||
2739 | if (unscaled->faces && unscaled->faces->unscaled == NULL((void*)0)) { | |||
2740 | /* This "zombie" font_face (from _cairo_ft_font_face_destroy) | |||
2741 | * is no longer needed. */ | |||
2742 | assert (unscaled->from_face && unscaled->faces->next == NULL)do { if (!(unscaled->from_face && unscaled->faces ->next == ((void*)0))) fprintf(stderr, "Assertion failed at %s:%d: %s\n" , "/home/sylvestre/dev/mozilla/ff/firefox.hg/gfx/cairo/cairo/src/cairo-ft-font.c" , 2742, "unscaled->from_face && unscaled->faces->next == NULL" ); } while (0); | |||
2743 | cairo_font_face_destroy_moz_cairo_font_face_destroy (&unscaled->faces->base); | |||
2744 | unscaled->faces = NULL((void*)0); | |||
2745 | } | |||
2746 | ||||
2747 | font_face->next = unscaled->faces; | |||
2748 | unscaled->faces = font_face; | |||
2749 | ||||
2750 | #if CAIRO_HAS_FC_FONT1 | |||
2751 | font_face->pattern = NULL((void*)0); | |||
2752 | #endif | |||
2753 | ||||
2754 | _cairo_font_face_init (&font_face->base, &_cairo_ft_font_face_backend); | |||
2755 | ||||
2756 | return &font_face->base; | |||
2757 | } | |||
2758 | ||||
2759 | /* implement the platform-specific interface */ | |||
2760 | ||||
2761 | #if CAIRO_HAS_FC_FONT1 | |||
2762 | static cairo_status_t | |||
2763 | _cairo_ft_font_options_substitute (const cairo_font_options_t *options, | |||
2764 | FcPattern *pattern) | |||
2765 | { | |||
2766 | FcValue v; | |||
2767 | ||||
2768 | if (options->antialias != CAIRO_ANTIALIAS_DEFAULT) | |||
2769 | { | |||
2770 | if (FcPatternGet (pattern, FC_ANTIALIAS"antialias", 0, &v) == FcResultNoMatch) | |||
2771 | { | |||
2772 | if (! FcPatternAddBool (pattern, | |||
2773 | FC_ANTIALIAS"antialias", | |||
2774 | options->antialias != CAIRO_ANTIALIAS_NONE)) | |||
2775 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); | |||
2776 | ||||
2777 | if (options->antialias != CAIRO_ANTIALIAS_SUBPIXEL) { | |||
2778 | FcPatternDel (pattern, FC_RGBA"rgba"); | |||
2779 | if (! FcPatternAddInteger (pattern, FC_RGBA"rgba", FC_RGBA_NONE5)) | |||
2780 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); | |||
2781 | } | |||
2782 | } | |||
2783 | } | |||
2784 | ||||
2785 | if (options->antialias != CAIRO_ANTIALIAS_DEFAULT) | |||
2786 | { | |||
2787 | if (FcPatternGet (pattern, FC_RGBA"rgba", 0, &v) == FcResultNoMatch) | |||
2788 | { | |||
2789 | int rgba; | |||
2790 | ||||
2791 | if (options->antialias == CAIRO_ANTIALIAS_SUBPIXEL) { | |||
2792 | switch (options->subpixel_order) { | |||
2793 | case CAIRO_SUBPIXEL_ORDER_DEFAULT: | |||
2794 | case CAIRO_SUBPIXEL_ORDER_RGB: | |||
2795 | default: | |||
2796 | rgba = FC_RGBA_RGB1; | |||
2797 | break; | |||
2798 | case CAIRO_SUBPIXEL_ORDER_BGR: | |||
2799 | rgba = FC_RGBA_BGR2; | |||
2800 | break; | |||
2801 | case CAIRO_SUBPIXEL_ORDER_VRGB: | |||
2802 | rgba = FC_RGBA_VRGB3; | |||
2803 | break; | |||
2804 | case CAIRO_SUBPIXEL_ORDER_VBGR: | |||
2805 | rgba = FC_RGBA_VBGR4; | |||
2806 | break; | |||
2807 | } | |||
2808 | } else { | |||
2809 | rgba = FC_RGBA_NONE5; | |||
2810 | } | |||
2811 | ||||
2812 | if (! FcPatternAddInteger (pattern, FC_RGBA"rgba", rgba)) | |||
2813 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); | |||
2814 | } | |||
2815 | } | |||
2816 | ||||
2817 | if (options->lcd_filter != CAIRO_LCD_FILTER_DEFAULT) | |||
2818 | { | |||
2819 | if (FcPatternGet (pattern, FC_LCD_FILTER"lcdfilter", 0, &v) == FcResultNoMatch) | |||
2820 | { | |||
2821 | int lcd_filter; | |||
2822 | ||||
2823 | switch (options->lcd_filter) { | |||
2824 | case CAIRO_LCD_FILTER_NONE: | |||
2825 | lcd_filter = FT_LCD_FILTER_NONE0; | |||
2826 | break; | |||
2827 | case CAIRO_LCD_FILTER_DEFAULT: | |||
2828 | case CAIRO_LCD_FILTER_INTRA_PIXEL: | |||
2829 | lcd_filter = FT_LCD_FILTER_LEGACY16; | |||
2830 | break; | |||
2831 | case CAIRO_LCD_FILTER_FIR3: | |||
2832 | lcd_filter = FT_LCD_FILTER_LIGHT2; | |||
2833 | break; | |||
2834 | default: | |||
2835 | case CAIRO_LCD_FILTER_FIR5: | |||
2836 | lcd_filter = FT_LCD_FILTER_DEFAULT1; | |||
2837 | break; | |||
2838 | } | |||
2839 | ||||
2840 | if (! FcPatternAddInteger (pattern, FC_LCD_FILTER"lcdfilter", lcd_filter)) | |||
2841 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); | |||
2842 | } | |||
2843 | } | |||
2844 | ||||
2845 | if (options->hint_style != CAIRO_HINT_STYLE_DEFAULT) | |||
2846 | { | |||
2847 | if (FcPatternGet (pattern, FC_HINTING"hinting", 0, &v) == FcResultNoMatch) | |||
2848 | { | |||
2849 | if (! FcPatternAddBool (pattern, | |||
2850 | FC_HINTING"hinting", | |||
2851 | options->hint_style != CAIRO_HINT_STYLE_NONE)) | |||
2852 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); | |||
2853 | } | |||
2854 | ||||
2855 | #ifdef FC_HINT_STYLE"hintstyle" | |||
2856 | if (FcPatternGet (pattern, FC_HINT_STYLE"hintstyle", 0, &v) == FcResultNoMatch) | |||
2857 | { | |||
2858 | int hint_style; | |||
2859 | ||||
2860 | switch (options->hint_style) { | |||
2861 | case CAIRO_HINT_STYLE_NONE: | |||
2862 | hint_style = FC_HINT_NONE0; | |||
2863 | break; | |||
2864 | case CAIRO_HINT_STYLE_SLIGHT: | |||
2865 | hint_style = FC_HINT_SLIGHT1; | |||
2866 | break; | |||
2867 | case CAIRO_HINT_STYLE_MEDIUM: | |||
2868 | hint_style = FC_HINT_MEDIUM2; | |||
2869 | break; | |||
2870 | case CAIRO_HINT_STYLE_FULL: | |||
2871 | case CAIRO_HINT_STYLE_DEFAULT: | |||
2872 | default: | |||
2873 | hint_style = FC_HINT_FULL3; | |||
2874 | break; | |||
2875 | } | |||
2876 | ||||
2877 | if (! FcPatternAddInteger (pattern, FC_HINT_STYLE"hintstyle", hint_style)) | |||
2878 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); | |||
2879 | } | |||
2880 | #endif | |||
2881 | } | |||
2882 | ||||
2883 | return CAIRO_STATUS_SUCCESS; | |||
2884 | } | |||
2885 | ||||
2886 | /** | |||
2887 | * cairo_ft_font_options_substitute: | |||
2888 | * @options: a #cairo_font_options_t object | |||
2889 | * @pattern: an existing #FcPattern | |||
2890 | * | |||
2891 | * Add options to a #FcPattern based on a #cairo_font_options_t font | |||
2892 | * options object. Options that are already in the pattern, are not overridden, | |||
2893 | * so you should call this function after calling FcConfigSubstitute() (the | |||
2894 | * user's settings should override options based on the surface type), but | |||
2895 | * before calling FcDefaultSubstitute(). | |||
2896 | **/ | |||
2897 | void | |||
2898 | cairo_ft_font_options_substitute_moz_cairo_ft_font_options_substitute (const cairo_font_options_t *options, | |||
2899 | FcPattern *pattern) | |||
2900 | { | |||
2901 | if (cairo_font_options_status_moz_cairo_font_options_status ((cairo_font_options_t *) options)) | |||
2902 | return; | |||
2903 | ||||
2904 | _cairo_ft_font_options_substitute (options, pattern); | |||
2905 | } | |||
2906 | ||||
2907 | static cairo_font_face_t * | |||
2908 | _cairo_ft_resolve_pattern (FcPattern *pattern, | |||
2909 | const cairo_matrix_t *font_matrix, | |||
2910 | const cairo_matrix_t *ctm, | |||
2911 | const cairo_font_options_t *font_options) | |||
2912 | { | |||
2913 | cairo_status_t status; | |||
2914 | ||||
2915 | cairo_matrix_t scale; | |||
2916 | FcPattern *resolved; | |||
2917 | cairo_ft_font_transform_t sf; | |||
2918 | FcResult result; | |||
2919 | cairo_ft_unscaled_font_t *unscaled; | |||
2920 | cairo_ft_options_t ft_options; | |||
2921 | cairo_font_face_t *font_face; | |||
2922 | ||||
2923 | scale = *ctm; | |||
2924 | scale.x0 = scale.y0 = 0; | |||
2925 | cairo_matrix_multiply_moz_cairo_matrix_multiply (&scale, | |||
2926 | font_matrix, | |||
2927 | &scale); | |||
2928 | ||||
2929 | status = _compute_transform (&sf, &scale); | |||
2930 | if (unlikely (status)(__builtin_expect (__extension__ ({ int _cairo_boolean_var_; if (status) _cairo_boolean_var_ = 1; else _cairo_boolean_var_ = 0; _cairo_boolean_var_; }), 0))) | |||
2931 | return (cairo_font_face_t *)&_cairo_font_face_nil; | |||
2932 | ||||
2933 | pattern = FcPatternDuplicate (pattern); | |||
2934 | if (pattern == NULL((void*)0)) | |||
2935 | return (cairo_font_face_t *)&_cairo_font_face_nil; | |||
2936 | ||||
2937 | if (! FcPatternAddDouble (pattern, FC_PIXEL_SIZE"pixelsize", sf.y_scale)) { | |||
2938 | font_face = (cairo_font_face_t *)&_cairo_font_face_nil; | |||
2939 | goto FREE_PATTERN; | |||
2940 | } | |||
2941 | ||||
2942 | if (! FcConfigSubstitute (NULL((void*)0), pattern, FcMatchPattern)) { | |||
2943 | font_face = (cairo_font_face_t *)&_cairo_font_face_nil; | |||
2944 | goto FREE_PATTERN; | |||
2945 | } | |||
2946 | ||||
2947 | status = _cairo_ft_font_options_substitute (font_options, pattern); | |||
2948 | if (status) { | |||
2949 | font_face = (cairo_font_face_t *)&_cairo_font_face_nil; | |||
2950 | goto FREE_PATTERN; | |||
2951 | } | |||
2952 | ||||
2953 | FcDefaultSubstitute (pattern); | |||
2954 | ||||
2955 | resolved = FcFontMatch (NULL((void*)0), pattern, &result); | |||
2956 | if (!resolved) { | |||
2957 | /* We failed to find any font. Substitute twin so that the user can | |||
2958 | * see something (and hopefully recognise that the font is missing) | |||
2959 | * and not just receive a NO_MEMORY error during rendering. | |||
2960 | */ | |||
2961 | font_face = _cairo_font_face_twin_create_fallback (); | |||
2962 | goto FREE_PATTERN; | |||
2963 | } | |||
2964 | ||||
2965 | status = _cairo_ft_unscaled_font_create_for_pattern (resolved, &unscaled); | |||
2966 | if (unlikely (status || unscaled == NULL)(__builtin_expect (__extension__ ({ int _cairo_boolean_var_; if (status || unscaled == ((void*)0)) _cairo_boolean_var_ = 1; else _cairo_boolean_var_ = 0; _cairo_boolean_var_; }), 0))) { | |||
2967 | font_face = (cairo_font_face_t *)&_cairo_font_face_nil; | |||
2968 | goto FREE_RESOLVED; | |||
2969 | } | |||
2970 | ||||
2971 | _get_pattern_ft_options (resolved, &ft_options); | |||
2972 | font_face = _cairo_ft_font_face_create (unscaled, &ft_options); | |||
2973 | _cairo_unscaled_font_destroy (&unscaled->base); | |||
2974 | ||||
2975 | FREE_RESOLVED: | |||
2976 | FcPatternDestroy (resolved); | |||
2977 | ||||
2978 | FREE_PATTERN: | |||
2979 | FcPatternDestroy (pattern); | |||
2980 | ||||
2981 | return font_face; | |||
2982 | } | |||
2983 | ||||
2984 | /** | |||
2985 | * cairo_ft_font_face_create_for_pattern: | |||
2986 | * @pattern: A fontconfig pattern. Cairo makes a copy of the pattern | |||
2987 | * if it needs to. You are free to modify or free @pattern after this call. | |||
2988 | * | |||
2989 | * Creates a new font face for the FreeType font backend based on a | |||
2990 | * fontconfig pattern. This font can then be used with | |||
2991 | * cairo_set_font_face() or cairo_scaled_font_create(). The | |||
2992 | * #cairo_scaled_font_t returned from cairo_scaled_font_create() is | |||
2993 | * also for the FreeType backend and can be used with functions such | |||
2994 | * as cairo_ft_scaled_font_lock_face(). | |||
2995 | * | |||
2996 | * Font rendering options are represented both here and when you | |||
2997 | * call cairo_scaled_font_create(). Font options that have a representation | |||
2998 | * in a #FcPattern must be passed in here; to modify #FcPattern | |||
2999 | * appropriately to reflect the options in a #cairo_font_options_t, call | |||
3000 | * cairo_ft_font_options_substitute(). | |||
3001 | * | |||
3002 | * The pattern's FC_FT_FACE element is inspected first and if that is set, | |||
3003 | * that will be the FreeType font face associated with the returned cairo | |||
3004 | * font face. Otherwise the FC_FILE element is checked. If it's set, | |||
3005 | * that and the value of the FC_INDEX element (defaults to zero) of @pattern | |||
3006 | * are used to load a font face from file. | |||
3007 | * | |||
3008 | * If both steps from the previous paragraph fails, @pattern will be passed | |||
3009 | * to FcConfigSubstitute, FcDefaultSubstitute, and finally FcFontMatch, | |||
3010 | * and the resulting font pattern is used. | |||
3011 | * | |||
3012 | * If the FC_FT_FACE element of @pattern is set, the user is responsible | |||
3013 | * for making sure that the referenced FT_Face remains valid for the life | |||
3014 | * time of the returned #cairo_font_face_t. See | |||
3015 | * cairo_ft_font_face_create_for_ft_face() for an exmaple of how to couple | |||
3016 | * the life time of the FT_Face to that of the cairo font-face. | |||
3017 | * | |||
3018 | * Return value: a newly created #cairo_font_face_t. Free with | |||
3019 | * cairo_font_face_destroy() when you are done using it. | |||
3020 | **/ | |||
3021 | cairo_font_face_t * | |||
3022 | cairo_ft_font_face_create_for_pattern_moz_cairo_ft_font_face_create_for_pattern (FcPattern *pattern) | |||
3023 | { | |||
3024 | cairo_ft_unscaled_font_t *unscaled; | |||
3025 | cairo_font_face_t *font_face; | |||
3026 | cairo_ft_options_t ft_options; | |||
3027 | cairo_status_t status; | |||
3028 | ||||
3029 | status = _cairo_ft_unscaled_font_create_for_pattern (pattern, &unscaled); | |||
3030 | if (unlikely (status)(__builtin_expect (__extension__ ({ int _cairo_boolean_var_; if (status) _cairo_boolean_var_ = 1; else _cairo_boolean_var_ = 0; _cairo_boolean_var_; }), 0))) | |||
3031 | return (cairo_font_face_t *) &_cairo_font_face_nil; | |||
3032 | if (unlikely (unscaled == NULL)(__builtin_expect (__extension__ ({ int _cairo_boolean_var_; if (unscaled == ((void*)0)) _cairo_boolean_var_ = 1; else _cairo_boolean_var_ = 0; _cairo_boolean_var_; }), 0))) { | |||
3033 | /* Store the pattern. We will resolve it and create unscaled | |||
3034 | * font when creating scaled fonts */ | |||
3035 | status = _cairo_ft_font_face_create_for_pattern (pattern, | |||
3036 | &font_face); | |||
3037 | if (unlikely (status)(__builtin_expect (__extension__ ({ int _cairo_boolean_var_; if (status) _cairo_boolean_var_ = 1; else _cairo_boolean_var_ = 0; _cairo_boolean_var_; }), 0))) | |||
3038 | return (cairo_font_face_t *) &_cairo_font_face_nil; | |||
3039 | ||||
3040 | return font_face; | |||
3041 | } | |||
3042 | ||||
3043 | _get_pattern_ft_options (pattern, &ft_options); | |||
3044 | font_face = _cairo_ft_font_face_create (unscaled, &ft_options); | |||
3045 | _cairo_unscaled_font_destroy (&unscaled->base); | |||
3046 | ||||
3047 | return font_face; | |||
3048 | } | |||
3049 | #endif | |||
3050 | ||||
3051 | /** | |||
3052 | * cairo_ft_font_face_create_for_ft_face: | |||
3053 | * @face: A FreeType face object, already opened. This must | |||
3054 | * be kept around until the face's ref_count drops to | |||
3055 | * zero and it is freed. Since the face may be referenced | |||
3056 | * internally to Cairo, the best way to determine when it | |||
3057 | * is safe to free the face is to pass a | |||
3058 | * #cairo_destroy_func_t to cairo_font_face_set_user_data() | |||
3059 | * @load_flags: flags to pass to FT_Load_Glyph when loading | |||
3060 | * glyphs from the font. These flags are OR'ed together with | |||
3061 | * the flags derived from the #cairo_font_options_t passed | |||
3062 | * to cairo_scaled_font_create(), so only a few values such | |||
3063 | * as %FT_LOAD_VERTICAL_LAYOUT, and %FT_LOAD_FORCE_AUTOHINT | |||
3064 | * are useful. You should not pass any of the flags affecting | |||
3065 | * the load target, such as %FT_LOAD_TARGET_LIGHT. | |||
3066 | * | |||
3067 | * Creates a new font face for the FreeType font backend from a | |||
3068 | * pre-opened FreeType face. This font can then be used with | |||
3069 | * cairo_set_font_face() or cairo_scaled_font_create(). The | |||
3070 | * #cairo_scaled_font_t returned from cairo_scaled_font_create() is | |||
3071 | * also for the FreeType backend and can be used with functions such | |||
3072 | * as cairo_ft_scaled_font_lock_face(). Note that Cairo may keep a reference | |||
3073 | * to the FT_Face alive in a font-cache and the exact lifetime of the reference | |||
3074 | * depends highly upon the exact usage pattern and is subject to external | |||
3075 | * factors. You must not call FT_Done_Face() before the last reference to the | |||
3076 | * #cairo_font_face_t has been dropped. | |||
3077 | * | |||
3078 | * As an example, below is how one might correctly couple the lifetime of | |||
3079 | * the FreeType face object to the #cairo_font_face_t. | |||
3080 | * | |||
3081 | * <informalexample><programlisting> | |||
3082 | * static const cairo_user_data_key_t key; | |||
3083 | * | |||
3084 | * font_face = cairo_ft_font_face_create_for_ft_face (ft_face, 0); | |||
3085 | * status = cairo_font_face_set_user_data (font_face, &key, | |||
3086 | * ft_face, (cairo_destroy_func_t) FT_Done_Face); | |||
3087 | * if (status) { | |||
3088 | * cairo_font_face_destroy (font_face); | |||
3089 | * FT_Done_Face (ft_face); | |||
3090 | * return ERROR; | |||
3091 | * } | |||
3092 | * </programlisting></informalexample> | |||
3093 | * | |||
3094 | * Return value: a newly created #cairo_font_face_t. Free with | |||
3095 | * cairo_font_face_destroy() when you are done using it. | |||
3096 | **/ | |||
3097 | cairo_font_face_t * | |||
3098 | cairo_ft_font_face_create_for_ft_face_moz_cairo_ft_font_face_create_for_ft_face (FT_Face face, | |||
3099 | int load_flags) | |||
3100 | { | |||
3101 | cairo_ft_unscaled_font_t *unscaled; | |||
3102 | cairo_font_face_t *font_face; | |||
3103 | cairo_ft_options_t ft_options; | |||
3104 | cairo_status_t status; | |||
3105 | ||||
3106 | status = _cairo_ft_unscaled_font_create_from_face (face, &unscaled); | |||
3107 | if (unlikely (status)(__builtin_expect (__extension__ ({ int _cairo_boolean_var_; if (status) _cairo_boolean_var_ = 1; else _cairo_boolean_var_ = 0; _cairo_boolean_var_; }), 0))) | |||
3108 | return (cairo_font_face_t *)&_cairo_font_face_nil; | |||
3109 | ||||
3110 | ft_options.load_flags = load_flags; | |||
3111 | ft_options.extra_flags = 0; | |||
3112 | _cairo_font_options_init_default (&ft_options.base); | |||
3113 | ||||
3114 | font_face = _cairo_ft_font_face_create (unscaled, &ft_options); | |||
3115 | _cairo_unscaled_font_destroy (&unscaled->base); | |||
3116 | ||||
3117 | return font_face; | |||
3118 | } | |||
3119 | ||||
3120 | /** | |||
3121 | * cairo_ft_scaled_font_lock_face: | |||
3122 | * @scaled_font: A #cairo_scaled_font_t from the FreeType font backend. Such an | |||
3123 | * object can be created by calling cairo_scaled_font_create() on a | |||
3124 | * FreeType backend font face (see cairo_ft_font_face_create_for_pattern(), | |||
3125 | * cairo_ft_font_face_create_for_ft_face()). | |||
3126 | * | |||
3127 | * cairo_ft_scaled_font_lock_face() gets the #FT_Face object from a FreeType | |||
3128 | * backend font and scales it appropriately for the font. You must | |||
3129 | * release the face with cairo_ft_scaled_font_unlock_face() | |||
3130 | * when you are done using it. Since the #FT_Face object can be | |||
3131 | * shared between multiple #cairo_scaled_font_t objects, you must not | |||
3132 | * lock any other font objects until you unlock this one. A count is | |||
3133 | * kept of the number of times cairo_ft_scaled_font_lock_face() is | |||
3134 | * called. cairo_ft_scaled_font_unlock_face() must be called the same number | |||
3135 | * of times. | |||
3136 | * | |||
3137 | * You must be careful when using this function in a library or in a | |||
3138 | * threaded application, because freetype's design makes it unsafe to | |||
3139 | * call freetype functions simultaneously from multiple threads, (even | |||
3140 | * if using distinct FT_Face objects). Because of this, application | |||
3141 | * code that acquires an FT_Face object with this call must add its | |||
3142 | * own locking to protect any use of that object, (and which also must | |||
3143 | * protect any other calls into cairo as almost any cairo function | |||
3144 | * might result in a call into the freetype library). | |||
3145 | * | |||
3146 | * Return value: The #FT_Face object for @font, scaled appropriately, | |||
3147 | * or %NULL if @scaled_font is in an error state (see | |||
3148 | * cairo_scaled_font_status()) or there is insufficient memory. | |||
3149 | **/ | |||
3150 | FT_Face | |||
3151 | cairo_ft_scaled_font_lock_face_moz_cairo_ft_scaled_font_lock_face (cairo_scaled_font_t *abstract_font) | |||
3152 | { | |||
3153 | cairo_ft_scaled_font_t *scaled_font = (cairo_ft_scaled_font_t *) abstract_font; | |||
3154 | FT_Face face; | |||
3155 | cairo_status_t status; | |||
3156 | ||||
3157 | if (! _cairo_scaled_font_is_ft (abstract_font)) { | |||
3158 | _cairo_error_throw (CAIRO_STATUS_FONT_TYPE_MISMATCH)do { cairo_status_t status__ = _cairo_error (CAIRO_STATUS_FONT_TYPE_MISMATCH ); (void) status__; } while (0); | |||
3159 | return NULL((void*)0); | |||
3160 | } | |||
3161 | ||||
3162 | if (scaled_font->base.status) | |||
3163 | return NULL((void*)0); | |||
3164 | ||||
3165 | face = _cairo_ft_unscaled_font_lock_face (scaled_font->unscaled); | |||
3166 | if (unlikely (face == NULL)(__builtin_expect (__extension__ ({ int _cairo_boolean_var_; if (face == ((void*)0)) _cairo_boolean_var_ = 1; else _cairo_boolean_var_ = 0; _cairo_boolean_var_; }), 0))) { | |||
3167 | status = _cairo_scaled_font_set_error (&scaled_font->base, CAIRO_STATUS_NO_MEMORY); | |||
3168 | return NULL((void*)0); | |||
3169 | } | |||
3170 | ||||
3171 | status = _cairo_ft_unscaled_font_set_scale (scaled_font->unscaled, | |||
3172 | &scaled_font->base.scale); | |||
3173 | if (unlikely (status)(__builtin_expect (__extension__ ({ int _cairo_boolean_var_; if (status) _cairo_boolean_var_ = 1; else _cairo_boolean_var_ = 0; _cairo_boolean_var_; }), 0))) { | |||
3174 | _cairo_ft_unscaled_font_unlock_face (scaled_font->unscaled); | |||
3175 | status = _cairo_scaled_font_set_error (&scaled_font->base, status); | |||
3176 | return NULL((void*)0); | |||
3177 | } | |||
3178 | ||||
3179 | /* Note: We deliberately release the unscaled font's mutex here, | |||
3180 | * so that we are not holding a lock across two separate calls to | |||
3181 | * cairo function, (which would give the application some | |||
3182 | * opportunity for creating deadlock. This is obviously unsafe, | |||
3183 | * but as documented, the user must add manual locking when using | |||
3184 | * this function. */ | |||
3185 | CAIRO_MUTEX_UNLOCK (scaled_font->unscaled->mutex)pthread_mutex_unlock (&(scaled_font->unscaled->mutex )); | |||
3186 | ||||
3187 | return face; | |||
3188 | } | |||
3189 | ||||
3190 | /** | |||
3191 | * cairo_ft_scaled_font_unlock_face: | |||
3192 | * @scaled_font: A #cairo_scaled_font_t from the FreeType font backend. Such an | |||
3193 | * object can be created by calling cairo_scaled_font_create() on a | |||
3194 | * FreeType backend font face (see cairo_ft_font_face_create_for_pattern(), | |||
3195 | * cairo_ft_font_face_create_for_ft_face()). | |||
3196 | * | |||
3197 | * Releases a face obtained with cairo_ft_scaled_font_lock_face(). | |||
3198 | **/ | |||
3199 | void | |||
3200 | cairo_ft_scaled_font_unlock_face_moz_cairo_ft_scaled_font_unlock_face (cairo_scaled_font_t *abstract_font) | |||
3201 | { | |||
3202 | cairo_ft_scaled_font_t *scaled_font = (cairo_ft_scaled_font_t *) abstract_font; | |||
3203 | ||||
3204 | if (! _cairo_scaled_font_is_ft (abstract_font)) { | |||
3205 | _cairo_error_throw (CAIRO_STATUS_FONT_TYPE_MISMATCH)do { cairo_status_t status__ = _cairo_error (CAIRO_STATUS_FONT_TYPE_MISMATCH ); (void) status__; } while (0); | |||
3206 | return; | |||
3207 | } | |||
3208 | ||||
3209 | if (scaled_font->base.status) | |||
3210 | return; | |||
3211 | ||||
3212 | /* Note: We released the unscaled font's mutex at the end of | |||
3213 | * cairo_ft_scaled_font_lock_face, so we have to acquire it again | |||
3214 | * as _cairo_ft_unscaled_font_unlock_face expects it to be held | |||
3215 | * when we call into it. */ | |||
3216 | CAIRO_MUTEX_LOCK (scaled_font->unscaled->mutex)pthread_mutex_lock (&(scaled_font->unscaled->mutex) ); | |||
3217 | ||||
3218 | _cairo_ft_unscaled_font_unlock_face (scaled_font->unscaled); | |||
3219 | } | |||
3220 | ||||
3221 | /* We expose our unscaled font implementation internally for the the | |||
3222 | * PDF backend, which needs to keep track of the the different | |||
3223 | * fonts-on-disk used by a document, so it can embed them. | |||
3224 | */ | |||
3225 | cairo_unscaled_font_t * | |||
3226 | _cairo_ft_scaled_font_get_unscaled_font (cairo_scaled_font_t *abstract_font) | |||
3227 | { | |||
3228 | cairo_ft_scaled_font_t *scaled_font = (cairo_ft_scaled_font_t *) abstract_font; | |||
3229 | ||||
3230 | return &scaled_font->unscaled->base; | |||
3231 | } | |||
3232 | ||||
3233 | cairo_bool_t | |||
3234 | _cairo_ft_scaled_font_is_vertical (cairo_scaled_font_t *scaled_font) | |||
3235 | { | |||
3236 | cairo_ft_scaled_font_t *ft_scaled_font; | |||
3237 | ||||
3238 | if (!_cairo_scaled_font_is_ft (scaled_font)) | |||
3239 | return FALSE0; | |||
3240 | ||||
3241 | ft_scaled_font = (cairo_ft_scaled_font_t *) scaled_font; | |||
3242 | if (ft_scaled_font->ft_options.load_flags & FT_LOAD_VERTICAL_LAYOUT( 1L << 4 )) | |||
3243 | return TRUE1; | |||
3244 | return FALSE0; | |||
3245 | } | |||
3246 | ||||
3247 | unsigned int | |||
3248 | _cairo_ft_scaled_font_get_load_flags (cairo_scaled_font_t *scaled_font) | |||
3249 | { | |||
3250 | cairo_ft_scaled_font_t *ft_scaled_font; | |||
3251 | ||||
3252 | if (! _cairo_scaled_font_is_ft (scaled_font)) | |||
3253 | return 0; | |||
3254 | ||||
3255 | ft_scaled_font = (cairo_ft_scaled_font_t *) scaled_font; | |||
3256 | return ft_scaled_font->ft_options.load_flags; | |||
3257 | } | |||
3258 | ||||
3259 | void | |||
3260 | _cairo_ft_font_reset_static_data (void) | |||
3261 | { | |||
3262 | _cairo_ft_unscaled_font_map_destroy (); | |||
3263 | } |