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