/work/workdir/UnpackedTarball/cairo/src/cairo-scaled-font-subsets.c
Line | Count | Source |
1 | | /* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ |
2 | | /* cairo - a vector graphics library with display and print output |
3 | | * |
4 | | * Copyright © 2003 University of Southern California |
5 | | * Copyright © 2005 Red Hat, Inc |
6 | | * Copyright © 2006 Keith Packard |
7 | | * Copyright © 2006 Red Hat, Inc |
8 | | * |
9 | | * This library is free software; you can redistribute it and/or |
10 | | * modify it either under the terms of the GNU Lesser General Public |
11 | | * License version 2.1 as published by the Free Software Foundation |
12 | | * (the "LGPL") or, at your option, under the terms of the Mozilla |
13 | | * Public License Version 1.1 (the "MPL"). If you do not alter this |
14 | | * notice, a recipient may use your version of this file under either |
15 | | * the MPL or the LGPL. |
16 | | * |
17 | | * You should have received a copy of the LGPL along with this library |
18 | | * in the file COPYING-LGPL-2.1; if not, write to the Free Software |
19 | | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA |
20 | | * You should have received a copy of the MPL along with this library |
21 | | * in the file COPYING-MPL-1.1 |
22 | | * |
23 | | * The contents of this file are subject to the Mozilla Public License |
24 | | * Version 1.1 (the "License"); you may not use this file except in |
25 | | * compliance with the License. You may obtain a copy of the License at |
26 | | * http://www.mozilla.org/MPL/ |
27 | | * |
28 | | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY |
29 | | * OF ANY KIND, either express or implied. See the LGPL or the MPL for |
30 | | * the specific language governing rights and limitations. |
31 | | * |
32 | | * The Original Code is the cairo graphics library. |
33 | | * |
34 | | * The Initial Developer of the Original Code is University of Southern |
35 | | * California. |
36 | | * |
37 | | * Contributor(s): |
38 | | * Carl D. Worth <cworth@cworth.org> |
39 | | * Kristian Høgsberg <krh@redhat.com> |
40 | | * Keith Packard <keithp@keithp.com> |
41 | | * Adrian Johnson <ajohnson@redneon.com> |
42 | | */ |
43 | | |
44 | | #define _DEFAULT_SOURCE /* for snprintf(), strdup() */ |
45 | | #include "cairoint.h" |
46 | | #include "cairo-error-private.h" |
47 | | |
48 | | #if CAIRO_HAS_FONT_SUBSET |
49 | | |
50 | | #include "cairo-scaled-font-subsets-private.h" |
51 | | #include "cairo-user-font-private.h" |
52 | | |
53 | 0 | #define MAX_GLYPHS_PER_SIMPLE_FONT 256 |
54 | 0 | #define MAX_GLYPHS_PER_COMPOSITE_FONT 65536 |
55 | | |
56 | | typedef enum { |
57 | | CAIRO_SUBSETS_SCALED, |
58 | | CAIRO_SUBSETS_SIMPLE, |
59 | | CAIRO_SUBSETS_COMPOSITE |
60 | | } cairo_subsets_type_t; |
61 | | |
62 | | typedef enum { |
63 | | CAIRO_SUBSETS_FOREACH_UNSCALED, |
64 | | CAIRO_SUBSETS_FOREACH_SCALED, |
65 | | } cairo_subsets_foreach_type_t; |
66 | | |
67 | | typedef struct _cairo_sub_font { |
68 | | cairo_hash_entry_t base; |
69 | | |
70 | | cairo_bool_t is_scaled; |
71 | | cairo_bool_t is_composite; |
72 | | cairo_bool_t use_latin_subset; |
73 | | cairo_bool_t reserve_notdef; |
74 | | cairo_scaled_font_subsets_t *parent; |
75 | | cairo_scaled_font_t *scaled_font; |
76 | | unsigned int font_id; |
77 | | |
78 | | int current_subset; |
79 | | int num_glyphs_in_current_subset; |
80 | | int num_glyphs_in_latin_subset; |
81 | | int max_glyphs_per_subset; |
82 | | char latin_char_map[256]; |
83 | | |
84 | | cairo_hash_table_t *sub_font_glyphs; |
85 | | struct _cairo_sub_font *next; |
86 | | } cairo_sub_font_t; |
87 | | |
88 | | struct _cairo_scaled_font_subsets { |
89 | | cairo_subsets_type_t type; |
90 | | cairo_bool_t use_latin_subset; |
91 | | |
92 | | int max_glyphs_per_unscaled_subset_used; |
93 | | cairo_hash_table_t *unscaled_sub_fonts; |
94 | | cairo_sub_font_t *unscaled_sub_fonts_list; |
95 | | cairo_sub_font_t *unscaled_sub_fonts_list_end; |
96 | | |
97 | | int max_glyphs_per_scaled_subset_used; |
98 | | cairo_hash_table_t *scaled_sub_fonts; |
99 | | cairo_sub_font_t *scaled_sub_fonts_list; |
100 | | cairo_sub_font_t *scaled_sub_fonts_list_end; |
101 | | |
102 | | int num_sub_fonts; |
103 | | }; |
104 | | |
105 | | typedef struct _cairo_sub_font_glyph { |
106 | | cairo_hash_entry_t base; |
107 | | |
108 | | unsigned int subset_id; |
109 | | unsigned int subset_glyph_index; |
110 | | double x_advance; |
111 | | double y_advance; |
112 | | |
113 | | cairo_bool_t is_latin; |
114 | | int latin_character; |
115 | | cairo_bool_t is_mapped; |
116 | | uint32_t unicode; |
117 | | char *utf8; |
118 | | int utf8_len; |
119 | | } cairo_sub_font_glyph_t; |
120 | | |
121 | | typedef struct _cairo_sub_font_collection { |
122 | | unsigned long *glyphs; /* scaled_font_glyph_index */ |
123 | | char **utf8; |
124 | | unsigned int glyphs_size; |
125 | | int *to_latin_char; |
126 | | unsigned long *latin_to_subset_glyph_index; |
127 | | unsigned int max_glyph; |
128 | | unsigned int num_glyphs; |
129 | | |
130 | | unsigned int subset_id; |
131 | | |
132 | | cairo_status_t status; |
133 | | cairo_scaled_font_subset_callback_func_t font_subset_callback; |
134 | | void *font_subset_callback_closure; |
135 | | } cairo_sub_font_collection_t; |
136 | | |
137 | | typedef struct _cairo_string_entry { |
138 | | cairo_hash_entry_t base; |
139 | | char *string; |
140 | | } cairo_string_entry_t; |
141 | | |
142 | | static cairo_status_t |
143 | | _cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font, |
144 | | unsigned long scaled_font_glyph_index, |
145 | | const char * utf8, |
146 | | int utf8_len, |
147 | | cairo_scaled_font_subsets_glyph_t *subset_glyph); |
148 | | |
149 | | static void |
150 | | _cairo_sub_font_glyph_init_key (cairo_sub_font_glyph_t *sub_font_glyph, |
151 | | unsigned long scaled_font_glyph_index) |
152 | 0 | { |
153 | 0 | sub_font_glyph->base.hash = scaled_font_glyph_index; |
154 | 0 | } |
155 | | |
156 | | static cairo_sub_font_glyph_t * |
157 | | _cairo_sub_font_glyph_create (unsigned long scaled_font_glyph_index, |
158 | | unsigned int subset_id, |
159 | | unsigned int subset_glyph_index, |
160 | | double x_advance, |
161 | | double y_advance, |
162 | | int latin_character, |
163 | | uint32_t unicode, |
164 | | char *utf8, |
165 | | int utf8_len) |
166 | 0 | { |
167 | 0 | cairo_sub_font_glyph_t *sub_font_glyph; |
168 | |
|
169 | 0 | sub_font_glyph = _cairo_calloc (sizeof (cairo_sub_font_glyph_t)); |
170 | 0 | if (unlikely (sub_font_glyph == NULL)) { |
171 | 0 | _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); |
172 | 0 | return NULL; |
173 | 0 | } |
174 | | |
175 | 0 | _cairo_sub_font_glyph_init_key (sub_font_glyph, scaled_font_glyph_index); |
176 | 0 | sub_font_glyph->subset_id = subset_id; |
177 | 0 | sub_font_glyph->subset_glyph_index = subset_glyph_index; |
178 | 0 | sub_font_glyph->x_advance = x_advance; |
179 | 0 | sub_font_glyph->y_advance = y_advance; |
180 | 0 | sub_font_glyph->is_latin = (latin_character >= 0); |
181 | 0 | sub_font_glyph->latin_character = latin_character; |
182 | 0 | sub_font_glyph->is_mapped = FALSE; |
183 | 0 | sub_font_glyph->unicode = unicode; |
184 | 0 | sub_font_glyph->utf8 = utf8; |
185 | 0 | sub_font_glyph->utf8_len = utf8_len; |
186 | |
|
187 | 0 | return sub_font_glyph; |
188 | 0 | } |
189 | | |
190 | | static void |
191 | | _cairo_sub_font_glyph_destroy (cairo_sub_font_glyph_t *sub_font_glyph) |
192 | 0 | { |
193 | 0 | free (sub_font_glyph->utf8); |
194 | |
|
195 | 0 | free (sub_font_glyph); |
196 | 0 | } |
197 | | |
198 | | static void |
199 | | _cairo_sub_font_glyph_pluck (void *entry, void *closure) |
200 | 0 | { |
201 | 0 | cairo_sub_font_glyph_t *sub_font_glyph = entry; |
202 | 0 | cairo_hash_table_t *sub_font_glyphs = closure; |
203 | |
|
204 | 0 | _cairo_hash_table_remove (sub_font_glyphs, &sub_font_glyph->base); |
205 | 0 | _cairo_sub_font_glyph_destroy (sub_font_glyph); |
206 | 0 | } |
207 | | |
208 | | static void |
209 | | _cairo_sub_font_glyph_collect (void *entry, void *closure) |
210 | 0 | { |
211 | 0 | cairo_sub_font_glyph_t *sub_font_glyph = entry; |
212 | 0 | cairo_sub_font_collection_t *collection = closure; |
213 | 0 | unsigned long scaled_font_glyph_index; |
214 | 0 | unsigned int subset_glyph_index; |
215 | |
|
216 | 0 | if (sub_font_glyph->subset_id != collection->subset_id) |
217 | 0 | return; |
218 | | |
219 | 0 | scaled_font_glyph_index = sub_font_glyph->base.hash; |
220 | 0 | subset_glyph_index = sub_font_glyph->subset_glyph_index; |
221 | | |
222 | | /* Ensure we don't exceed the allocated bounds. */ |
223 | 0 | assert (subset_glyph_index < collection->glyphs_size); |
224 | |
|
225 | 0 | collection->glyphs[subset_glyph_index] = scaled_font_glyph_index; |
226 | 0 | collection->utf8[subset_glyph_index] = sub_font_glyph->utf8; |
227 | 0 | collection->to_latin_char[subset_glyph_index] = sub_font_glyph->latin_character; |
228 | 0 | if (sub_font_glyph->is_latin) |
229 | 0 | collection->latin_to_subset_glyph_index[sub_font_glyph->latin_character] = subset_glyph_index; |
230 | |
|
231 | 0 | if (subset_glyph_index > collection->max_glyph) |
232 | 0 | collection->max_glyph = subset_glyph_index; |
233 | |
|
234 | 0 | collection->num_glyphs++; |
235 | 0 | } |
236 | | |
237 | | static cairo_bool_t |
238 | | _cairo_sub_fonts_equal (const void *key_a, const void *key_b) |
239 | 0 | { |
240 | 0 | const cairo_sub_font_t *sub_font_a = key_a; |
241 | 0 | const cairo_sub_font_t *sub_font_b = key_b; |
242 | 0 | cairo_scaled_font_t *a = sub_font_a->scaled_font; |
243 | 0 | cairo_scaled_font_t *b = sub_font_b->scaled_font; |
244 | |
|
245 | 0 | if (sub_font_a->is_scaled) |
246 | 0 | return a == b; |
247 | 0 | else |
248 | 0 | return a->font_face == b->font_face || a->original_font_face == b->original_font_face; |
249 | 0 | } |
250 | | |
251 | | static void |
252 | | _cairo_sub_font_init_key (cairo_sub_font_t *sub_font, |
253 | | cairo_scaled_font_t *scaled_font) |
254 | 0 | { |
255 | 0 | if (sub_font->is_scaled) |
256 | 0 | { |
257 | 0 | sub_font->base.hash = (uintptr_t) scaled_font; |
258 | 0 | sub_font->scaled_font = scaled_font; |
259 | 0 | } |
260 | 0 | else |
261 | 0 | { |
262 | 0 | sub_font->base.hash = (uintptr_t) scaled_font->font_face; |
263 | 0 | sub_font->scaled_font = scaled_font; |
264 | 0 | } |
265 | 0 | } |
266 | | |
267 | | static cairo_status_t |
268 | | _cairo_sub_font_create (cairo_scaled_font_subsets_t *parent, |
269 | | cairo_scaled_font_t *scaled_font, |
270 | | unsigned int font_id, |
271 | | int max_glyphs_per_subset, |
272 | | cairo_bool_t is_scaled, |
273 | | cairo_bool_t is_composite, |
274 | | cairo_sub_font_t **sub_font_out) |
275 | 0 | { |
276 | 0 | cairo_sub_font_t *sub_font; |
277 | 0 | int i; |
278 | |
|
279 | 0 | sub_font = _cairo_calloc (sizeof (cairo_sub_font_t)); |
280 | 0 | if (unlikely (sub_font == NULL)) |
281 | 0 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
282 | | |
283 | 0 | sub_font->is_scaled = is_scaled; |
284 | 0 | sub_font->is_composite = is_composite; |
285 | 0 | sub_font->reserve_notdef = !sub_font->is_scaled; |
286 | 0 | _cairo_sub_font_init_key (sub_font, scaled_font); |
287 | |
|
288 | 0 | sub_font->parent = parent; |
289 | 0 | sub_font->scaled_font = scaled_font; |
290 | 0 | sub_font->font_id = font_id; |
291 | |
|
292 | 0 | sub_font->use_latin_subset = parent->use_latin_subset; |
293 | | |
294 | | /* latin subsets of Type 3 and CID CFF fonts are not supported */ |
295 | 0 | if (sub_font->is_scaled || |
296 | 0 | _cairo_cff_scaled_font_is_cid_cff (scaled_font) ) |
297 | 0 | { |
298 | 0 | sub_font->use_latin_subset = FALSE; |
299 | 0 | } |
300 | |
|
301 | 0 | if (sub_font->use_latin_subset) |
302 | 0 | sub_font->current_subset = 1; /* reserve subset 0 for latin glyphs */ |
303 | 0 | else |
304 | 0 | sub_font->current_subset = 0; |
305 | |
|
306 | 0 | sub_font->num_glyphs_in_current_subset = 0; |
307 | 0 | sub_font->num_glyphs_in_latin_subset = 0; |
308 | 0 | sub_font->max_glyphs_per_subset = max_glyphs_per_subset; |
309 | 0 | for (i = 0; i < 256; i++) |
310 | 0 | sub_font->latin_char_map[i] = FALSE; |
311 | |
|
312 | 0 | sub_font->sub_font_glyphs = _cairo_hash_table_create (NULL); |
313 | 0 | if (unlikely (sub_font->sub_font_glyphs == NULL)) { |
314 | 0 | free (sub_font); |
315 | 0 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
316 | 0 | } |
317 | 0 | sub_font->next = NULL; |
318 | 0 | *sub_font_out = sub_font; |
319 | 0 | return CAIRO_STATUS_SUCCESS; |
320 | 0 | } |
321 | | |
322 | | static void |
323 | | _cairo_sub_font_destroy (cairo_sub_font_t *sub_font) |
324 | 0 | { |
325 | 0 | _cairo_hash_table_foreach (sub_font->sub_font_glyphs, |
326 | 0 | _cairo_sub_font_glyph_pluck, |
327 | 0 | sub_font->sub_font_glyphs); |
328 | 0 | _cairo_hash_table_destroy (sub_font->sub_font_glyphs); |
329 | 0 | cairo_scaled_font_destroy (sub_font->scaled_font); |
330 | 0 | free (sub_font); |
331 | 0 | } |
332 | | |
333 | | static void |
334 | | _cairo_sub_font_pluck (void *entry, void *closure) |
335 | 0 | { |
336 | 0 | cairo_sub_font_t *sub_font = entry; |
337 | 0 | cairo_hash_table_t *sub_fonts = closure; |
338 | |
|
339 | 0 | _cairo_hash_table_remove (sub_fonts, &sub_font->base); |
340 | 0 | _cairo_sub_font_destroy (sub_font); |
341 | 0 | } |
342 | | |
343 | | /* Characters 0x80 to 0x9f in the winansi encoding. |
344 | | * All other characters in the range 0x00 to 0xff map 1:1 to unicode */ |
345 | | static unsigned int _winansi_0x80_to_0x9f[] = { |
346 | | 0x20ac, 0x0000, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021, |
347 | | 0x02c6, 0x2030, 0x0160, 0x2039, 0x0152, 0x0000, 0x017d, 0x0000, |
348 | | 0x0000, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014, |
349 | | 0x02dc, 0x2122, 0x0161, 0x203a, 0x0153, 0x0000, 0x017e, 0x0178 |
350 | | }; |
351 | | |
352 | | int |
353 | | _cairo_unicode_to_winansi (unsigned long uni) |
354 | 0 | { |
355 | 0 | int i; |
356 | | |
357 | | /* exclude the extra "hyphen" at 0xad to avoid duplicate glyphnames */ |
358 | 0 | if ((uni >= 0x20 && uni <= 0x7e) || |
359 | 0 | (uni >= 0xa1 && uni <= 0xff && uni != 0xad) || |
360 | 0 | uni == 0) |
361 | 0 | return uni; |
362 | | |
363 | 0 | for (i = 0; i < 32; i++) |
364 | 0 | if (_winansi_0x80_to_0x9f[i] == uni) |
365 | 0 | return i + 0x80; |
366 | | |
367 | 0 | return -1; |
368 | 0 | } |
369 | | |
370 | | static cairo_status_t |
371 | | _cairo_sub_font_glyph_lookup_unicode (cairo_scaled_font_t *scaled_font, |
372 | | unsigned long scaled_font_glyph_index, |
373 | | uint32_t *unicode_out, |
374 | | char **utf8_out, |
375 | | int *utf8_len_out) |
376 | 0 | { |
377 | 0 | uint32_t unicode; |
378 | 0 | char buf[8]; |
379 | 0 | int len; |
380 | 0 | cairo_status_t status; |
381 | | |
382 | | /* Do a reverse lookup on the glyph index. unicode is -1 if the |
383 | | * index could not be mapped to a unicode character. */ |
384 | 0 | unicode = -1; |
385 | 0 | status = _cairo_truetype_index_to_ucs4 (scaled_font, |
386 | 0 | scaled_font_glyph_index, |
387 | 0 | &unicode); |
388 | 0 | if (_cairo_status_is_error (status)) |
389 | 0 | return status; |
390 | | |
391 | 0 | if (unicode == (uint32_t)-1 && scaled_font->backend->index_to_ucs4) { |
392 | 0 | status = scaled_font->backend->index_to_ucs4 (scaled_font, |
393 | 0 | scaled_font_glyph_index, |
394 | 0 | &unicode); |
395 | 0 | if (unlikely (status)) |
396 | 0 | return status; |
397 | 0 | } |
398 | | |
399 | 0 | *unicode_out = unicode; |
400 | 0 | *utf8_out = NULL; |
401 | 0 | *utf8_len_out = 0; |
402 | 0 | if (unicode != (uint32_t) -1) { |
403 | 0 | len = _cairo_ucs4_to_utf8 (unicode, buf); |
404 | 0 | if (len > 0) { |
405 | 0 | *utf8_out = _cairo_strndup (buf, len); |
406 | 0 | if (unlikely (*utf8_out == NULL)) |
407 | 0 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
408 | | |
409 | 0 | *utf8_len_out = len; |
410 | 0 | } |
411 | 0 | } |
412 | | |
413 | 0 | return CAIRO_STATUS_SUCCESS; |
414 | 0 | } |
415 | | |
416 | | static cairo_status_t |
417 | | _cairo_sub_font_glyph_map_to_unicode (cairo_sub_font_glyph_t *sub_font_glyph, |
418 | | const char *utf8, |
419 | | int utf8_len, |
420 | | cairo_bool_t *is_mapped) |
421 | 0 | { |
422 | 0 | *is_mapped = FALSE; |
423 | |
|
424 | 0 | if (utf8_len < 0) |
425 | 0 | return CAIRO_STATUS_SUCCESS; |
426 | | |
427 | 0 | if (utf8 != NULL && utf8_len != 0 && utf8[utf8_len - 1] == '\0') |
428 | 0 | utf8_len--; |
429 | |
|
430 | 0 | if (utf8 != NULL && utf8_len != 0) { |
431 | 0 | if (sub_font_glyph->utf8 != NULL) { |
432 | 0 | if (utf8_len == sub_font_glyph->utf8_len && |
433 | 0 | strncmp (utf8, sub_font_glyph->utf8, utf8_len) == 0) |
434 | 0 | { |
435 | | /* Requested utf8 mapping matches the existing mapping */ |
436 | 0 | *is_mapped = TRUE; |
437 | 0 | } |
438 | 0 | } else { |
439 | | /* No existing mapping. Use the requested mapping */ |
440 | 0 | sub_font_glyph->utf8 = _cairo_strndup (utf8, utf8_len); |
441 | 0 | if (unlikely (sub_font_glyph->utf8 == NULL)) |
442 | 0 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
443 | | |
444 | 0 | sub_font_glyph->utf8_len = utf8_len; |
445 | 0 | *is_mapped = TRUE; |
446 | 0 | } |
447 | 0 | } |
448 | | |
449 | 0 | return CAIRO_STATUS_SUCCESS; |
450 | 0 | } |
451 | | |
452 | | static cairo_int_status_t |
453 | | _cairo_sub_font_lookup_glyph (cairo_sub_font_t *sub_font, |
454 | | unsigned long scaled_font_glyph_index, |
455 | | const char *utf8, |
456 | | int utf8_len, |
457 | | cairo_scaled_font_subsets_glyph_t *subset_glyph) |
458 | 0 | { |
459 | 0 | cairo_sub_font_glyph_t key, *sub_font_glyph; |
460 | 0 | cairo_int_status_t status; |
461 | |
|
462 | 0 | _cairo_sub_font_glyph_init_key (&key, scaled_font_glyph_index); |
463 | 0 | sub_font_glyph = _cairo_hash_table_lookup (sub_font->sub_font_glyphs, |
464 | 0 | &key.base); |
465 | 0 | if (sub_font_glyph != NULL) { |
466 | 0 | subset_glyph->font_id = sub_font->font_id; |
467 | 0 | subset_glyph->subset_id = sub_font_glyph->subset_id; |
468 | 0 | if (sub_font_glyph->is_latin) |
469 | 0 | subset_glyph->subset_glyph_index = sub_font_glyph->latin_character; |
470 | 0 | else |
471 | 0 | subset_glyph->subset_glyph_index = sub_font_glyph->subset_glyph_index; |
472 | |
|
473 | 0 | subset_glyph->is_scaled = sub_font->is_scaled; |
474 | 0 | subset_glyph->is_composite = sub_font->is_composite; |
475 | 0 | subset_glyph->is_latin = sub_font_glyph->is_latin; |
476 | 0 | subset_glyph->x_advance = sub_font_glyph->x_advance; |
477 | 0 | subset_glyph->y_advance = sub_font_glyph->y_advance; |
478 | 0 | status = _cairo_sub_font_glyph_map_to_unicode (sub_font_glyph, |
479 | 0 | utf8, utf8_len, |
480 | 0 | &subset_glyph->utf8_is_mapped); |
481 | 0 | subset_glyph->unicode = sub_font_glyph->unicode; |
482 | |
|
483 | 0 | return status; |
484 | 0 | } |
485 | | |
486 | 0 | return CAIRO_INT_STATUS_UNSUPPORTED; |
487 | 0 | } |
488 | | |
489 | | static cairo_status_t |
490 | | _cairo_sub_font_add_glyph (cairo_sub_font_t *sub_font, |
491 | | unsigned long scaled_font_glyph_index, |
492 | | cairo_bool_t is_latin, |
493 | | int latin_character, |
494 | | uint32_t unicode, |
495 | | char *utf8, |
496 | | int utf8_len, |
497 | | cairo_sub_font_glyph_t **sub_font_glyph_out) |
498 | 0 | { |
499 | 0 | cairo_scaled_glyph_t *scaled_glyph; |
500 | 0 | cairo_sub_font_glyph_t *sub_font_glyph; |
501 | 0 | int *num_glyphs_in_subset_ptr; |
502 | 0 | double x_advance; |
503 | 0 | double y_advance; |
504 | 0 | cairo_int_status_t status; |
505 | |
|
506 | 0 | _cairo_scaled_font_freeze_cache (sub_font->scaled_font); |
507 | 0 | status = _cairo_scaled_glyph_lookup (sub_font->scaled_font, |
508 | 0 | scaled_font_glyph_index, |
509 | 0 | CAIRO_SCALED_GLYPH_INFO_METRICS, |
510 | 0 | NULL, /* foreground color */ |
511 | 0 | &scaled_glyph); |
512 | 0 | assert (status != CAIRO_INT_STATUS_UNSUPPORTED); |
513 | 0 | if (unlikely (status)) { |
514 | 0 | _cairo_scaled_font_thaw_cache (sub_font->scaled_font); |
515 | 0 | return status; |
516 | 0 | } |
517 | | |
518 | 0 | x_advance = scaled_glyph->metrics.x_advance; |
519 | 0 | y_advance = scaled_glyph->metrics.y_advance; |
520 | 0 | _cairo_scaled_font_thaw_cache (sub_font->scaled_font); |
521 | |
|
522 | 0 | if (!is_latin && sub_font->num_glyphs_in_current_subset == sub_font->max_glyphs_per_subset) |
523 | 0 | { |
524 | 0 | sub_font->current_subset++; |
525 | 0 | sub_font->num_glyphs_in_current_subset = 0; |
526 | 0 | } |
527 | |
|
528 | 0 | if (is_latin) |
529 | 0 | num_glyphs_in_subset_ptr = &sub_font->num_glyphs_in_latin_subset; |
530 | 0 | else |
531 | 0 | num_glyphs_in_subset_ptr = &sub_font->num_glyphs_in_current_subset; |
532 | |
|
533 | 0 | if ((*num_glyphs_in_subset_ptr == 0) && sub_font->reserve_notdef) |
534 | 0 | (*num_glyphs_in_subset_ptr)++; |
535 | |
|
536 | 0 | sub_font_glyph = _cairo_sub_font_glyph_create (scaled_font_glyph_index, |
537 | 0 | is_latin ? 0 : sub_font->current_subset, |
538 | 0 | *num_glyphs_in_subset_ptr, |
539 | 0 | x_advance, |
540 | 0 | y_advance, |
541 | 0 | is_latin ? latin_character : -1, |
542 | 0 | unicode, |
543 | 0 | utf8, |
544 | 0 | utf8_len); |
545 | |
|
546 | 0 | if (unlikely (sub_font_glyph == NULL)) |
547 | 0 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
548 | | |
549 | 0 | status = _cairo_hash_table_insert (sub_font->sub_font_glyphs, &sub_font_glyph->base); |
550 | 0 | if (unlikely (status)) { |
551 | 0 | _cairo_sub_font_glyph_destroy (sub_font_glyph); |
552 | 0 | return status; |
553 | 0 | } |
554 | | |
555 | 0 | (*num_glyphs_in_subset_ptr)++; |
556 | 0 | if (sub_font->is_scaled) { |
557 | 0 | if (*num_glyphs_in_subset_ptr > sub_font->parent->max_glyphs_per_scaled_subset_used) |
558 | 0 | sub_font->parent->max_glyphs_per_scaled_subset_used = *num_glyphs_in_subset_ptr; |
559 | 0 | } else { |
560 | 0 | if (*num_glyphs_in_subset_ptr > sub_font->parent->max_glyphs_per_unscaled_subset_used) |
561 | 0 | sub_font->parent->max_glyphs_per_unscaled_subset_used = *num_glyphs_in_subset_ptr; |
562 | 0 | } |
563 | |
|
564 | 0 | *sub_font_glyph_out = sub_font_glyph; |
565 | |
|
566 | 0 | return CAIRO_STATUS_SUCCESS; |
567 | 0 | } |
568 | | |
569 | | static cairo_status_t |
570 | | _cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font, |
571 | | unsigned long scaled_font_glyph_index, |
572 | | const char *text_utf8, |
573 | | int text_utf8_len, |
574 | | cairo_scaled_font_subsets_glyph_t *subset_glyph) |
575 | 0 | { |
576 | 0 | cairo_sub_font_glyph_t key, *sub_font_glyph; |
577 | 0 | cairo_status_t status; |
578 | |
|
579 | 0 | _cairo_sub_font_glyph_init_key (&key, scaled_font_glyph_index); |
580 | 0 | sub_font_glyph = _cairo_hash_table_lookup (sub_font->sub_font_glyphs, |
581 | 0 | &key.base); |
582 | 0 | if (sub_font_glyph == NULL) { |
583 | 0 | uint32_t font_unicode; |
584 | 0 | char *font_utf8; |
585 | 0 | int font_utf8_len; |
586 | 0 | cairo_bool_t is_latin; |
587 | 0 | int latin_character; |
588 | |
|
589 | 0 | status = _cairo_sub_font_glyph_lookup_unicode (sub_font->scaled_font, |
590 | 0 | scaled_font_glyph_index, |
591 | 0 | &font_unicode, |
592 | 0 | &font_utf8, |
593 | 0 | &font_utf8_len); |
594 | 0 | if (unlikely(status)) |
595 | 0 | return status; |
596 | | |
597 | | /* If the supplied utf8 is a valid single character, use it |
598 | | * instead of the font lookup */ |
599 | 0 | if (text_utf8 != NULL && text_utf8_len > 0) { |
600 | 0 | uint32_t *ucs4; |
601 | 0 | int ucs4_len; |
602 | |
|
603 | 0 | status = _cairo_utf8_to_ucs4 (text_utf8, text_utf8_len, |
604 | 0 | &ucs4, &ucs4_len); |
605 | 0 | if (status == CAIRO_STATUS_SUCCESS) { |
606 | 0 | if (ucs4_len == 1) { |
607 | 0 | font_unicode = ucs4[0]; |
608 | 0 | free (font_utf8); |
609 | 0 | font_utf8 = _cairo_strndup (text_utf8, text_utf8_len); |
610 | 0 | if (font_utf8 == NULL) { |
611 | 0 | free (ucs4); |
612 | 0 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
613 | 0 | } |
614 | 0 | font_utf8_len = text_utf8_len; |
615 | 0 | } |
616 | 0 | free (ucs4); |
617 | 0 | } |
618 | 0 | } |
619 | | |
620 | | /* If glyph is in the winansi encoding and font is not a scaled |
621 | | * font, put glyph in the latin subset. */ |
622 | 0 | is_latin = FALSE; |
623 | 0 | latin_character = -1; |
624 | 0 | if (sub_font->use_latin_subset && !sub_font->is_scaled) |
625 | 0 | { |
626 | 0 | latin_character = _cairo_unicode_to_winansi (font_unicode); |
627 | 0 | if (latin_character > 0) |
628 | 0 | { |
629 | 0 | if (!sub_font->latin_char_map[latin_character]) { |
630 | 0 | sub_font->latin_char_map[latin_character] = TRUE; |
631 | 0 | is_latin = TRUE; |
632 | 0 | } |
633 | 0 | } |
634 | 0 | } |
635 | |
|
636 | 0 | status = _cairo_sub_font_add_glyph (sub_font, |
637 | 0 | scaled_font_glyph_index, |
638 | 0 | is_latin, |
639 | 0 | latin_character, |
640 | 0 | font_unicode, |
641 | 0 | font_utf8, |
642 | 0 | font_utf8_len, |
643 | 0 | &sub_font_glyph); |
644 | 0 | if (unlikely(status)) |
645 | 0 | return status; |
646 | 0 | } |
647 | | |
648 | 0 | subset_glyph->font_id = sub_font->font_id; |
649 | 0 | subset_glyph->subset_id = sub_font_glyph->subset_id; |
650 | 0 | if (sub_font_glyph->is_latin) |
651 | 0 | subset_glyph->subset_glyph_index = sub_font_glyph->latin_character; |
652 | 0 | else |
653 | 0 | subset_glyph->subset_glyph_index = sub_font_glyph->subset_glyph_index; |
654 | |
|
655 | 0 | subset_glyph->is_scaled = sub_font->is_scaled; |
656 | 0 | subset_glyph->is_composite = sub_font->is_composite; |
657 | 0 | subset_glyph->is_latin = sub_font_glyph->is_latin; |
658 | 0 | subset_glyph->x_advance = sub_font_glyph->x_advance; |
659 | 0 | subset_glyph->y_advance = sub_font_glyph->y_advance; |
660 | 0 | status = _cairo_sub_font_glyph_map_to_unicode (sub_font_glyph, |
661 | 0 | text_utf8, text_utf8_len, |
662 | 0 | &subset_glyph->utf8_is_mapped); |
663 | 0 | subset_glyph->unicode = sub_font_glyph->unicode; |
664 | |
|
665 | 0 | return status; |
666 | 0 | } |
667 | | |
668 | | static void |
669 | | _cairo_sub_font_collect (void *entry, void *closure) |
670 | 0 | { |
671 | 0 | cairo_sub_font_t *sub_font = entry; |
672 | 0 | cairo_sub_font_collection_t *collection = closure; |
673 | 0 | cairo_scaled_font_subset_t subset; |
674 | 0 | int i; |
675 | 0 | unsigned int j; |
676 | |
|
677 | 0 | if (collection->status) |
678 | 0 | return; |
679 | | |
680 | 0 | collection->status = sub_font->scaled_font->status; |
681 | 0 | if (collection->status) |
682 | 0 | return; |
683 | | |
684 | 0 | for (i = 0; i <= sub_font->current_subset; i++) { |
685 | 0 | collection->subset_id = i; |
686 | 0 | collection->num_glyphs = 0; |
687 | 0 | collection->max_glyph = 0; |
688 | 0 | memset (collection->latin_to_subset_glyph_index, 0, 256*sizeof(unsigned long)); |
689 | |
|
690 | 0 | if (sub_font->reserve_notdef) { |
691 | | // add .notdef |
692 | 0 | collection->glyphs[0] = 0; |
693 | 0 | collection->utf8[0] = 0; |
694 | 0 | collection->to_latin_char[0] = 0; |
695 | 0 | collection->latin_to_subset_glyph_index[0] = 0; |
696 | 0 | collection->num_glyphs++; |
697 | 0 | } |
698 | |
|
699 | 0 | _cairo_hash_table_foreach (sub_font->sub_font_glyphs, |
700 | 0 | _cairo_sub_font_glyph_collect, collection); |
701 | 0 | if (collection->status) |
702 | 0 | break; |
703 | | |
704 | 0 | if (collection->num_glyphs == 0) |
705 | 0 | continue; |
706 | | |
707 | 0 | if (sub_font->reserve_notdef && collection->num_glyphs == 1) |
708 | 0 | continue; |
709 | | |
710 | | /* Ensure the resulting array has no uninitialized holes */ |
711 | 0 | assert (collection->num_glyphs == collection->max_glyph + 1); |
712 | |
|
713 | 0 | subset.scaled_font = sub_font->scaled_font; |
714 | 0 | subset.is_composite = sub_font->is_composite; |
715 | 0 | subset.is_scaled = sub_font->is_scaled; |
716 | 0 | subset.font_id = sub_font->font_id; |
717 | 0 | subset.subset_id = i; |
718 | 0 | subset.glyphs = collection->glyphs; |
719 | 0 | subset.utf8 = collection->utf8; |
720 | 0 | subset.num_glyphs = collection->num_glyphs; |
721 | 0 | subset.glyph_names = NULL; |
722 | |
|
723 | 0 | subset.is_latin = FALSE; |
724 | 0 | if (sub_font->use_latin_subset && i == 0) { |
725 | 0 | subset.is_latin = TRUE; |
726 | 0 | subset.to_latin_char = collection->to_latin_char; |
727 | 0 | subset.latin_to_subset_glyph_index = collection->latin_to_subset_glyph_index; |
728 | 0 | } else { |
729 | 0 | subset.to_latin_char = NULL; |
730 | 0 | subset.latin_to_subset_glyph_index = NULL; |
731 | 0 | } |
732 | |
|
733 | 0 | collection->status = (collection->font_subset_callback) (&subset, |
734 | 0 | collection->font_subset_callback_closure); |
735 | |
|
736 | 0 | if (subset.glyph_names != NULL) { |
737 | 0 | for (j = 0; j < collection->num_glyphs; j++) |
738 | 0 | free (subset.glyph_names[j]); |
739 | 0 | free (subset.glyph_names); |
740 | 0 | } |
741 | |
|
742 | 0 | if (collection->status) |
743 | 0 | break; |
744 | 0 | } |
745 | 0 | } |
746 | | |
747 | | static cairo_scaled_font_subsets_t * |
748 | | _cairo_scaled_font_subsets_create_internal (cairo_subsets_type_t type) |
749 | 2 | { |
750 | 2 | cairo_scaled_font_subsets_t *subsets; |
751 | | |
752 | 2 | subsets = _cairo_calloc (sizeof (cairo_scaled_font_subsets_t)); |
753 | 2 | if (unlikely (subsets == NULL)) { |
754 | 0 | _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); |
755 | 0 | return NULL; |
756 | 0 | } |
757 | | |
758 | 2 | subsets->type = type; |
759 | 2 | subsets->use_latin_subset = FALSE; |
760 | 2 | subsets->max_glyphs_per_unscaled_subset_used = 0; |
761 | 2 | subsets->max_glyphs_per_scaled_subset_used = 0; |
762 | 2 | subsets->num_sub_fonts = 0; |
763 | | |
764 | 2 | subsets->unscaled_sub_fonts = _cairo_hash_table_create (_cairo_sub_fonts_equal); |
765 | 2 | if (! subsets->unscaled_sub_fonts) { |
766 | 0 | free (subsets); |
767 | 0 | return NULL; |
768 | 0 | } |
769 | 2 | subsets->unscaled_sub_fonts_list = NULL; |
770 | 2 | subsets->unscaled_sub_fonts_list_end = NULL; |
771 | | |
772 | 2 | subsets->scaled_sub_fonts = _cairo_hash_table_create (_cairo_sub_fonts_equal); |
773 | 2 | if (! subsets->scaled_sub_fonts) { |
774 | 0 | _cairo_hash_table_destroy (subsets->unscaled_sub_fonts); |
775 | 0 | free (subsets); |
776 | 0 | return NULL; |
777 | 0 | } |
778 | 2 | subsets->scaled_sub_fonts_list = NULL; |
779 | 2 | subsets->scaled_sub_fonts_list_end = NULL; |
780 | | |
781 | 2 | return subsets; |
782 | 2 | } |
783 | | |
784 | | cairo_scaled_font_subsets_t * |
785 | | _cairo_scaled_font_subsets_create_scaled (void) |
786 | 2 | { |
787 | 2 | return _cairo_scaled_font_subsets_create_internal (CAIRO_SUBSETS_SCALED); |
788 | 2 | } |
789 | | |
790 | | cairo_scaled_font_subsets_t * |
791 | | _cairo_scaled_font_subsets_create_simple (void) |
792 | 0 | { |
793 | 0 | return _cairo_scaled_font_subsets_create_internal (CAIRO_SUBSETS_SIMPLE); |
794 | 0 | } |
795 | | |
796 | | cairo_scaled_font_subsets_t * |
797 | | _cairo_scaled_font_subsets_create_composite (void) |
798 | 0 | { |
799 | 0 | return _cairo_scaled_font_subsets_create_internal (CAIRO_SUBSETS_COMPOSITE); |
800 | 0 | } |
801 | | |
802 | | void |
803 | | _cairo_scaled_font_subsets_destroy (cairo_scaled_font_subsets_t *subsets) |
804 | 2 | { |
805 | 2 | _cairo_hash_table_foreach (subsets->scaled_sub_fonts, _cairo_sub_font_pluck, subsets->scaled_sub_fonts); |
806 | 2 | _cairo_hash_table_destroy (subsets->scaled_sub_fonts); |
807 | | |
808 | 2 | _cairo_hash_table_foreach (subsets->unscaled_sub_fonts, _cairo_sub_font_pluck, subsets->unscaled_sub_fonts); |
809 | 2 | _cairo_hash_table_destroy (subsets->unscaled_sub_fonts); |
810 | | |
811 | 2 | free (subsets); |
812 | 2 | } |
813 | | |
814 | | void |
815 | | _cairo_scaled_font_subsets_enable_latin_subset (cairo_scaled_font_subsets_t *font_subsets, |
816 | | cairo_bool_t use_latin) |
817 | 0 | { |
818 | 0 | font_subsets->use_latin_subset = use_latin; |
819 | 0 | } |
820 | | |
821 | | cairo_status_t |
822 | | _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets, |
823 | | cairo_scaled_font_t *scaled_font, |
824 | | unsigned long scaled_font_glyph_index, |
825 | | const char * utf8, |
826 | | int utf8_len, |
827 | | cairo_scaled_font_subsets_glyph_t *subset_glyph) |
828 | 0 | { |
829 | 0 | cairo_sub_font_t key, *sub_font; |
830 | 0 | cairo_scaled_glyph_t *scaled_glyph; |
831 | 0 | cairo_font_face_t *font_face; |
832 | 0 | cairo_matrix_t identity; |
833 | 0 | cairo_font_options_t font_options; |
834 | 0 | cairo_scaled_font_t *unscaled_font; |
835 | 0 | cairo_int_status_t status; |
836 | 0 | int max_glyphs; |
837 | 0 | cairo_bool_t type1_font; |
838 | 0 | cairo_bool_t has_path; |
839 | 0 | cairo_bool_t has_color; |
840 | 0 | cairo_bool_t is_user; |
841 | | |
842 | | /* Lookup glyph in unscaled subsets */ |
843 | 0 | if (subsets->type != CAIRO_SUBSETS_SCALED) { |
844 | 0 | key.is_scaled = FALSE; |
845 | 0 | _cairo_sub_font_init_key (&key, scaled_font); |
846 | 0 | sub_font = _cairo_hash_table_lookup (subsets->unscaled_sub_fonts, |
847 | 0 | &key.base); |
848 | 0 | if (sub_font != NULL) { |
849 | 0 | status = _cairo_sub_font_lookup_glyph (sub_font, |
850 | 0 | scaled_font_glyph_index, |
851 | 0 | utf8, utf8_len, |
852 | 0 | subset_glyph); |
853 | 0 | if (status != CAIRO_INT_STATUS_UNSUPPORTED) |
854 | 0 | return status; |
855 | 0 | } |
856 | 0 | } |
857 | | |
858 | | /* Lookup glyph in scaled subsets */ |
859 | 0 | key.is_scaled = TRUE; |
860 | 0 | _cairo_sub_font_init_key (&key, scaled_font); |
861 | 0 | sub_font = _cairo_hash_table_lookup (subsets->scaled_sub_fonts, |
862 | 0 | &key.base); |
863 | 0 | if (sub_font != NULL) { |
864 | 0 | status = _cairo_sub_font_lookup_glyph (sub_font, |
865 | 0 | scaled_font_glyph_index, |
866 | 0 | utf8, utf8_len, |
867 | 0 | subset_glyph); |
868 | 0 | if (status != CAIRO_INT_STATUS_UNSUPPORTED) |
869 | 0 | return status; |
870 | 0 | } |
871 | | |
872 | | /* Glyph not found. Determine whether the glyph is outline or |
873 | | * bitmap and add to the appropriate subset. |
874 | | */ |
875 | 0 | is_user = _cairo_font_face_is_user (scaled_font->font_face); |
876 | 0 | _cairo_scaled_font_freeze_cache (scaled_font); |
877 | | /* Check if glyph is color */ |
878 | 0 | status = _cairo_scaled_glyph_lookup (scaled_font, |
879 | 0 | scaled_font_glyph_index, |
880 | 0 | CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE, |
881 | 0 | NULL, /* foreground color */ |
882 | 0 | &scaled_glyph); |
883 | 0 | has_color = (status == CAIRO_INT_STATUS_SUCCESS); |
884 | | |
885 | | /* Check if glyph has a path */ |
886 | 0 | status = _cairo_scaled_glyph_lookup (scaled_font, |
887 | 0 | scaled_font_glyph_index, |
888 | 0 | CAIRO_SCALED_GLYPH_INFO_PATH, |
889 | 0 | NULL, /* foreground color */ |
890 | 0 | &scaled_glyph); |
891 | 0 | has_path = (status == CAIRO_INT_STATUS_SUCCESS); |
892 | | |
893 | | /* glyph_index 0 (the .notdef glyph) is a special case. Some fonts |
894 | | * will return CAIRO_INT_STATUS_UNSUPPORTED when doing a |
895 | | * _scaled_glyph_lookup(_GLYPH_INFO_PATH). Type1-fallback creates |
896 | | * empty glyphs in this case so we can put the glyph in a unscaled |
897 | | * subset. |
898 | | */ |
899 | 0 | if (scaled_font_glyph_index == 0 && !is_user) |
900 | 0 | has_path = TRUE; |
901 | | |
902 | | /* If this fails there is nothing we can do with this glyph. */ |
903 | 0 | status = _cairo_scaled_glyph_lookup (scaled_font, |
904 | 0 | scaled_font_glyph_index, |
905 | 0 | CAIRO_SCALED_GLYPH_INFO_SURFACE, |
906 | 0 | NULL, /* foreground color */ |
907 | 0 | &scaled_glyph); |
908 | 0 | _cairo_scaled_font_thaw_cache (scaled_font); |
909 | 0 | if (_cairo_int_status_is_error (status)) |
910 | 0 | return status; |
911 | | |
912 | | /* Type 3 glyphs (is_user and has_color) must be added to scaled subset */ |
913 | 0 | if (subsets->type != CAIRO_SUBSETS_SCALED && |
914 | 0 | has_path && !has_color && !is_user) |
915 | 0 | { |
916 | | /* Path available. Add to unscaled subset. */ |
917 | 0 | key.is_scaled = FALSE; |
918 | 0 | _cairo_sub_font_init_key (&key, scaled_font); |
919 | 0 | sub_font = _cairo_hash_table_lookup (subsets->unscaled_sub_fonts, |
920 | 0 | &key.base); |
921 | 0 | if (sub_font == NULL) { |
922 | 0 | font_face = cairo_scaled_font_get_font_face (scaled_font); |
923 | 0 | cairo_matrix_init_identity (&identity); |
924 | 0 | _cairo_font_options_init_default (&font_options); |
925 | 0 | cairo_scaled_font_get_font_options (scaled_font, &font_options); |
926 | 0 | cairo_font_options_set_hint_style (&font_options, CAIRO_HINT_STYLE_NONE); |
927 | 0 | cairo_font_options_set_hint_metrics (&font_options, CAIRO_HINT_METRICS_OFF); |
928 | 0 | unscaled_font = cairo_scaled_font_create (font_face, |
929 | 0 | &identity, |
930 | 0 | &identity, |
931 | 0 | &font_options); |
932 | 0 | if (unlikely (unscaled_font->status)) |
933 | 0 | return unscaled_font->status; |
934 | | |
935 | 0 | subset_glyph->is_scaled = FALSE; |
936 | 0 | type1_font = _cairo_type1_scaled_font_is_type1 (unscaled_font); |
937 | 0 | if (subsets->type == CAIRO_SUBSETS_COMPOSITE && !type1_font) { |
938 | 0 | max_glyphs = MAX_GLYPHS_PER_COMPOSITE_FONT; |
939 | 0 | subset_glyph->is_composite = TRUE; |
940 | 0 | } else { |
941 | 0 | max_glyphs = MAX_GLYPHS_PER_SIMPLE_FONT; |
942 | 0 | subset_glyph->is_composite = FALSE; |
943 | 0 | } |
944 | |
|
945 | 0 | status = _cairo_sub_font_create (subsets, |
946 | 0 | unscaled_font, |
947 | 0 | subsets->num_sub_fonts, |
948 | 0 | max_glyphs, |
949 | 0 | subset_glyph->is_scaled, |
950 | 0 | subset_glyph->is_composite, |
951 | 0 | &sub_font); |
952 | |
|
953 | 0 | if (unlikely (status)) { |
954 | 0 | cairo_scaled_font_destroy (unscaled_font); |
955 | 0 | return status; |
956 | 0 | } |
957 | | |
958 | 0 | status = _cairo_hash_table_insert (subsets->unscaled_sub_fonts, |
959 | 0 | &sub_font->base); |
960 | |
|
961 | 0 | if (unlikely (status)) { |
962 | 0 | _cairo_sub_font_destroy (sub_font); |
963 | 0 | return status; |
964 | 0 | } |
965 | 0 | if (!subsets->unscaled_sub_fonts_list) |
966 | 0 | subsets->unscaled_sub_fonts_list = sub_font; |
967 | 0 | else |
968 | 0 | subsets->unscaled_sub_fonts_list_end->next = sub_font; |
969 | 0 | subsets->unscaled_sub_fonts_list_end = sub_font; |
970 | 0 | subsets->num_sub_fonts++; |
971 | 0 | } |
972 | 0 | } else { |
973 | | /* No path available. Add to scaled subset. */ |
974 | 0 | key.is_scaled = TRUE; |
975 | 0 | _cairo_sub_font_init_key (&key, scaled_font); |
976 | 0 | sub_font = _cairo_hash_table_lookup (subsets->scaled_sub_fonts, |
977 | 0 | &key.base); |
978 | 0 | if (sub_font == NULL) { |
979 | 0 | subset_glyph->is_scaled = TRUE; |
980 | 0 | subset_glyph->is_composite = FALSE; |
981 | 0 | if (subsets->type == CAIRO_SUBSETS_SCALED) |
982 | 0 | max_glyphs = INT_MAX; |
983 | 0 | else |
984 | 0 | max_glyphs = MAX_GLYPHS_PER_SIMPLE_FONT; |
985 | |
|
986 | 0 | status = _cairo_sub_font_create (subsets, |
987 | 0 | cairo_scaled_font_reference (scaled_font), |
988 | 0 | subsets->num_sub_fonts, |
989 | 0 | max_glyphs, |
990 | 0 | subset_glyph->is_scaled, |
991 | 0 | subset_glyph->is_composite, |
992 | 0 | &sub_font); |
993 | 0 | if (unlikely (status)) { |
994 | 0 | cairo_scaled_font_destroy (scaled_font); |
995 | 0 | return status; |
996 | 0 | } |
997 | | |
998 | 0 | status = _cairo_hash_table_insert (subsets->scaled_sub_fonts, |
999 | 0 | &sub_font->base); |
1000 | 0 | if (unlikely (status)) { |
1001 | 0 | _cairo_sub_font_destroy (sub_font); |
1002 | 0 | return status; |
1003 | 0 | } |
1004 | 0 | if (!subsets->scaled_sub_fonts_list) |
1005 | 0 | subsets->scaled_sub_fonts_list = sub_font; |
1006 | 0 | else |
1007 | 0 | subsets->scaled_sub_fonts_list_end->next = sub_font; |
1008 | 0 | subsets->scaled_sub_fonts_list_end = sub_font; |
1009 | 0 | subsets->num_sub_fonts++; |
1010 | 0 | } |
1011 | 0 | } |
1012 | | |
1013 | 0 | return _cairo_sub_font_map_glyph (sub_font, |
1014 | 0 | scaled_font_glyph_index, |
1015 | 0 | utf8, utf8_len, |
1016 | 0 | subset_glyph); |
1017 | 0 | } |
1018 | | |
1019 | | static cairo_status_t |
1020 | | _cairo_scaled_font_subsets_foreach_internal (cairo_scaled_font_subsets_t *font_subsets, |
1021 | | cairo_scaled_font_subset_callback_func_t font_subset_callback, |
1022 | | void *closure, |
1023 | | cairo_subsets_foreach_type_t type) |
1024 | 2 | { |
1025 | 2 | cairo_sub_font_collection_t collection; |
1026 | 2 | cairo_sub_font_t *sub_font; |
1027 | 2 | cairo_bool_t is_scaled; |
1028 | | |
1029 | 2 | is_scaled = FALSE; |
1030 | | |
1031 | 2 | if (type == CAIRO_SUBSETS_FOREACH_SCALED) |
1032 | 2 | is_scaled = TRUE; |
1033 | | |
1034 | 2 | if (is_scaled) |
1035 | 2 | collection.glyphs_size = font_subsets->max_glyphs_per_scaled_subset_used; |
1036 | 0 | else |
1037 | 0 | collection.glyphs_size = font_subsets->max_glyphs_per_unscaled_subset_used; |
1038 | | |
1039 | 2 | if (! collection.glyphs_size) |
1040 | 2 | return CAIRO_STATUS_SUCCESS; |
1041 | | |
1042 | 0 | collection.glyphs = _cairo_malloc_ab (collection.glyphs_size, sizeof(unsigned long)); |
1043 | 0 | collection.utf8 = _cairo_malloc_ab (collection.glyphs_size, sizeof(char *)); |
1044 | 0 | collection.to_latin_char = _cairo_malloc_ab (collection.glyphs_size, sizeof(int)); |
1045 | 0 | collection.latin_to_subset_glyph_index = _cairo_malloc_ab (256, sizeof(unsigned long)); |
1046 | 0 | if (unlikely (collection.glyphs == NULL || |
1047 | 0 | collection.utf8 == NULL || |
1048 | 0 | collection.to_latin_char == NULL || |
1049 | 0 | collection.latin_to_subset_glyph_index == NULL)) { |
1050 | 0 | free (collection.glyphs); |
1051 | 0 | free (collection.utf8); |
1052 | 0 | free (collection.to_latin_char); |
1053 | 0 | free (collection.latin_to_subset_glyph_index); |
1054 | |
|
1055 | 0 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
1056 | 0 | } |
1057 | | |
1058 | 0 | collection.font_subset_callback = font_subset_callback; |
1059 | 0 | collection.font_subset_callback_closure = closure; |
1060 | 0 | collection.status = CAIRO_STATUS_SUCCESS; |
1061 | |
|
1062 | 0 | if (is_scaled) |
1063 | 0 | sub_font = font_subsets->scaled_sub_fonts_list; |
1064 | 0 | else |
1065 | 0 | sub_font = font_subsets->unscaled_sub_fonts_list; |
1066 | |
|
1067 | 0 | while (sub_font) { |
1068 | 0 | _cairo_sub_font_collect (sub_font, &collection); |
1069 | 0 | sub_font = sub_font->next; |
1070 | 0 | } |
1071 | 0 | free (collection.utf8); |
1072 | 0 | free (collection.glyphs); |
1073 | 0 | free (collection.to_latin_char); |
1074 | 0 | free (collection.latin_to_subset_glyph_index); |
1075 | |
|
1076 | 0 | return collection.status; |
1077 | 0 | } |
1078 | | |
1079 | | cairo_status_t |
1080 | | _cairo_scaled_font_subsets_foreach_scaled (cairo_scaled_font_subsets_t *font_subsets, |
1081 | | cairo_scaled_font_subset_callback_func_t font_subset_callback, |
1082 | | void *closure) |
1083 | 2 | { |
1084 | 2 | return _cairo_scaled_font_subsets_foreach_internal (font_subsets, |
1085 | 2 | font_subset_callback, |
1086 | 2 | closure, |
1087 | 2 | CAIRO_SUBSETS_FOREACH_SCALED); |
1088 | 2 | } |
1089 | | |
1090 | | cairo_status_t |
1091 | | _cairo_scaled_font_subsets_foreach_unscaled (cairo_scaled_font_subsets_t *font_subsets, |
1092 | | cairo_scaled_font_subset_callback_func_t font_subset_callback, |
1093 | | void *closure) |
1094 | 0 | { |
1095 | 0 | return _cairo_scaled_font_subsets_foreach_internal (font_subsets, |
1096 | 0 | font_subset_callback, |
1097 | 0 | closure, |
1098 | 0 | CAIRO_SUBSETS_FOREACH_UNSCALED); |
1099 | 0 | } |
1100 | | |
1101 | | static cairo_bool_t |
1102 | | _cairo_string_equal (const void *key_a, const void *key_b) |
1103 | 0 | { |
1104 | 0 | const cairo_string_entry_t *a = key_a; |
1105 | 0 | const cairo_string_entry_t *b = key_b; |
1106 | |
|
1107 | 0 | if (strcmp (a->string, b->string) == 0) |
1108 | 0 | return TRUE; |
1109 | 0 | else |
1110 | 0 | return FALSE; |
1111 | 0 | } |
1112 | | |
1113 | | #if DEBUG_SUBSETS |
1114 | | |
1115 | | static void |
1116 | | dump_glyph (void *entry, void *closure) |
1117 | | { |
1118 | | cairo_sub_font_glyph_t *glyph = entry; |
1119 | | char buf[10]; |
1120 | | int i; |
1121 | | |
1122 | | printf(" font_glyph_index: %ld\n", glyph->base.hash); |
1123 | | printf(" subset_id: %d\n", glyph->subset_id); |
1124 | | printf(" subset_glyph_index: %d\n", glyph->subset_glyph_index); |
1125 | | printf(" x_advance: %f\n", glyph->x_advance); |
1126 | | printf(" y_advance: %f\n", glyph->y_advance); |
1127 | | printf(" is_latin: %d\n", glyph->is_latin); |
1128 | | printf(" latin_character: '%c' (0x%02x)\n", glyph->latin_character, glyph->latin_character); |
1129 | | printf(" is_latin: %d\n", glyph->is_latin); |
1130 | | printf(" is_mapped: %d\n", glyph->is_mapped); |
1131 | | printf(" unicode: U+%04x\n", glyph->unicode); |
1132 | | memset(buf, 0, sizeof(buf)); |
1133 | | memcpy(buf, glyph->utf8, glyph->utf8_len); |
1134 | | printf(" utf8: '%s'\n", buf); |
1135 | | printf(" utf8 (hex):"); |
1136 | | for (i = 0; i < glyph->utf8_len; i++) |
1137 | | printf(" 0x%02x", glyph->utf8[i]); |
1138 | | printf("\n\n"); |
1139 | | } |
1140 | | |
1141 | | static void |
1142 | | dump_subfont (cairo_sub_font_t *sub_font) |
1143 | | { |
1144 | | while (sub_font) { |
1145 | | printf(" font_id: %d\n", sub_font->font_id); |
1146 | | printf(" current_subset: %d\n", sub_font->current_subset); |
1147 | | printf(" is_scaled: %d\n", sub_font->is_scaled); |
1148 | | printf(" is_composite: %d\n", sub_font->is_composite); |
1149 | | printf(" is_user: %d\n", sub_font->is_user); |
1150 | | printf(" use_latin_subset: %d\n", sub_font->use_latin_subset); |
1151 | | printf(" reserve_notdef: %d\n", sub_font->reserve_notdef); |
1152 | | printf(" num_glyphs_in_current_subset: %d\n", sub_font->num_glyphs_in_current_subset); |
1153 | | printf(" num_glyphs_in_latin_subset: %d\n", sub_font->num_glyphs_in_latin_subset); |
1154 | | printf(" max_glyphs_per_subset: %d\n\n", sub_font->max_glyphs_per_subset); |
1155 | | |
1156 | | _cairo_hash_table_foreach (sub_font->sub_font_glyphs, dump_glyph, NULL); |
1157 | | |
1158 | | printf("\n"); |
1159 | | sub_font = sub_font->next; |
1160 | | } |
1161 | | } |
1162 | | |
1163 | | void |
1164 | | dump_scaled_font_subsets (cairo_scaled_font_subsets_t *font_subsets) |
1165 | | { |
1166 | | printf("font subsets\n"); |
1167 | | switch (font_subsets->type) |
1168 | | { |
1169 | | case CAIRO_SUBSETS_SCALED: |
1170 | | printf(" type: CAIRO_SUBSETS_SCALED\n"); |
1171 | | break; |
1172 | | case CAIRO_SUBSETS_SIMPLE: |
1173 | | printf(" type: CAIRO_SUBSETS_SIMPLE\n"); |
1174 | | break; |
1175 | | case CAIRO_SUBSETS_COMPOSITE: |
1176 | | printf(" type: CAIRO_SUBSETS_COMPOSITE\n"); |
1177 | | break; |
1178 | | } |
1179 | | printf(" use_latin_subset: %d\n", font_subsets->use_latin_subset); |
1180 | | printf(" max_glyphs_per_unscaled_subset_used: %d\n", font_subsets->max_glyphs_per_unscaled_subset_used); |
1181 | | printf(" max_glyphs_per_scaled_subset_used: %d\n", font_subsets->max_glyphs_per_scaled_subset_used); |
1182 | | printf(" num_sub_fonts: %d\n\n", font_subsets->num_sub_fonts); |
1183 | | |
1184 | | printf(" scaled subsets:\n"); |
1185 | | dump_subfont (font_subsets->scaled_sub_fonts_list); |
1186 | | |
1187 | | printf("\n unscaled subsets:\n"); |
1188 | | dump_subfont (font_subsets->unscaled_sub_fonts_list); |
1189 | | } |
1190 | | |
1191 | | #endif |
1192 | | |
1193 | | |
1194 | | static void |
1195 | | _cairo_string_init_key (cairo_string_entry_t *key, char *s) |
1196 | 0 | { |
1197 | 0 | unsigned long sum = 0; |
1198 | 0 | unsigned int i; |
1199 | |
|
1200 | 0 | for (i = 0; i < strlen(s); i++) |
1201 | 0 | sum += s[i]; |
1202 | 0 | key->base.hash = sum; |
1203 | 0 | key->string = s; |
1204 | 0 | } |
1205 | | |
1206 | | static cairo_status_t |
1207 | | create_string_entry (char *s, cairo_string_entry_t **entry) |
1208 | 0 | { |
1209 | 0 | *entry = _cairo_calloc (sizeof (cairo_string_entry_t)); |
1210 | 0 | if (unlikely (*entry == NULL)) |
1211 | 0 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
1212 | | |
1213 | 0 | _cairo_string_init_key (*entry, s); |
1214 | |
|
1215 | 0 | return CAIRO_STATUS_SUCCESS; |
1216 | 0 | } |
1217 | | |
1218 | | static void |
1219 | | _pluck_entry (void *entry, void *closure) |
1220 | 0 | { |
1221 | 0 | _cairo_hash_table_remove (closure, entry); |
1222 | 0 | free (entry); |
1223 | 0 | } |
1224 | | |
1225 | | cairo_int_status_t |
1226 | | _cairo_scaled_font_subset_create_glyph_names (cairo_scaled_font_subset_t *subset) |
1227 | 0 | { |
1228 | 0 | unsigned int i; |
1229 | 0 | cairo_hash_table_t *names; |
1230 | 0 | cairo_string_entry_t key, *entry; |
1231 | 0 | char buf[30]; |
1232 | 0 | char *utf8; |
1233 | 0 | uint16_t *utf16; |
1234 | 0 | int utf16_len; |
1235 | 0 | cairo_status_t status = CAIRO_STATUS_SUCCESS; |
1236 | |
|
1237 | 0 | names = _cairo_hash_table_create (_cairo_string_equal); |
1238 | 0 | if (unlikely (names == NULL)) |
1239 | 0 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
1240 | | |
1241 | 0 | subset->glyph_names = _cairo_calloc_ab (subset->num_glyphs, sizeof (char *)); |
1242 | 0 | if (unlikely (subset->glyph_names == NULL)) { |
1243 | 0 | status = _cairo_error (CAIRO_STATUS_NO_MEMORY); |
1244 | 0 | goto CLEANUP_HASH; |
1245 | 0 | } |
1246 | | |
1247 | 0 | i = 0; |
1248 | 0 | if (! subset->is_scaled) { |
1249 | 0 | subset->glyph_names[0] = strdup (".notdef"); |
1250 | 0 | if (unlikely (subset->glyph_names[0] == NULL)) { |
1251 | 0 | status = _cairo_error (CAIRO_STATUS_NO_MEMORY); |
1252 | 0 | goto CLEANUP_HASH; |
1253 | 0 | } |
1254 | | |
1255 | 0 | status = create_string_entry (subset->glyph_names[0], &entry); |
1256 | 0 | if (unlikely (status)) |
1257 | 0 | goto CLEANUP_HASH; |
1258 | | |
1259 | 0 | status = _cairo_hash_table_insert (names, &entry->base); |
1260 | 0 | if (unlikely (status)) { |
1261 | 0 | free (entry); |
1262 | 0 | goto CLEANUP_HASH; |
1263 | 0 | } |
1264 | 0 | i++; |
1265 | 0 | } |
1266 | | |
1267 | 0 | for (; i < subset->num_glyphs; i++) { |
1268 | 0 | utf8 = subset->utf8[i]; |
1269 | 0 | utf16 = NULL; |
1270 | 0 | utf16_len = 0; |
1271 | 0 | if (utf8 && *utf8) { |
1272 | 0 | status = _cairo_utf8_to_utf16 (utf8, -1, &utf16, &utf16_len); |
1273 | 0 | if (status == CAIRO_STATUS_INVALID_STRING) { |
1274 | 0 | utf16 = NULL; |
1275 | 0 | utf16_len = 0; |
1276 | 0 | } else if (unlikely (status)) { |
1277 | 0 | goto CLEANUP_HASH; |
1278 | 0 | } |
1279 | 0 | } |
1280 | | |
1281 | 0 | if (utf16_len == 1) { |
1282 | 0 | int ch = _cairo_unicode_to_winansi (utf16[0]); |
1283 | 0 | if (ch > 0 && _cairo_winansi_to_glyphname (ch)) { |
1284 | 0 | strncpy (buf, _cairo_winansi_to_glyphname (ch), sizeof (buf)); |
1285 | 0 | buf[sizeof (buf)-1] = '\0'; |
1286 | 0 | } else { |
1287 | 0 | snprintf (buf, sizeof (buf), "uni%04X", (int) utf16[0]); |
1288 | 0 | } |
1289 | |
|
1290 | 0 | _cairo_string_init_key (&key, buf); |
1291 | 0 | entry = _cairo_hash_table_lookup (names, &key.base); |
1292 | 0 | if (entry != NULL) |
1293 | 0 | snprintf (buf, sizeof (buf), "g%d", i); |
1294 | 0 | } else { |
1295 | 0 | snprintf (buf, sizeof (buf), "g%d", i); |
1296 | 0 | } |
1297 | 0 | free (utf16); |
1298 | |
|
1299 | 0 | subset->glyph_names[i] = strdup (buf); |
1300 | 0 | if (unlikely (subset->glyph_names[i] == NULL)) { |
1301 | 0 | status = _cairo_error (CAIRO_STATUS_NO_MEMORY); |
1302 | 0 | goto CLEANUP_HASH; |
1303 | 0 | } |
1304 | | |
1305 | 0 | status = create_string_entry (subset->glyph_names[i], &entry); |
1306 | 0 | if (unlikely (status)) |
1307 | 0 | goto CLEANUP_HASH; |
1308 | | |
1309 | 0 | status = _cairo_hash_table_insert (names, &entry->base); |
1310 | 0 | if (unlikely (status)) { |
1311 | 0 | free (entry); |
1312 | 0 | goto CLEANUP_HASH; |
1313 | 0 | } |
1314 | 0 | } |
1315 | | |
1316 | 0 | CLEANUP_HASH: |
1317 | 0 | _cairo_hash_table_foreach (names, _pluck_entry, names); |
1318 | 0 | _cairo_hash_table_destroy (names); |
1319 | |
|
1320 | 0 | if (likely (status == CAIRO_STATUS_SUCCESS)) |
1321 | 0 | return CAIRO_STATUS_SUCCESS; |
1322 | | |
1323 | 0 | if (subset->glyph_names != NULL) { |
1324 | 0 | for (i = 0; i < subset->num_glyphs; i++) { |
1325 | 0 | free (subset->glyph_names[i]); |
1326 | 0 | } |
1327 | |
|
1328 | 0 | free (subset->glyph_names); |
1329 | 0 | subset->glyph_names = NULL; |
1330 | 0 | } |
1331 | |
|
1332 | 0 | return status; |
1333 | 0 | } |
1334 | | |
1335 | | cairo_int_status_t |
1336 | | _cairo_escape_ps_name (char **ps_name) |
1337 | 0 | { |
1338 | 0 | cairo_status_t status = CAIRO_STATUS_SUCCESS; |
1339 | | |
1340 | | /* Ensure PS name is a valid PDF/PS name object. In PDF names are |
1341 | | * treated as UTF8 and non ASCII bytes, ' ', and '#' are encoded |
1342 | | * as '#' followed by 2 hex digits that encode the byte. By also |
1343 | | * encoding the characters in the reserved string we ensure the |
1344 | | * name is also PS compatible. */ |
1345 | 0 | if (*ps_name) { |
1346 | 0 | static const char *reserved = "()<>[]{}/%#\\"; |
1347 | 0 | char buf[128]; /* max name length is 127 bytes */ |
1348 | 0 | char *src = *ps_name; |
1349 | 0 | char *dst = buf; |
1350 | |
|
1351 | 0 | while (*src && dst < buf + 127) { |
1352 | 0 | unsigned char c = *src; |
1353 | 0 | if (c < 0x21 || c > 0x7e || strchr (reserved, c)) { |
1354 | 0 | if (dst + 4 > buf + 127) |
1355 | 0 | break; |
1356 | | |
1357 | 0 | snprintf (dst, 4, "#%02X", c); |
1358 | 0 | src++; |
1359 | 0 | dst += 3; |
1360 | 0 | } else { |
1361 | 0 | *dst++ = *src++; |
1362 | 0 | } |
1363 | 0 | } |
1364 | 0 | *dst = 0; |
1365 | 0 | free (*ps_name); |
1366 | 0 | *ps_name = strdup (buf); |
1367 | 0 | if (*ps_name == NULL) { |
1368 | 0 | status = _cairo_error (CAIRO_STATUS_NO_MEMORY); |
1369 | 0 | } |
1370 | 0 | } |
1371 | |
|
1372 | 0 | return status; |
1373 | 0 | } |
1374 | | |
1375 | | #endif /* CAIRO_HAS_FONT_SUBSET */ |