Line data Source code
1 : /* cairo - a vector graphics library with display and print output
2 : *
3 : * Copyright © 2003 University of Southern California
4 : * Copyright © 2005 Red Hat, Inc
5 : * Copyright © 2006 Keith Packard
6 : * Copyright © 2006 Red Hat, Inc
7 : *
8 : * This library is free software; you can redistribute it and/or
9 : * modify it either under the terms of the GNU Lesser General Public
10 : * License version 2.1 as published by the Free Software Foundation
11 : * (the "LGPL") or, at your option, under the terms of the Mozilla
12 : * Public License Version 1.1 (the "MPL"). If you do not alter this
13 : * notice, a recipient may use your version of this file under either
14 : * the MPL or the LGPL.
15 : *
16 : * You should have received a copy of the LGPL along with this library
17 : * in the file COPYING-LGPL-2.1; if not, write to the Free Software
18 : * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
19 : * You should have received a copy of the MPL along with this library
20 : * in the file COPYING-MPL-1.1
21 : *
22 : * The contents of this file are subject to the Mozilla Public License
23 : * Version 1.1 (the "License"); you may not use this file except in
24 : * compliance with the License. You may obtain a copy of the License at
25 : * http://www.mozilla.org/MPL/
26 : *
27 : * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
28 : * OF ANY KIND, either express or implied. See the LGPL or the MPL for
29 : * the specific language governing rights and limitations.
30 : *
31 : * The Original Code is the cairo graphics library.
32 : *
33 : * The Initial Developer of the Original Code is University of Southern
34 : * California.
35 : *
36 : * Contributor(s):
37 : * Carl D. Worth <cworth@cworth.org>
38 : * Kristian Høgsberg <krh@redhat.com>
39 : * Keith Packard <keithp@keithp.com>
40 : * Adrian Johnson <ajohnson@redneon.com>
41 : */
42 :
43 : #define _BSD_SOURCE /* for snprintf(), strdup() */
44 : #include "cairoint.h"
45 : #include "cairo-error-private.h"
46 :
47 : #if CAIRO_HAS_FONT_SUBSET
48 :
49 : #include "cairo-scaled-font-subsets-private.h"
50 : #include "cairo-user-font-private.h"
51 :
52 : #define MAX_GLYPHS_PER_SIMPLE_FONT 256
53 : #define MAX_GLYPHS_PER_COMPOSITE_FONT 65536
54 :
55 : typedef enum {
56 : CAIRO_SUBSETS_SCALED,
57 : CAIRO_SUBSETS_SIMPLE,
58 : CAIRO_SUBSETS_COMPOSITE
59 : } cairo_subsets_type_t;
60 :
61 : typedef enum {
62 : CAIRO_SUBSETS_FOREACH_UNSCALED,
63 : CAIRO_SUBSETS_FOREACH_SCALED,
64 : CAIRO_SUBSETS_FOREACH_USER
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 is_user;
73 : cairo_scaled_font_subsets_t *parent;
74 : cairo_scaled_font_t *scaled_font;
75 : unsigned int font_id;
76 :
77 : int current_subset;
78 : int num_glyphs_in_current_subset;
79 : int max_glyphs_per_subset;
80 :
81 : cairo_hash_table_t *sub_font_glyphs;
82 : struct _cairo_sub_font *next;
83 : } cairo_sub_font_t;
84 :
85 : struct _cairo_scaled_font_subsets {
86 : cairo_subsets_type_t type;
87 :
88 : int max_glyphs_per_unscaled_subset_used;
89 : cairo_hash_table_t *unscaled_sub_fonts;
90 : cairo_sub_font_t *unscaled_sub_fonts_list;
91 : cairo_sub_font_t *unscaled_sub_fonts_list_end;
92 :
93 : int max_glyphs_per_scaled_subset_used;
94 : cairo_hash_table_t *scaled_sub_fonts;
95 : cairo_sub_font_t *scaled_sub_fonts_list;
96 : cairo_sub_font_t *scaled_sub_fonts_list_end;
97 :
98 : int num_sub_fonts;
99 : };
100 :
101 : typedef struct _cairo_sub_font_glyph {
102 : cairo_hash_entry_t base;
103 :
104 : unsigned int subset_id;
105 : unsigned int subset_glyph_index;
106 : double x_advance;
107 : double y_advance;
108 :
109 : cairo_bool_t is_mapped;
110 : uint32_t unicode;
111 : char *utf8;
112 : int utf8_len;
113 : } cairo_sub_font_glyph_t;
114 :
115 : typedef struct _cairo_sub_font_collection {
116 : unsigned long *glyphs; /* scaled_font_glyph_index */
117 : char **utf8;
118 : unsigned int glyphs_size;
119 : unsigned int max_glyph;
120 : unsigned int num_glyphs;
121 :
122 : unsigned int subset_id;
123 :
124 : cairo_status_t status;
125 : cairo_scaled_font_subset_callback_func_t font_subset_callback;
126 : void *font_subset_callback_closure;
127 : } cairo_sub_font_collection_t;
128 :
129 : typedef struct _cairo_string_entry {
130 : cairo_hash_entry_t base;
131 : char *string;
132 : } cairo_string_entry_t;
133 :
134 : static cairo_status_t
135 : _cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font,
136 : unsigned long scaled_font_glyph_index,
137 : const char * utf8,
138 : int utf8_len,
139 : cairo_scaled_font_subsets_glyph_t *subset_glyph);
140 :
141 : static void
142 0 : _cairo_sub_font_glyph_init_key (cairo_sub_font_glyph_t *sub_font_glyph,
143 : unsigned long scaled_font_glyph_index)
144 : {
145 0 : sub_font_glyph->base.hash = scaled_font_glyph_index;
146 0 : }
147 :
148 : static cairo_bool_t
149 0 : _cairo_sub_font_glyphs_equal (const void *key_a, const void *key_b)
150 : {
151 0 : const cairo_sub_font_glyph_t *sub_font_glyph_a = key_a;
152 0 : const cairo_sub_font_glyph_t *sub_font_glyph_b = key_b;
153 :
154 0 : return sub_font_glyph_a->base.hash == sub_font_glyph_b->base.hash;
155 : }
156 :
157 : static cairo_sub_font_glyph_t *
158 0 : _cairo_sub_font_glyph_create (unsigned long scaled_font_glyph_index,
159 : unsigned int subset_id,
160 : unsigned int subset_glyph_index,
161 : double x_advance,
162 : double y_advance)
163 : {
164 : cairo_sub_font_glyph_t *sub_font_glyph;
165 :
166 0 : sub_font_glyph = malloc (sizeof (cairo_sub_font_glyph_t));
167 0 : if (unlikely (sub_font_glyph == NULL)) {
168 0 : _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
169 0 : return NULL;
170 : }
171 :
172 0 : _cairo_sub_font_glyph_init_key (sub_font_glyph, scaled_font_glyph_index);
173 0 : sub_font_glyph->subset_id = subset_id;
174 0 : sub_font_glyph->subset_glyph_index = subset_glyph_index;
175 0 : sub_font_glyph->x_advance = x_advance;
176 0 : sub_font_glyph->y_advance = y_advance;
177 0 : sub_font_glyph->is_mapped = FALSE;
178 0 : sub_font_glyph->unicode = -1;
179 0 : sub_font_glyph->utf8 = NULL;
180 0 : sub_font_glyph->utf8_len = 0;
181 :
182 0 : return sub_font_glyph;
183 : }
184 :
185 : static void
186 0 : _cairo_sub_font_glyph_destroy (cairo_sub_font_glyph_t *sub_font_glyph)
187 : {
188 0 : if (sub_font_glyph->utf8 != NULL)
189 0 : free (sub_font_glyph->utf8);
190 :
191 0 : free (sub_font_glyph);
192 0 : }
193 :
194 : static void
195 0 : _cairo_sub_font_glyph_pluck (void *entry, void *closure)
196 : {
197 0 : cairo_sub_font_glyph_t *sub_font_glyph = entry;
198 0 : cairo_hash_table_t *sub_font_glyphs = closure;
199 :
200 0 : _cairo_hash_table_remove (sub_font_glyphs, &sub_font_glyph->base);
201 0 : _cairo_sub_font_glyph_destroy (sub_font_glyph);
202 0 : }
203 :
204 : static void
205 0 : _cairo_sub_font_glyph_collect (void *entry, void *closure)
206 : {
207 0 : cairo_sub_font_glyph_t *sub_font_glyph = entry;
208 0 : cairo_sub_font_collection_t *collection = closure;
209 : unsigned long scaled_font_glyph_index;
210 : unsigned int subset_glyph_index;
211 :
212 0 : if (sub_font_glyph->subset_id != collection->subset_id)
213 0 : return;
214 :
215 0 : scaled_font_glyph_index = sub_font_glyph->base.hash;
216 0 : subset_glyph_index = sub_font_glyph->subset_glyph_index;
217 :
218 : /* Ensure we don't exceed the allocated bounds. */
219 0 : assert (subset_glyph_index < collection->glyphs_size);
220 :
221 0 : collection->glyphs[subset_glyph_index] = scaled_font_glyph_index;
222 0 : collection->utf8[subset_glyph_index] = sub_font_glyph->utf8;
223 0 : if (subset_glyph_index > collection->max_glyph)
224 0 : collection->max_glyph = subset_glyph_index;
225 :
226 0 : collection->num_glyphs++;
227 : }
228 :
229 : static cairo_bool_t
230 0 : _cairo_sub_fonts_equal (const void *key_a, const void *key_b)
231 : {
232 0 : const cairo_sub_font_t *sub_font_a = key_a;
233 0 : const cairo_sub_font_t *sub_font_b = key_b;
234 0 : cairo_scaled_font_t *a = sub_font_a->scaled_font;
235 0 : cairo_scaled_font_t *b = sub_font_b->scaled_font;
236 :
237 0 : if (sub_font_a->is_scaled)
238 0 : return a == b;
239 : else
240 0 : return a->font_face == b->font_face || a->original_font_face == b->original_font_face;
241 : }
242 :
243 : static void
244 0 : _cairo_sub_font_init_key (cairo_sub_font_t *sub_font,
245 : cairo_scaled_font_t *scaled_font)
246 : {
247 0 : if (sub_font->is_scaled)
248 : {
249 0 : sub_font->base.hash = (unsigned long) scaled_font;
250 0 : sub_font->scaled_font = scaled_font;
251 : }
252 : else
253 : {
254 0 : sub_font->base.hash = (unsigned long) scaled_font->font_face;
255 0 : sub_font->scaled_font = scaled_font;
256 : }
257 0 : }
258 :
259 : static cairo_status_t
260 0 : _cairo_sub_font_create (cairo_scaled_font_subsets_t *parent,
261 : cairo_scaled_font_t *scaled_font,
262 : unsigned int font_id,
263 : int max_glyphs_per_subset,
264 : cairo_bool_t is_scaled,
265 : cairo_bool_t is_composite,
266 : cairo_sub_font_t **sub_font_out)
267 : {
268 : cairo_sub_font_t *sub_font;
269 : cairo_status_t status;
270 : cairo_scaled_font_subsets_glyph_t subset_glyph;
271 :
272 0 : sub_font = malloc (sizeof (cairo_sub_font_t));
273 0 : if (unlikely (sub_font == NULL))
274 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
275 :
276 0 : sub_font->is_scaled = is_scaled;
277 0 : sub_font->is_composite = is_composite;
278 0 : sub_font->is_user = _cairo_font_face_is_user (scaled_font->font_face);
279 0 : _cairo_sub_font_init_key (sub_font, scaled_font);
280 :
281 0 : sub_font->parent = parent;
282 0 : sub_font->scaled_font = scaled_font;
283 0 : sub_font->font_id = font_id;
284 :
285 0 : sub_font->current_subset = 0;
286 0 : sub_font->num_glyphs_in_current_subset = 0;
287 0 : sub_font->max_glyphs_per_subset = max_glyphs_per_subset;
288 :
289 0 : sub_font->sub_font_glyphs = _cairo_hash_table_create (_cairo_sub_font_glyphs_equal);
290 0 : if (unlikely (sub_font->sub_font_glyphs == NULL)) {
291 0 : free (sub_font);
292 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
293 : }
294 0 : sub_font->next = NULL;
295 :
296 : /* Reserve first glyph in subset for the .notdef glyph except for
297 : * Type 3 fonts */
298 0 : if (! is_scaled) {
299 0 : status = _cairo_sub_font_map_glyph (sub_font, 0, NULL, -1, &subset_glyph);
300 0 : if (unlikely (status)) {
301 0 : _cairo_hash_table_destroy (sub_font->sub_font_glyphs);
302 0 : free (sub_font);
303 0 : return status;
304 : }
305 : }
306 :
307 0 : *sub_font_out = sub_font;
308 0 : return CAIRO_STATUS_SUCCESS;
309 : }
310 :
311 : static void
312 0 : _cairo_sub_font_destroy (cairo_sub_font_t *sub_font)
313 : {
314 0 : _cairo_hash_table_foreach (sub_font->sub_font_glyphs,
315 : _cairo_sub_font_glyph_pluck,
316 0 : sub_font->sub_font_glyphs);
317 0 : _cairo_hash_table_destroy (sub_font->sub_font_glyphs);
318 0 : cairo_scaled_font_destroy (sub_font->scaled_font);
319 0 : free (sub_font);
320 0 : }
321 :
322 : static void
323 0 : _cairo_sub_font_pluck (void *entry, void *closure)
324 : {
325 0 : cairo_sub_font_t *sub_font = entry;
326 0 : cairo_hash_table_t *sub_fonts = closure;
327 :
328 0 : _cairo_hash_table_remove (sub_fonts, &sub_font->base);
329 0 : _cairo_sub_font_destroy (sub_font);
330 0 : }
331 :
332 : static cairo_status_t
333 0 : _cairo_sub_font_glyph_lookup_unicode (cairo_sub_font_glyph_t *sub_font_glyph,
334 : cairo_scaled_font_t *scaled_font,
335 : unsigned long scaled_font_glyph_index)
336 : {
337 : uint32_t unicode;
338 : char buf[8];
339 : int len;
340 : cairo_status_t status;
341 :
342 : /* Do a reverse lookup on the glyph index. unicode is -1 if the
343 : * index could not be mapped to a unicode character. */
344 0 : unicode = -1;
345 0 : status = _cairo_truetype_index_to_ucs4 (scaled_font,
346 : scaled_font_glyph_index,
347 : &unicode);
348 0 : if (_cairo_status_is_error (status))
349 0 : return status;
350 :
351 0 : if (unicode == (uint32_t)-1 && scaled_font->backend->index_to_ucs4) {
352 0 : status = scaled_font->backend->index_to_ucs4 (scaled_font,
353 : scaled_font_glyph_index,
354 : &unicode);
355 0 : if (unlikely (status))
356 0 : return status;
357 : }
358 :
359 0 : sub_font_glyph->unicode = unicode;
360 0 : sub_font_glyph->utf8 = NULL;
361 0 : sub_font_glyph->utf8_len = 0;
362 0 : if (unicode != (uint32_t) -1) {
363 0 : len = _cairo_ucs4_to_utf8 (unicode, buf);
364 0 : if (len > 0) {
365 0 : sub_font_glyph->utf8 = malloc (len + 1);
366 0 : if (unlikely (sub_font_glyph->utf8 == NULL))
367 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
368 :
369 0 : memcpy (sub_font_glyph->utf8, buf, len);
370 0 : sub_font_glyph->utf8[len] = 0;
371 0 : sub_font_glyph->utf8_len = len;
372 : }
373 : }
374 :
375 0 : return CAIRO_STATUS_SUCCESS;
376 : }
377 :
378 : static cairo_status_t
379 0 : _cairo_sub_font_glyph_map_to_unicode (cairo_sub_font_glyph_t *sub_font_glyph,
380 : const char *utf8,
381 : int utf8_len,
382 : cairo_bool_t *is_mapped)
383 : {
384 0 : *is_mapped = FALSE;
385 :
386 0 : if (utf8_len < 0)
387 0 : return CAIRO_STATUS_SUCCESS;
388 :
389 0 : if (utf8 != NULL && utf8_len != 0 && utf8[utf8_len - 1] == '\0')
390 0 : utf8_len--;
391 :
392 0 : if (utf8 != NULL && utf8_len != 0) {
393 0 : if (sub_font_glyph->utf8 != NULL) {
394 0 : if (utf8_len == sub_font_glyph->utf8_len &&
395 0 : memcmp (utf8, sub_font_glyph->utf8, utf8_len) == 0)
396 : {
397 : /* Requested utf8 mapping matches the existing mapping */
398 0 : *is_mapped = TRUE;
399 : }
400 : } else {
401 : /* No existing mapping. Use the requested mapping */
402 0 : sub_font_glyph->utf8 = malloc (utf8_len + 1);
403 0 : if (unlikely (sub_font_glyph->utf8 == NULL))
404 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
405 :
406 0 : memcpy (sub_font_glyph->utf8, utf8, utf8_len);
407 0 : sub_font_glyph->utf8[utf8_len] = 0;
408 0 : sub_font_glyph->utf8_len = utf8_len;
409 0 : *is_mapped = TRUE;
410 : }
411 : }
412 :
413 0 : return CAIRO_STATUS_SUCCESS;
414 : }
415 :
416 : static cairo_int_status_t
417 0 : _cairo_sub_font_lookup_glyph (cairo_sub_font_t *sub_font,
418 : unsigned long scaled_font_glyph_index,
419 : const char *utf8,
420 : int utf8_len,
421 : cairo_scaled_font_subsets_glyph_t *subset_glyph)
422 : {
423 : cairo_sub_font_glyph_t key, *sub_font_glyph;
424 : cairo_int_status_t status;
425 :
426 0 : _cairo_sub_font_glyph_init_key (&key, scaled_font_glyph_index);
427 0 : sub_font_glyph = _cairo_hash_table_lookup (sub_font->sub_font_glyphs,
428 : &key.base);
429 0 : if (sub_font_glyph != NULL) {
430 0 : subset_glyph->font_id = sub_font->font_id;
431 0 : subset_glyph->subset_id = sub_font_glyph->subset_id;
432 0 : subset_glyph->subset_glyph_index = sub_font_glyph->subset_glyph_index;
433 0 : subset_glyph->is_scaled = sub_font->is_scaled;
434 0 : subset_glyph->is_composite = sub_font->is_composite;
435 0 : subset_glyph->x_advance = sub_font_glyph->x_advance;
436 0 : subset_glyph->y_advance = sub_font_glyph->y_advance;
437 0 : status = _cairo_sub_font_glyph_map_to_unicode (sub_font_glyph,
438 : utf8, utf8_len,
439 : &subset_glyph->utf8_is_mapped);
440 0 : subset_glyph->unicode = sub_font_glyph->unicode;
441 :
442 0 : return status;
443 : }
444 :
445 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
446 : }
447 :
448 : static cairo_status_t
449 0 : _cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font,
450 : unsigned long scaled_font_glyph_index,
451 : const char *utf8,
452 : int utf8_len,
453 : cairo_scaled_font_subsets_glyph_t *subset_glyph)
454 : {
455 : cairo_sub_font_glyph_t key, *sub_font_glyph;
456 : cairo_status_t status;
457 :
458 0 : _cairo_sub_font_glyph_init_key (&key, scaled_font_glyph_index);
459 0 : sub_font_glyph = _cairo_hash_table_lookup (sub_font->sub_font_glyphs,
460 : &key.base);
461 0 : if (sub_font_glyph == NULL) {
462 : cairo_scaled_glyph_t *scaled_glyph;
463 :
464 0 : if (sub_font->num_glyphs_in_current_subset == sub_font->max_glyphs_per_subset)
465 : {
466 : cairo_scaled_font_subsets_glyph_t tmp_subset_glyph;
467 :
468 0 : sub_font->current_subset++;
469 0 : sub_font->num_glyphs_in_current_subset = 0;
470 :
471 : /* Reserve first glyph in subset for the .notdef glyph
472 : * except for Type 3 fonts */
473 0 : if (! _cairo_font_face_is_user (sub_font->scaled_font->font_face)) {
474 0 : status = _cairo_sub_font_map_glyph (sub_font, 0, NULL, -1, &tmp_subset_glyph);
475 0 : if (unlikely (status))
476 0 : return status;
477 : }
478 : }
479 :
480 0 : _cairo_scaled_font_freeze_cache (sub_font->scaled_font);
481 0 : status = _cairo_scaled_glyph_lookup (sub_font->scaled_font,
482 : scaled_font_glyph_index,
483 : CAIRO_SCALED_GLYPH_INFO_METRICS,
484 : &scaled_glyph);
485 0 : assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
486 0 : if (unlikely (status)) {
487 0 : _cairo_scaled_font_thaw_cache (sub_font->scaled_font);
488 0 : return status;
489 : }
490 :
491 0 : sub_font_glyph = _cairo_sub_font_glyph_create (scaled_font_glyph_index,
492 0 : sub_font->current_subset,
493 0 : sub_font->num_glyphs_in_current_subset,
494 0 : scaled_glyph->metrics.x_advance,
495 0 : scaled_glyph->metrics.y_advance);
496 0 : _cairo_scaled_font_thaw_cache (sub_font->scaled_font);
497 :
498 0 : if (unlikely (sub_font_glyph == NULL))
499 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
500 :
501 0 : status = _cairo_sub_font_glyph_lookup_unicode (sub_font_glyph,
502 : sub_font->scaled_font,
503 : scaled_font_glyph_index);
504 0 : if (unlikely (status)) {
505 0 : _cairo_sub_font_glyph_destroy (sub_font_glyph);
506 0 : return status;
507 : }
508 :
509 0 : status = _cairo_hash_table_insert (sub_font->sub_font_glyphs, &sub_font_glyph->base);
510 0 : if (unlikely (status)) {
511 0 : _cairo_sub_font_glyph_destroy (sub_font_glyph);
512 0 : return status;
513 : }
514 :
515 0 : sub_font->num_glyphs_in_current_subset++;
516 :
517 0 : if (sub_font->is_scaled) {
518 0 : if (sub_font->num_glyphs_in_current_subset > sub_font->parent->max_glyphs_per_scaled_subset_used)
519 0 : sub_font->parent->max_glyphs_per_scaled_subset_used = sub_font->num_glyphs_in_current_subset;
520 : } else {
521 0 : if (sub_font->num_glyphs_in_current_subset > sub_font->parent->max_glyphs_per_unscaled_subset_used)
522 0 : sub_font->parent->max_glyphs_per_unscaled_subset_used = sub_font->num_glyphs_in_current_subset;
523 : }
524 : }
525 :
526 0 : subset_glyph->font_id = sub_font->font_id;
527 0 : subset_glyph->subset_id = sub_font_glyph->subset_id;
528 0 : subset_glyph->subset_glyph_index = sub_font_glyph->subset_glyph_index;
529 0 : subset_glyph->is_scaled = sub_font->is_scaled;
530 0 : subset_glyph->is_composite = sub_font->is_composite;
531 0 : subset_glyph->x_advance = sub_font_glyph->x_advance;
532 0 : subset_glyph->y_advance = sub_font_glyph->y_advance;
533 0 : status = _cairo_sub_font_glyph_map_to_unicode (sub_font_glyph,
534 : utf8, utf8_len,
535 : &subset_glyph->utf8_is_mapped);
536 0 : subset_glyph->unicode = sub_font_glyph->unicode;
537 :
538 0 : return status;
539 : }
540 :
541 : static void
542 0 : _cairo_sub_font_collect (void *entry, void *closure)
543 : {
544 0 : cairo_sub_font_t *sub_font = entry;
545 0 : cairo_sub_font_collection_t *collection = closure;
546 : cairo_scaled_font_subset_t subset;
547 : int i;
548 : unsigned int j;
549 :
550 0 : if (collection->status)
551 0 : return;
552 :
553 0 : collection->status = sub_font->scaled_font->status;
554 0 : if (collection->status)
555 0 : return;
556 :
557 0 : for (i = 0; i <= sub_font->current_subset; i++) {
558 0 : collection->subset_id = i;
559 0 : collection->num_glyphs = 0;
560 0 : collection->max_glyph = 0;
561 :
562 0 : _cairo_hash_table_foreach (sub_font->sub_font_glyphs,
563 : _cairo_sub_font_glyph_collect, collection);
564 0 : if (collection->status)
565 0 : break;
566 0 : if (collection->num_glyphs == 0)
567 0 : continue;
568 :
569 : /* Ensure the resulting array has no uninitialized holes */
570 0 : assert (collection->num_glyphs == collection->max_glyph + 1);
571 :
572 0 : subset.scaled_font = sub_font->scaled_font;
573 0 : subset.is_composite = sub_font->is_composite;
574 0 : subset.is_scaled = sub_font->is_scaled;
575 0 : subset.font_id = sub_font->font_id;
576 0 : subset.subset_id = i;
577 0 : subset.glyphs = collection->glyphs;
578 0 : subset.utf8 = collection->utf8;
579 0 : subset.num_glyphs = collection->num_glyphs;
580 0 : subset.glyph_names = NULL;
581 : /* No need to check for out of memory here. If to_unicode is NULL, the PDF
582 : * surface does not emit an ToUnicode stream */
583 0 : subset.to_unicode = _cairo_malloc_ab (collection->num_glyphs, sizeof (unsigned long));
584 0 : if (subset.to_unicode) {
585 0 : for (j = 0; j < collection->num_glyphs; j++) {
586 : /* default unicode character required when mapping fails */
587 0 : subset.to_unicode[j] = 0xfffd;
588 : }
589 : }
590 0 : collection->status = (collection->font_subset_callback) (&subset,
591 : collection->font_subset_callback_closure);
592 :
593 0 : if (subset.to_unicode != NULL)
594 0 : free (subset.to_unicode);
595 :
596 0 : if (subset.glyph_names != NULL) {
597 0 : for (j = 0; j < collection->num_glyphs; j++)
598 0 : free (subset.glyph_names[j]);
599 0 : free (subset.glyph_names);
600 : }
601 :
602 0 : if (collection->status)
603 0 : break;
604 : }
605 : }
606 :
607 : static cairo_scaled_font_subsets_t *
608 0 : _cairo_scaled_font_subsets_create_internal (cairo_subsets_type_t type)
609 : {
610 : cairo_scaled_font_subsets_t *subsets;
611 :
612 0 : subsets = malloc (sizeof (cairo_scaled_font_subsets_t));
613 0 : if (unlikely (subsets == NULL)) {
614 0 : _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
615 0 : return NULL;
616 : }
617 :
618 0 : subsets->type = type;
619 0 : subsets->max_glyphs_per_unscaled_subset_used = 0;
620 0 : subsets->max_glyphs_per_scaled_subset_used = 0;
621 0 : subsets->num_sub_fonts = 0;
622 :
623 0 : subsets->unscaled_sub_fonts = _cairo_hash_table_create (_cairo_sub_fonts_equal);
624 0 : if (! subsets->unscaled_sub_fonts) {
625 0 : free (subsets);
626 0 : return NULL;
627 : }
628 0 : subsets->unscaled_sub_fonts_list = NULL;
629 0 : subsets->unscaled_sub_fonts_list_end = NULL;
630 :
631 0 : subsets->scaled_sub_fonts = _cairo_hash_table_create (_cairo_sub_fonts_equal);
632 0 : if (! subsets->scaled_sub_fonts) {
633 0 : _cairo_hash_table_destroy (subsets->unscaled_sub_fonts);
634 0 : free (subsets);
635 0 : return NULL;
636 : }
637 0 : subsets->scaled_sub_fonts_list = NULL;
638 0 : subsets->scaled_sub_fonts_list_end = NULL;
639 :
640 0 : return subsets;
641 : }
642 :
643 : cairo_scaled_font_subsets_t *
644 0 : _cairo_scaled_font_subsets_create_scaled (void)
645 : {
646 0 : return _cairo_scaled_font_subsets_create_internal (CAIRO_SUBSETS_SCALED);
647 : }
648 :
649 : cairo_scaled_font_subsets_t *
650 0 : _cairo_scaled_font_subsets_create_simple (void)
651 : {
652 0 : return _cairo_scaled_font_subsets_create_internal (CAIRO_SUBSETS_SIMPLE);
653 : }
654 :
655 : cairo_scaled_font_subsets_t *
656 0 : _cairo_scaled_font_subsets_create_composite (void)
657 : {
658 0 : return _cairo_scaled_font_subsets_create_internal (CAIRO_SUBSETS_COMPOSITE);
659 : }
660 :
661 : void
662 0 : _cairo_scaled_font_subsets_destroy (cairo_scaled_font_subsets_t *subsets)
663 : {
664 0 : _cairo_hash_table_foreach (subsets->scaled_sub_fonts, _cairo_sub_font_pluck, subsets->scaled_sub_fonts);
665 0 : _cairo_hash_table_destroy (subsets->scaled_sub_fonts);
666 :
667 0 : _cairo_hash_table_foreach (subsets->unscaled_sub_fonts, _cairo_sub_font_pluck, subsets->unscaled_sub_fonts);
668 0 : _cairo_hash_table_destroy (subsets->unscaled_sub_fonts);
669 :
670 0 : free (subsets);
671 0 : }
672 :
673 : cairo_status_t
674 0 : _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets,
675 : cairo_scaled_font_t *scaled_font,
676 : unsigned long scaled_font_glyph_index,
677 : const char * utf8,
678 : int utf8_len,
679 : cairo_scaled_font_subsets_glyph_t *subset_glyph)
680 : {
681 : cairo_sub_font_t key, *sub_font;
682 : cairo_scaled_glyph_t *scaled_glyph;
683 : cairo_font_face_t *font_face;
684 : cairo_matrix_t identity;
685 : cairo_font_options_t font_options;
686 : cairo_scaled_font_t *unscaled_font;
687 : cairo_status_t status;
688 : int max_glyphs;
689 : cairo_bool_t type1_font;
690 :
691 : /* Lookup glyph in unscaled subsets */
692 0 : if (subsets->type != CAIRO_SUBSETS_SCALED) {
693 0 : key.is_scaled = FALSE;
694 0 : _cairo_sub_font_init_key (&key, scaled_font);
695 0 : sub_font = _cairo_hash_table_lookup (subsets->unscaled_sub_fonts,
696 : &key.base);
697 0 : if (sub_font != NULL) {
698 0 : status = _cairo_sub_font_lookup_glyph (sub_font,
699 : scaled_font_glyph_index,
700 : utf8, utf8_len,
701 : subset_glyph);
702 0 : if (status != CAIRO_INT_STATUS_UNSUPPORTED)
703 0 : return status;
704 : }
705 : }
706 :
707 : /* Lookup glyph in scaled subsets */
708 0 : key.is_scaled = TRUE;
709 0 : _cairo_sub_font_init_key (&key, scaled_font);
710 0 : sub_font = _cairo_hash_table_lookup (subsets->scaled_sub_fonts,
711 : &key.base);
712 0 : if (sub_font != NULL) {
713 0 : status = _cairo_sub_font_lookup_glyph (sub_font,
714 : scaled_font_glyph_index,
715 : utf8, utf8_len,
716 : subset_glyph);
717 0 : if (status != CAIRO_INT_STATUS_UNSUPPORTED)
718 0 : return status;
719 : }
720 :
721 : /* Glyph not found. Determine whether the glyph is outline or
722 : * bitmap and add to the appropriate subset.
723 : *
724 : * glyph_index 0 (the .notdef glyph) is a special case. Some fonts
725 : * will return CAIRO_INT_STATUS_UNSUPPORTED when doing a
726 : * _scaled_glyph_lookup(_GLYPH_INFO_PATH). Type1-fallback creates
727 : * empty glyphs in this case so we can put the glyph in a unscaled
728 : * subset. */
729 0 : if (scaled_font_glyph_index == 0 ||
730 0 : _cairo_font_face_is_user (scaled_font->font_face)) {
731 0 : status = CAIRO_STATUS_SUCCESS;
732 : } else {
733 0 : _cairo_scaled_font_freeze_cache (scaled_font);
734 0 : status = _cairo_scaled_glyph_lookup (scaled_font,
735 : scaled_font_glyph_index,
736 : CAIRO_SCALED_GLYPH_INFO_PATH,
737 : &scaled_glyph);
738 0 : _cairo_scaled_font_thaw_cache (scaled_font);
739 : }
740 0 : if (_cairo_status_is_error (status))
741 0 : return status;
742 :
743 0 : if (status == CAIRO_STATUS_SUCCESS &&
744 0 : subsets->type != CAIRO_SUBSETS_SCALED &&
745 0 : ! _cairo_font_face_is_user (scaled_font->font_face))
746 : {
747 : /* Path available. Add to unscaled subset. */
748 0 : key.is_scaled = FALSE;
749 0 : _cairo_sub_font_init_key (&key, scaled_font);
750 0 : sub_font = _cairo_hash_table_lookup (subsets->unscaled_sub_fonts,
751 : &key.base);
752 0 : if (sub_font == NULL) {
753 0 : font_face = cairo_scaled_font_get_font_face (scaled_font);
754 0 : cairo_matrix_init_identity (&identity);
755 0 : _cairo_font_options_init_default (&font_options);
756 0 : cairo_font_options_set_hint_style (&font_options, CAIRO_HINT_STYLE_NONE);
757 0 : cairo_font_options_set_hint_metrics (&font_options, CAIRO_HINT_METRICS_OFF);
758 0 : unscaled_font = cairo_scaled_font_create (font_face,
759 : &identity,
760 : &identity,
761 : &font_options);
762 0 : if (unlikely (unscaled_font->status))
763 0 : return unscaled_font->status;
764 :
765 0 : subset_glyph->is_scaled = FALSE;
766 0 : type1_font = FALSE;
767 : #if CAIRO_HAS_FT_FONT
768 0 : type1_font = _cairo_type1_scaled_font_is_type1 (unscaled_font);
769 : #endif
770 0 : if (subsets->type == CAIRO_SUBSETS_COMPOSITE && !type1_font) {
771 0 : max_glyphs = MAX_GLYPHS_PER_COMPOSITE_FONT;
772 0 : subset_glyph->is_composite = TRUE;
773 : } else {
774 0 : max_glyphs = MAX_GLYPHS_PER_SIMPLE_FONT;
775 0 : subset_glyph->is_composite = FALSE;
776 : }
777 :
778 0 : status = _cairo_sub_font_create (subsets,
779 : unscaled_font,
780 0 : subsets->num_sub_fonts,
781 : max_glyphs,
782 : subset_glyph->is_scaled,
783 : subset_glyph->is_composite,
784 : &sub_font);
785 :
786 0 : if (unlikely (status)) {
787 0 : cairo_scaled_font_destroy (unscaled_font);
788 0 : return status;
789 : }
790 :
791 0 : status = _cairo_hash_table_insert (subsets->unscaled_sub_fonts,
792 0 : &sub_font->base);
793 :
794 0 : if (unlikely (status)) {
795 0 : _cairo_sub_font_destroy (sub_font);
796 0 : return status;
797 : }
798 0 : if (!subsets->unscaled_sub_fonts_list)
799 0 : subsets->unscaled_sub_fonts_list = sub_font;
800 : else
801 0 : subsets->unscaled_sub_fonts_list_end->next = sub_font;
802 0 : subsets->unscaled_sub_fonts_list_end = sub_font;
803 0 : subsets->num_sub_fonts++;
804 : }
805 : } else {
806 : /* No path available. Add to scaled subset. */
807 0 : key.is_scaled = TRUE;
808 0 : _cairo_sub_font_init_key (&key, scaled_font);
809 0 : sub_font = _cairo_hash_table_lookup (subsets->scaled_sub_fonts,
810 : &key.base);
811 0 : if (sub_font == NULL) {
812 0 : subset_glyph->is_scaled = TRUE;
813 0 : subset_glyph->is_composite = FALSE;
814 0 : if (subsets->type == CAIRO_SUBSETS_SCALED)
815 0 : max_glyphs = INT_MAX;
816 : else
817 0 : max_glyphs = MAX_GLYPHS_PER_SIMPLE_FONT;
818 :
819 0 : status = _cairo_sub_font_create (subsets,
820 : cairo_scaled_font_reference (scaled_font),
821 0 : subsets->num_sub_fonts,
822 : max_glyphs,
823 : subset_glyph->is_scaled,
824 : subset_glyph->is_composite,
825 : &sub_font);
826 0 : if (unlikely (status)) {
827 0 : cairo_scaled_font_destroy (scaled_font);
828 0 : return status;
829 : }
830 :
831 0 : status = _cairo_hash_table_insert (subsets->scaled_sub_fonts,
832 0 : &sub_font->base);
833 0 : if (unlikely (status)) {
834 0 : _cairo_sub_font_destroy (sub_font);
835 0 : return status;
836 : }
837 0 : if (!subsets->scaled_sub_fonts_list)
838 0 : subsets->scaled_sub_fonts_list = sub_font;
839 : else
840 0 : subsets->scaled_sub_fonts_list_end->next = sub_font;
841 0 : subsets->scaled_sub_fonts_list_end = sub_font;
842 0 : subsets->num_sub_fonts++;
843 : }
844 : }
845 :
846 0 : return _cairo_sub_font_map_glyph (sub_font,
847 : scaled_font_glyph_index,
848 : utf8, utf8_len,
849 : subset_glyph);
850 : }
851 :
852 : static cairo_status_t
853 0 : _cairo_scaled_font_subsets_foreach_internal (cairo_scaled_font_subsets_t *font_subsets,
854 : cairo_scaled_font_subset_callback_func_t font_subset_callback,
855 : void *closure,
856 : cairo_subsets_foreach_type_t type)
857 : {
858 : cairo_sub_font_collection_t collection;
859 : cairo_sub_font_t *sub_font;
860 : cairo_bool_t is_scaled, is_user;
861 :
862 0 : is_scaled = FALSE;
863 0 : is_user = FALSE;
864 :
865 0 : if (type == CAIRO_SUBSETS_FOREACH_USER)
866 0 : is_user = TRUE;
867 :
868 0 : if (type == CAIRO_SUBSETS_FOREACH_SCALED ||
869 : type == CAIRO_SUBSETS_FOREACH_USER)
870 : {
871 0 : is_scaled = TRUE;
872 : }
873 :
874 0 : if (is_scaled)
875 0 : collection.glyphs_size = font_subsets->max_glyphs_per_scaled_subset_used;
876 : else
877 0 : collection.glyphs_size = font_subsets->max_glyphs_per_unscaled_subset_used;
878 :
879 0 : if (! collection.glyphs_size)
880 0 : return CAIRO_STATUS_SUCCESS;
881 :
882 0 : collection.glyphs = _cairo_malloc_ab (collection.glyphs_size, sizeof(unsigned long));
883 0 : collection.utf8 = _cairo_malloc_ab (collection.glyphs_size, sizeof(char *));
884 0 : if (unlikely (collection.glyphs == NULL || collection.utf8 == NULL)) {
885 0 : if (collection.glyphs != NULL)
886 0 : free (collection.glyphs);
887 0 : if (collection.utf8 != NULL)
888 0 : free (collection.utf8);
889 :
890 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
891 : }
892 :
893 0 : collection.font_subset_callback = font_subset_callback;
894 0 : collection.font_subset_callback_closure = closure;
895 0 : collection.status = CAIRO_STATUS_SUCCESS;
896 :
897 0 : if (is_scaled)
898 0 : sub_font = font_subsets->scaled_sub_fonts_list;
899 : else
900 0 : sub_font = font_subsets->unscaled_sub_fonts_list;
901 :
902 0 : while (sub_font) {
903 0 : if (sub_font->is_user == is_user)
904 0 : _cairo_sub_font_collect (sub_font, &collection);
905 :
906 0 : sub_font = sub_font->next;
907 : }
908 0 : free (collection.utf8);
909 0 : free (collection.glyphs);
910 :
911 0 : return collection.status;
912 : }
913 :
914 : cairo_status_t
915 0 : _cairo_scaled_font_subsets_foreach_scaled (cairo_scaled_font_subsets_t *font_subsets,
916 : cairo_scaled_font_subset_callback_func_t font_subset_callback,
917 : void *closure)
918 : {
919 0 : return _cairo_scaled_font_subsets_foreach_internal (font_subsets,
920 : font_subset_callback,
921 : closure,
922 : CAIRO_SUBSETS_FOREACH_SCALED);
923 : }
924 :
925 : cairo_status_t
926 0 : _cairo_scaled_font_subsets_foreach_unscaled (cairo_scaled_font_subsets_t *font_subsets,
927 : cairo_scaled_font_subset_callback_func_t font_subset_callback,
928 : void *closure)
929 : {
930 0 : return _cairo_scaled_font_subsets_foreach_internal (font_subsets,
931 : font_subset_callback,
932 : closure,
933 : CAIRO_SUBSETS_FOREACH_UNSCALED);
934 : }
935 :
936 : cairo_status_t
937 0 : _cairo_scaled_font_subsets_foreach_user (cairo_scaled_font_subsets_t *font_subsets,
938 : cairo_scaled_font_subset_callback_func_t font_subset_callback,
939 : void *closure)
940 : {
941 0 : return _cairo_scaled_font_subsets_foreach_internal (font_subsets,
942 : font_subset_callback,
943 : closure,
944 : CAIRO_SUBSETS_FOREACH_USER);
945 : }
946 :
947 : static cairo_bool_t
948 0 : _cairo_string_equal (const void *key_a, const void *key_b)
949 : {
950 0 : const cairo_string_entry_t *a = key_a;
951 0 : const cairo_string_entry_t *b = key_b;
952 :
953 0 : if (strcmp (a->string, b->string) == 0)
954 0 : return TRUE;
955 : else
956 0 : return FALSE;
957 : }
958 :
959 : static void
960 0 : _cairo_string_init_key (cairo_string_entry_t *key, char *s)
961 : {
962 0 : unsigned long sum = 0;
963 : unsigned int i;
964 :
965 0 : for (i = 0; i < strlen(s); i++)
966 0 : sum += s[i];
967 0 : key->base.hash = sum;
968 0 : key->string = s;
969 0 : }
970 :
971 : static cairo_status_t
972 0 : create_string_entry (char *s, cairo_string_entry_t **entry)
973 : {
974 0 : *entry = malloc (sizeof (cairo_string_entry_t));
975 0 : if (unlikely (*entry == NULL))
976 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
977 :
978 0 : _cairo_string_init_key (*entry, s);
979 :
980 0 : return CAIRO_STATUS_SUCCESS;
981 : }
982 :
983 : static void
984 0 : _pluck_entry (void *entry, void *closure)
985 : {
986 0 : _cairo_hash_table_remove (closure, entry);
987 0 : free (entry);
988 0 : }
989 :
990 : cairo_int_status_t
991 0 : _cairo_scaled_font_subset_create_glyph_names (cairo_scaled_font_subset_t *subset)
992 : {
993 : unsigned int i;
994 : cairo_hash_table_t *names;
995 : cairo_string_entry_t key, *entry;
996 : char buf[30];
997 : char *utf8;
998 : uint16_t *utf16;
999 : int utf16_len;
1000 0 : cairo_status_t status = CAIRO_STATUS_SUCCESS;
1001 :
1002 0 : names = _cairo_hash_table_create (_cairo_string_equal);
1003 0 : if (unlikely (names == NULL))
1004 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1005 :
1006 0 : subset->glyph_names = calloc (subset->num_glyphs, sizeof (char *));
1007 0 : if (unlikely (subset->glyph_names == NULL)) {
1008 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1009 0 : goto CLEANUP_HASH;
1010 : }
1011 :
1012 0 : i = 0;
1013 0 : if (! subset->is_scaled) {
1014 0 : subset->glyph_names[0] = strdup (".notdef");
1015 0 : if (unlikely (subset->glyph_names[0] == NULL)) {
1016 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1017 0 : goto CLEANUP_HASH;
1018 : }
1019 :
1020 0 : status = create_string_entry (subset->glyph_names[0], &entry);
1021 0 : if (unlikely (status))
1022 0 : goto CLEANUP_HASH;
1023 :
1024 0 : status = _cairo_hash_table_insert (names, &entry->base);
1025 0 : if (unlikely (status)) {
1026 0 : free (entry);
1027 0 : goto CLEANUP_HASH;
1028 : }
1029 0 : i++;
1030 : }
1031 :
1032 0 : for (; i < subset->num_glyphs; i++) {
1033 0 : utf8 = subset->utf8[i];
1034 0 : utf16 = NULL;
1035 0 : utf16_len = 0;
1036 0 : if (utf8 && *utf8) {
1037 0 : status = _cairo_utf8_to_utf16 (utf8, -1, &utf16, &utf16_len);
1038 0 : if (unlikely (status))
1039 0 : goto CLEANUP_HASH;
1040 : }
1041 :
1042 0 : if (utf16_len == 1) {
1043 0 : snprintf (buf, sizeof (buf), "uni%04X", (int) utf16[0]);
1044 0 : _cairo_string_init_key (&key, buf);
1045 0 : entry = _cairo_hash_table_lookup (names, &key.base);
1046 0 : if (entry != NULL)
1047 0 : snprintf (buf, sizeof (buf), "g%d", i);
1048 : } else {
1049 0 : snprintf (buf, sizeof (buf), "g%d", i);
1050 : }
1051 0 : if (utf16)
1052 0 : free (utf16);
1053 :
1054 0 : subset->glyph_names[i] = strdup (buf);
1055 0 : if (unlikely (subset->glyph_names[i] == NULL)) {
1056 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1057 0 : goto CLEANUP_HASH;
1058 : }
1059 :
1060 0 : status = create_string_entry (subset->glyph_names[i], &entry);
1061 0 : if (unlikely (status))
1062 0 : goto CLEANUP_HASH;
1063 :
1064 0 : status = _cairo_hash_table_insert (names, &entry->base);
1065 0 : if (unlikely (status)) {
1066 0 : free (entry);
1067 0 : goto CLEANUP_HASH;
1068 : }
1069 : }
1070 :
1071 : CLEANUP_HASH:
1072 0 : _cairo_hash_table_foreach (names, _pluck_entry, names);
1073 0 : _cairo_hash_table_destroy (names);
1074 :
1075 0 : if (likely (status == CAIRO_STATUS_SUCCESS))
1076 0 : return CAIRO_STATUS_SUCCESS;
1077 :
1078 0 : if (subset->glyph_names != NULL) {
1079 0 : for (i = 0; i < subset->num_glyphs; i++) {
1080 0 : if (subset->glyph_names[i] != NULL)
1081 0 : free (subset->glyph_names[i]);
1082 : }
1083 :
1084 0 : free (subset->glyph_names);
1085 0 : subset->glyph_names = NULL;
1086 : }
1087 :
1088 0 : return status;
1089 : }
1090 :
1091 : #endif /* CAIRO_HAS_FONT_SUBSET */
|