Updated: Sudoku no longer crashes
[moon.git] / cairo / src / cairo-scaled-font-subsets.c
blob066f63781a7c5f1fa49fae7dbb460503f20fbab2
1 /* cairo - a vector graphics library with display and print output
3 * Copyright © 2003 University of Southern California
4 * Copyright © 2005 Red Hat, Inc
5 * Copyright © 2006 Keith Packard
6 * Copyright © 2006 Red Hat, Inc
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 * You should have received a copy of the MPL along with this library
20 * in the file COPYING-MPL-1.1
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/
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.
31 * The Original Code is the cairo graphics library.
33 * The Initial Developer of the Original Code is University of Southern
34 * California.
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>
43 #define _BSD_SOURCE /* for snprintf(), strdup() */
44 #include "cairoint.h"
46 #if CAIRO_HAS_FONT_SUBSET
48 #include "cairo-scaled-font-subsets-private.h"
49 #include "cairo-user-font-private.h"
51 #define MAX_GLYPHS_PER_SIMPLE_FONT 256
52 #define MAX_GLYPHS_PER_COMPOSITE_FONT 65536
54 typedef enum {
55 CAIRO_SUBSETS_SCALED,
56 CAIRO_SUBSETS_SIMPLE,
57 CAIRO_SUBSETS_COMPOSITE
58 } cairo_subsets_type_t;
60 typedef enum {
61 CAIRO_SUBSETS_FOREACH_UNSCALED,
62 CAIRO_SUBSETS_FOREACH_SCALED,
63 CAIRO_SUBSETS_FOREACH_USER
64 } cairo_subsets_foreach_type_t;
66 typedef struct _cairo_sub_font {
67 cairo_hash_entry_t base;
69 cairo_bool_t is_scaled;
70 cairo_bool_t is_composite;
71 cairo_bool_t is_user;
72 cairo_scaled_font_subsets_t *parent;
73 cairo_scaled_font_t *scaled_font;
74 unsigned int font_id;
76 int current_subset;
77 int num_glyphs_in_current_subset;
78 int max_glyphs_per_subset;
80 cairo_hash_table_t *sub_font_glyphs;
81 struct _cairo_sub_font *next;
82 } cairo_sub_font_t;
84 struct _cairo_scaled_font_subsets {
85 cairo_subsets_type_t type;
87 int max_glyphs_per_unscaled_subset_used;
88 cairo_hash_table_t *unscaled_sub_fonts;
89 cairo_sub_font_t *unscaled_sub_fonts_list;
90 cairo_sub_font_t *unscaled_sub_fonts_list_end;
92 int max_glyphs_per_scaled_subset_used;
93 cairo_hash_table_t *scaled_sub_fonts;
94 cairo_sub_font_t *scaled_sub_fonts_list;
95 cairo_sub_font_t *scaled_sub_fonts_list_end;
97 int num_sub_fonts;
100 typedef struct _cairo_sub_font_glyph {
101 cairo_hash_entry_t base;
103 unsigned int subset_id;
104 unsigned int subset_glyph_index;
105 double x_advance;
106 double y_advance;
108 cairo_bool_t is_mapped;
109 uint32_t unicode;
110 char *utf8;
111 int utf8_len;
112 } cairo_sub_font_glyph_t;
114 typedef struct _cairo_sub_font_collection {
115 unsigned long *glyphs; /* scaled_font_glyph_index */
116 char **utf8;
117 unsigned int glyphs_size;
118 unsigned int max_glyph;
119 unsigned int num_glyphs;
121 unsigned int subset_id;
123 cairo_status_t status;
124 cairo_scaled_font_subset_callback_func_t font_subset_callback;
125 void *font_subset_callback_closure;
126 } cairo_sub_font_collection_t;
128 typedef struct _cairo_string_entry {
129 cairo_hash_entry_t base;
130 char *string;
131 } cairo_string_entry_t;
133 static cairo_status_t
134 _cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font,
135 unsigned long scaled_font_glyph_index,
136 const char * utf8,
137 int utf8_len,
138 cairo_scaled_font_subsets_glyph_t *subset_glyph);
140 static void
141 _cairo_sub_font_glyph_init_key (cairo_sub_font_glyph_t *sub_font_glyph,
142 unsigned long scaled_font_glyph_index)
144 sub_font_glyph->base.hash = scaled_font_glyph_index;
147 static cairo_bool_t
148 _cairo_sub_font_glyphs_equal (const void *key_a, const void *key_b)
150 const cairo_sub_font_glyph_t *sub_font_glyph_a = key_a;
151 const cairo_sub_font_glyph_t *sub_font_glyph_b = key_b;
153 return sub_font_glyph_a->base.hash == sub_font_glyph_b->base.hash;
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)
163 cairo_sub_font_glyph_t *sub_font_glyph;
165 sub_font_glyph = malloc (sizeof (cairo_sub_font_glyph_t));
166 if (sub_font_glyph == NULL) {
167 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
168 return NULL;
171 _cairo_sub_font_glyph_init_key (sub_font_glyph, scaled_font_glyph_index);
172 sub_font_glyph->subset_id = subset_id;
173 sub_font_glyph->subset_glyph_index = subset_glyph_index;
174 sub_font_glyph->x_advance = x_advance;
175 sub_font_glyph->y_advance = y_advance;
176 sub_font_glyph->is_mapped = FALSE;
177 sub_font_glyph->unicode = -1;
178 sub_font_glyph->utf8 = NULL;
179 sub_font_glyph->utf8_len = 0;
181 return sub_font_glyph;
184 static void
185 _cairo_sub_font_glyph_destroy (cairo_sub_font_glyph_t *sub_font_glyph)
187 if (sub_font_glyph->utf8 != NULL)
188 free (sub_font_glyph->utf8);
190 free (sub_font_glyph);
193 static void
194 _cairo_sub_font_glyph_pluck (void *entry, void *closure)
196 cairo_sub_font_glyph_t *sub_font_glyph = entry;
197 cairo_hash_table_t *sub_font_glyphs = closure;
199 _cairo_hash_table_remove (sub_font_glyphs, &sub_font_glyph->base);
200 _cairo_sub_font_glyph_destroy (sub_font_glyph);
203 static void
204 _cairo_sub_font_glyph_collect (void *entry, void *closure)
206 cairo_sub_font_glyph_t *sub_font_glyph = entry;
207 cairo_sub_font_collection_t *collection = closure;
208 unsigned long scaled_font_glyph_index;
209 unsigned int subset_glyph_index;
211 if (sub_font_glyph->subset_id != collection->subset_id)
212 return;
214 scaled_font_glyph_index = sub_font_glyph->base.hash;
215 subset_glyph_index = sub_font_glyph->subset_glyph_index;
217 /* Ensure we don't exceed the allocated bounds. */
218 assert (subset_glyph_index < collection->glyphs_size);
220 collection->glyphs[subset_glyph_index] = scaled_font_glyph_index;
221 collection->utf8[subset_glyph_index] = sub_font_glyph->utf8;
222 if (subset_glyph_index > collection->max_glyph)
223 collection->max_glyph = subset_glyph_index;
225 collection->num_glyphs++;
228 static cairo_bool_t
229 _cairo_sub_fonts_equal (const void *key_a, const void *key_b)
231 const cairo_sub_font_t *sub_font_a = key_a;
232 const cairo_sub_font_t *sub_font_b = key_b;
234 if (sub_font_a->is_scaled)
235 return sub_font_a->scaled_font == sub_font_b->scaled_font;
236 else
237 return sub_font_a->scaled_font->font_face == sub_font_b->scaled_font->font_face;
240 static void
241 _cairo_sub_font_init_key (cairo_sub_font_t *sub_font,
242 cairo_scaled_font_t *scaled_font)
244 if (sub_font->is_scaled)
246 sub_font->base.hash = (unsigned long) scaled_font;
247 sub_font->scaled_font = scaled_font;
249 else
251 sub_font->base.hash = (unsigned long) scaled_font->font_face;
252 sub_font->scaled_font = scaled_font;
256 static cairo_status_t
257 _cairo_sub_font_create (cairo_scaled_font_subsets_t *parent,
258 cairo_scaled_font_t *scaled_font,
259 unsigned int font_id,
260 int max_glyphs_per_subset,
261 cairo_bool_t is_scaled,
262 cairo_bool_t is_composite,
263 cairo_sub_font_t **sub_font_out)
265 cairo_sub_font_t *sub_font;
266 cairo_status_t status;
267 cairo_scaled_font_subsets_glyph_t subset_glyph;
269 sub_font = malloc (sizeof (cairo_sub_font_t));
270 if (sub_font == NULL)
271 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
273 sub_font->is_scaled = is_scaled;
274 sub_font->is_composite = is_composite;
275 sub_font->is_user = _cairo_font_face_is_user (scaled_font->font_face);
276 _cairo_sub_font_init_key (sub_font, scaled_font);
278 sub_font->parent = parent;
279 sub_font->scaled_font = scaled_font;
280 sub_font->font_id = font_id;
282 sub_font->current_subset = 0;
283 sub_font->num_glyphs_in_current_subset = 0;
284 sub_font->max_glyphs_per_subset = max_glyphs_per_subset;
286 sub_font->sub_font_glyphs = _cairo_hash_table_create (_cairo_sub_font_glyphs_equal);
287 if (sub_font->sub_font_glyphs == NULL) {
288 free (sub_font);
289 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
291 sub_font->next = NULL;
293 /* Reserve first glyph in subset for the .notdef glyph except for
294 * Type 3 fonts */
295 if (! _cairo_font_face_is_user (scaled_font->font_face)) {
296 status = _cairo_sub_font_map_glyph (sub_font, 0, NULL, -1, &subset_glyph);
297 if (status) {
298 _cairo_hash_table_destroy (sub_font->sub_font_glyphs);
299 free (sub_font);
300 return status;
304 *sub_font_out = sub_font;
305 return CAIRO_STATUS_SUCCESS;
308 static void
309 _cairo_sub_font_destroy (cairo_sub_font_t *sub_font)
311 _cairo_hash_table_foreach (sub_font->sub_font_glyphs,
312 _cairo_sub_font_glyph_pluck,
313 sub_font->sub_font_glyphs);
314 _cairo_hash_table_destroy (sub_font->sub_font_glyphs);
315 cairo_scaled_font_destroy (sub_font->scaled_font);
316 free (sub_font);
319 static void
320 _cairo_sub_font_pluck (void *entry, void *closure)
322 cairo_sub_font_t *sub_font = entry;
323 cairo_hash_table_t *sub_fonts = closure;
325 _cairo_hash_table_remove (sub_fonts, &sub_font->base);
326 _cairo_sub_font_destroy (sub_font);
329 static cairo_status_t
330 _cairo_sub_font_glyph_lookup_unicode (cairo_sub_font_glyph_t *sub_font_glyph,
331 cairo_scaled_font_t *scaled_font,
332 unsigned long scaled_font_glyph_index)
334 uint32_t unicode;
335 char buf[8];
336 int len;
337 cairo_status_t status;
339 /* Do a reverse lookup on the glyph index. unicode is -1 if the
340 * index could not be mapped to a unicode character. */
341 unicode = -1;
342 status = _cairo_truetype_index_to_ucs4 (scaled_font,
343 scaled_font_glyph_index,
344 &unicode);
345 if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
346 return status;
348 if (unicode == (uint32_t)-1 && scaled_font->backend->index_to_ucs4) {
349 status = scaled_font->backend->index_to_ucs4 (scaled_font,
350 scaled_font_glyph_index,
351 &unicode);
352 if (status)
353 return status;
356 sub_font_glyph->unicode = unicode;
357 sub_font_glyph->utf8 = NULL;
358 sub_font_glyph->utf8_len = 0;
359 if (unicode != (uint32_t) -1) {
360 len = _cairo_ucs4_to_utf8 (unicode, buf);
361 if (len > 0) {
362 sub_font_glyph->utf8 = malloc (len + 1);
363 if (sub_font_glyph->utf8 == NULL)
364 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
366 memcpy (sub_font_glyph->utf8, buf, len);
367 sub_font_glyph->utf8[len] = 0;
368 sub_font_glyph->utf8_len = len;
372 return CAIRO_STATUS_SUCCESS;
375 static cairo_bool_t
376 _cairo_sub_font_glyph_map_to_unicode (cairo_sub_font_glyph_t *sub_font_glyph,
377 const char *utf8,
378 int utf8_len)
380 if (utf8_len < 0)
381 return FALSE;
383 if (utf8 != NULL && utf8_len != 0 && utf8[utf8_len - 1] == '\0')
384 utf8_len--;
386 if (utf8 != NULL && utf8_len != 0) {
387 if (sub_font_glyph->utf8 != NULL) {
388 if (utf8_len == sub_font_glyph->utf8_len &&
389 memcmp (utf8, sub_font_glyph->utf8, utf8_len) == 0)
391 /* Requested utf8 mapping matches the existing mapping */
392 return TRUE;
394 else
396 /* Requested utf8 mapping does not match the existing mapping */
397 return FALSE;
399 } else {
400 /* No existing mapping. Use the requested mapping */
401 sub_font_glyph->utf8 = malloc (utf8_len + 1);
402 memcpy (sub_font_glyph->utf8, utf8, utf8_len);
403 sub_font_glyph->utf8[utf8_len] = 0;
404 sub_font_glyph->utf8_len = utf8_len;
405 return TRUE;
409 /* No mapping was requested. */
410 return FALSE;
413 static cairo_bool_t
414 _cairo_sub_font_lookup_glyph (cairo_sub_font_t *sub_font,
415 unsigned long scaled_font_glyph_index,
416 const char *utf8,
417 int utf8_len,
418 cairo_scaled_font_subsets_glyph_t *subset_glyph)
420 cairo_sub_font_glyph_t key, *sub_font_glyph;
422 _cairo_sub_font_glyph_init_key (&key, scaled_font_glyph_index);
423 if (_cairo_hash_table_lookup (sub_font->sub_font_glyphs, &key.base,
424 (cairo_hash_entry_t **) &sub_font_glyph))
426 subset_glyph->font_id = sub_font->font_id;
427 subset_glyph->subset_id = sub_font_glyph->subset_id;
428 subset_glyph->subset_glyph_index = sub_font_glyph->subset_glyph_index;
429 subset_glyph->is_scaled = sub_font->is_scaled;
430 subset_glyph->is_composite = sub_font->is_composite;
431 subset_glyph->x_advance = sub_font_glyph->x_advance;
432 subset_glyph->y_advance = sub_font_glyph->y_advance;
433 subset_glyph->utf8_is_mapped = _cairo_sub_font_glyph_map_to_unicode (sub_font_glyph, utf8, utf8_len);
434 subset_glyph->unicode = sub_font_glyph->unicode;
436 return TRUE;
439 return FALSE;
442 static cairo_status_t
443 _cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font,
444 unsigned long scaled_font_glyph_index,
445 const char *utf8,
446 int utf8_len,
447 cairo_scaled_font_subsets_glyph_t *subset_glyph)
449 cairo_sub_font_glyph_t key, *sub_font_glyph;
450 cairo_status_t status;
452 _cairo_sub_font_glyph_init_key (&key, scaled_font_glyph_index);
453 if (! _cairo_hash_table_lookup (sub_font->sub_font_glyphs, &key.base,
454 (cairo_hash_entry_t **) &sub_font_glyph))
456 cairo_scaled_glyph_t *scaled_glyph;
458 if (sub_font->num_glyphs_in_current_subset == sub_font->max_glyphs_per_subset)
460 cairo_scaled_font_subsets_glyph_t tmp_subset_glyph;
462 sub_font->current_subset++;
463 sub_font->num_glyphs_in_current_subset = 0;
465 /* Reserve first glyph in subset for the .notdef glyph
466 * except for Type 3 fonts */
467 if (! _cairo_font_face_is_user (sub_font->scaled_font->font_face)) {
468 status = _cairo_sub_font_map_glyph (sub_font, 0, NULL, -1, &tmp_subset_glyph);
469 if (status)
470 return status;
474 _cairo_scaled_font_freeze_cache (sub_font->scaled_font);
475 status = _cairo_scaled_glyph_lookup (sub_font->scaled_font,
476 scaled_font_glyph_index,
477 CAIRO_SCALED_GLYPH_INFO_METRICS,
478 &scaled_glyph);
479 assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
480 if (status) {
481 _cairo_scaled_font_thaw_cache (sub_font->scaled_font);
482 return status;
485 sub_font_glyph = _cairo_sub_font_glyph_create (scaled_font_glyph_index,
486 sub_font->current_subset,
487 sub_font->num_glyphs_in_current_subset,
488 scaled_glyph->metrics.x_advance,
489 scaled_glyph->metrics.y_advance);
490 _cairo_scaled_font_thaw_cache (sub_font->scaled_font);
492 if (sub_font_glyph == NULL)
493 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
495 status = _cairo_sub_font_glyph_lookup_unicode (sub_font_glyph,
496 sub_font->scaled_font,
497 scaled_font_glyph_index);
498 if (status) {
499 _cairo_sub_font_glyph_destroy (sub_font_glyph);
500 return status;
503 status = _cairo_hash_table_insert (sub_font->sub_font_glyphs, &sub_font_glyph->base);
504 if (status) {
505 _cairo_sub_font_glyph_destroy (sub_font_glyph);
506 return status;
509 sub_font->num_glyphs_in_current_subset++;
511 if (sub_font->is_scaled) {
512 if (sub_font->num_glyphs_in_current_subset > sub_font->parent->max_glyphs_per_scaled_subset_used)
513 sub_font->parent->max_glyphs_per_scaled_subset_used = sub_font->num_glyphs_in_current_subset;
514 } else {
515 if (sub_font->num_glyphs_in_current_subset > sub_font->parent->max_glyphs_per_unscaled_subset_used)
516 sub_font->parent->max_glyphs_per_unscaled_subset_used = sub_font->num_glyphs_in_current_subset;
520 subset_glyph->font_id = sub_font->font_id;
521 subset_glyph->subset_id = sub_font_glyph->subset_id;
522 subset_glyph->subset_glyph_index = sub_font_glyph->subset_glyph_index;
523 subset_glyph->is_scaled = sub_font->is_scaled;
524 subset_glyph->is_composite = sub_font->is_composite;
525 subset_glyph->x_advance = sub_font_glyph->x_advance;
526 subset_glyph->y_advance = sub_font_glyph->y_advance;
527 subset_glyph->utf8_is_mapped = _cairo_sub_font_glyph_map_to_unicode (sub_font_glyph, utf8, utf8_len);
528 subset_glyph->unicode = sub_font_glyph->unicode;
530 return CAIRO_STATUS_SUCCESS;
533 static void
534 _cairo_sub_font_collect (void *entry, void *closure)
536 cairo_sub_font_t *sub_font = entry;
537 cairo_sub_font_collection_t *collection = closure;
538 cairo_scaled_font_subset_t subset;
539 int i;
540 unsigned int j;
542 if (collection->status)
543 return;
545 for (i = 0; i <= sub_font->current_subset; i++) {
546 collection->subset_id = i;
547 collection->num_glyphs = 0;
548 collection->max_glyph = 0;
550 _cairo_hash_table_foreach (sub_font->sub_font_glyphs,
551 _cairo_sub_font_glyph_collect, collection);
552 if (collection->status)
553 break;
554 if (collection->num_glyphs == 0)
555 continue;
557 /* Ensure the resulting array has no uninitialized holes */
558 assert (collection->num_glyphs == collection->max_glyph + 1);
560 subset.scaled_font = sub_font->scaled_font;
561 subset.is_composite = sub_font->is_composite;
562 subset.font_id = sub_font->font_id;
563 subset.subset_id = i;
564 subset.glyphs = collection->glyphs;
565 subset.utf8 = collection->utf8;
566 subset.num_glyphs = collection->num_glyphs;
567 subset.glyph_names = NULL;
568 /* No need to check for out of memory here. If to_unicode is NULL, the PDF
569 * surface does not emit an ToUnicode stream */
570 subset.to_unicode = _cairo_malloc_ab (collection->num_glyphs, sizeof (unsigned long));
571 if (subset.to_unicode) {
572 for (j = 0; j < collection->num_glyphs; j++) {
573 /* default unicode character required when mapping fails */
574 subset.to_unicode[j] = 0xfffd;
577 collection->status = (collection->font_subset_callback) (&subset,
578 collection->font_subset_callback_closure);
580 if (subset.to_unicode != NULL)
581 free (subset.to_unicode);
583 if (subset.glyph_names != NULL) {
584 for (j = 0; j < collection->num_glyphs; j++)
585 free (subset.glyph_names[j]);
586 free (subset.glyph_names);
589 if (collection->status)
590 break;
594 static cairo_scaled_font_subsets_t *
595 _cairo_scaled_font_subsets_create_internal (cairo_subsets_type_t type)
597 cairo_scaled_font_subsets_t *subsets;
599 subsets = malloc (sizeof (cairo_scaled_font_subsets_t));
600 if (subsets == NULL) {
601 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
602 return NULL;
605 subsets->type = type;
606 subsets->max_glyphs_per_unscaled_subset_used = 0;
607 subsets->max_glyphs_per_scaled_subset_used = 0;
608 subsets->num_sub_fonts = 0;
610 subsets->unscaled_sub_fonts = _cairo_hash_table_create (_cairo_sub_fonts_equal);
611 if (! subsets->unscaled_sub_fonts) {
612 free (subsets);
613 return NULL;
615 subsets->unscaled_sub_fonts_list = NULL;
616 subsets->unscaled_sub_fonts_list_end = NULL;
618 subsets->scaled_sub_fonts = _cairo_hash_table_create (_cairo_sub_fonts_equal);
619 if (! subsets->scaled_sub_fonts) {
620 _cairo_hash_table_destroy (subsets->unscaled_sub_fonts);
621 free (subsets);
622 return NULL;
624 subsets->scaled_sub_fonts_list = NULL;
625 subsets->scaled_sub_fonts_list_end = NULL;
627 return subsets;
630 cairo_scaled_font_subsets_t *
631 _cairo_scaled_font_subsets_create_scaled (void)
633 return _cairo_scaled_font_subsets_create_internal (CAIRO_SUBSETS_SCALED);
636 cairo_scaled_font_subsets_t *
637 _cairo_scaled_font_subsets_create_simple (void)
639 return _cairo_scaled_font_subsets_create_internal (CAIRO_SUBSETS_SIMPLE);
642 cairo_scaled_font_subsets_t *
643 _cairo_scaled_font_subsets_create_composite (void)
645 return _cairo_scaled_font_subsets_create_internal (CAIRO_SUBSETS_COMPOSITE);
648 void
649 _cairo_scaled_font_subsets_destroy (cairo_scaled_font_subsets_t *subsets)
651 _cairo_hash_table_foreach (subsets->scaled_sub_fonts, _cairo_sub_font_pluck, subsets->scaled_sub_fonts);
652 _cairo_hash_table_destroy (subsets->scaled_sub_fonts);
654 _cairo_hash_table_foreach (subsets->unscaled_sub_fonts, _cairo_sub_font_pluck, subsets->unscaled_sub_fonts);
655 _cairo_hash_table_destroy (subsets->unscaled_sub_fonts);
657 free (subsets);
660 cairo_status_t
661 _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets,
662 cairo_scaled_font_t *scaled_font,
663 unsigned long scaled_font_glyph_index,
664 const char * utf8,
665 int utf8_len,
666 cairo_scaled_font_subsets_glyph_t *subset_glyph)
668 cairo_sub_font_t key, *sub_font;
669 cairo_scaled_glyph_t *scaled_glyph;
670 cairo_font_face_t *font_face;
671 cairo_matrix_t identity;
672 cairo_font_options_t font_options;
673 cairo_scaled_font_t *unscaled_font;
674 cairo_status_t status;
675 int max_glyphs;
676 cairo_bool_t type1_font;
678 /* Lookup glyph in unscaled subsets */
679 if (subsets->type != CAIRO_SUBSETS_SCALED) {
680 key.is_scaled = FALSE;
681 _cairo_sub_font_init_key (&key, scaled_font);
682 if (_cairo_hash_table_lookup (subsets->unscaled_sub_fonts, &key.base,
683 (cairo_hash_entry_t **) &sub_font))
685 if (_cairo_sub_font_lookup_glyph (sub_font,
686 scaled_font_glyph_index,
687 utf8, utf8_len,
688 subset_glyph))
689 return CAIRO_STATUS_SUCCESS;
693 /* Lookup glyph in scaled subsets */
694 key.is_scaled = TRUE;
695 _cairo_sub_font_init_key (&key, scaled_font);
696 if (_cairo_hash_table_lookup (subsets->scaled_sub_fonts, &key.base,
697 (cairo_hash_entry_t **) &sub_font))
699 if (_cairo_sub_font_lookup_glyph (sub_font,
700 scaled_font_glyph_index,
701 utf8, utf8_len,
702 subset_glyph))
703 return CAIRO_STATUS_SUCCESS;
706 /* Glyph not found. Determine whether the glyph is outline or
707 * bitmap and add to the appropriate subset.
709 * glyph_index 0 (the .notdef glyph) is a special case. Some fonts
710 * will return CAIRO_INT_STATUS_UNSUPPORTED when doing a
711 * _scaled_glyph_lookup(_GLYPH_INFO_PATH). Type1-fallback creates
712 * empty glyphs in this case so we can put the glyph in a unscaled
713 * subset. */
714 if (scaled_font_glyph_index == 0 ||
715 _cairo_font_face_is_user (scaled_font->font_face)) {
716 status = CAIRO_STATUS_SUCCESS;
717 } else {
718 _cairo_scaled_font_freeze_cache (scaled_font);
719 status = _cairo_scaled_glyph_lookup (scaled_font,
720 scaled_font_glyph_index,
721 CAIRO_SCALED_GLYPH_INFO_PATH,
722 &scaled_glyph);
723 _cairo_scaled_font_thaw_cache (scaled_font);
725 if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
726 return status;
728 if (status == CAIRO_STATUS_SUCCESS &&
729 subsets->type != CAIRO_SUBSETS_SCALED &&
730 ! _cairo_font_face_is_user (scaled_font->font_face))
732 /* Path available. Add to unscaled subset. */
733 key.is_scaled = FALSE;
734 _cairo_sub_font_init_key (&key, scaled_font);
735 if (! _cairo_hash_table_lookup (subsets->unscaled_sub_fonts, &key.base,
736 (cairo_hash_entry_t **) &sub_font))
738 font_face = cairo_scaled_font_get_font_face (scaled_font);
739 cairo_matrix_init_identity (&identity);
740 _cairo_font_options_init_default (&font_options);
741 cairo_font_options_set_hint_style (&font_options, CAIRO_HINT_STYLE_NONE);
742 cairo_font_options_set_hint_metrics (&font_options, CAIRO_HINT_METRICS_OFF);
743 unscaled_font = cairo_scaled_font_create (font_face,
744 &identity,
745 &identity,
746 &font_options);
747 if (unscaled_font->status)
748 return unscaled_font->status;
750 subset_glyph->is_scaled = FALSE;
751 type1_font = FALSE;
752 #if CAIRO_HAS_FT_FONT
753 type1_font = _cairo_type1_scaled_font_is_type1 (unscaled_font);
754 #endif
755 if (subsets->type == CAIRO_SUBSETS_COMPOSITE && !type1_font) {
756 max_glyphs = MAX_GLYPHS_PER_COMPOSITE_FONT;
757 subset_glyph->is_composite = TRUE;
758 } else {
759 max_glyphs = MAX_GLYPHS_PER_SIMPLE_FONT;
760 subset_glyph->is_composite = FALSE;
763 status = _cairo_sub_font_create (subsets,
764 unscaled_font,
765 subsets->num_sub_fonts,
766 max_glyphs,
767 subset_glyph->is_scaled,
768 subset_glyph->is_composite,
769 &sub_font);
771 if (status) {
772 cairo_scaled_font_destroy (unscaled_font);
773 return status;
776 status = _cairo_hash_table_insert (subsets->unscaled_sub_fonts,
777 &sub_font->base);
779 if (status) {
780 _cairo_sub_font_destroy (sub_font);
781 return status;
783 if (!subsets->unscaled_sub_fonts_list)
784 subsets->unscaled_sub_fonts_list = sub_font;
785 else
786 subsets->unscaled_sub_fonts_list_end->next = sub_font;
787 subsets->unscaled_sub_fonts_list_end = sub_font;
788 subsets->num_sub_fonts++;
790 } else {
791 /* No path available. Add to scaled subset. */
792 key.is_scaled = TRUE;
793 _cairo_sub_font_init_key (&key, scaled_font);
794 if (! _cairo_hash_table_lookup (subsets->scaled_sub_fonts, &key.base,
795 (cairo_hash_entry_t **) &sub_font))
797 subset_glyph->is_scaled = TRUE;
798 subset_glyph->is_composite = FALSE;
799 if (subsets->type == CAIRO_SUBSETS_SCALED)
800 max_glyphs = INT_MAX;
801 else
802 max_glyphs = MAX_GLYPHS_PER_SIMPLE_FONT;
804 status = _cairo_sub_font_create (subsets,
805 cairo_scaled_font_reference (scaled_font),
806 subsets->num_sub_fonts,
807 max_glyphs,
808 subset_glyph->is_scaled,
809 subset_glyph->is_composite,
810 &sub_font);
811 if (status) {
812 cairo_scaled_font_destroy (scaled_font);
813 return status;
816 status = _cairo_hash_table_insert (subsets->scaled_sub_fonts,
817 &sub_font->base);
818 if (status) {
819 _cairo_sub_font_destroy (sub_font);
820 return status;
822 if (!subsets->scaled_sub_fonts_list)
823 subsets->scaled_sub_fonts_list = sub_font;
824 else
825 subsets->scaled_sub_fonts_list_end->next = sub_font;
826 subsets->scaled_sub_fonts_list_end = sub_font;
827 subsets->num_sub_fonts++;
831 return _cairo_sub_font_map_glyph (sub_font,
832 scaled_font_glyph_index,
833 utf8, utf8_len,
834 subset_glyph);
837 static cairo_status_t
838 _cairo_scaled_font_subsets_foreach_internal (cairo_scaled_font_subsets_t *font_subsets,
839 cairo_scaled_font_subset_callback_func_t font_subset_callback,
840 void *closure,
841 cairo_subsets_foreach_type_t type)
843 cairo_sub_font_collection_t collection;
844 cairo_sub_font_t *sub_font;
845 cairo_bool_t is_scaled, is_user;
847 is_scaled = FALSE;
848 is_user = FALSE;
850 if (type == CAIRO_SUBSETS_FOREACH_USER)
851 is_user = TRUE;
853 if (type == CAIRO_SUBSETS_FOREACH_SCALED ||
854 type == CAIRO_SUBSETS_FOREACH_USER)
856 is_scaled = TRUE;
859 if (is_scaled)
860 collection.glyphs_size = font_subsets->max_glyphs_per_scaled_subset_used;
861 else
862 collection.glyphs_size = font_subsets->max_glyphs_per_unscaled_subset_used;
864 if (! collection.glyphs_size)
865 return CAIRO_STATUS_SUCCESS;
867 collection.glyphs = _cairo_malloc_ab (collection.glyphs_size, sizeof(unsigned long));
868 collection.utf8 = _cairo_malloc_ab (collection.glyphs_size, sizeof(char *));
869 if (collection.glyphs == NULL || collection.utf8 == NULL) {
870 if (collection.glyphs != NULL)
871 free (collection.glyphs);
872 if (collection.utf8 != NULL)
873 free (collection.utf8);
875 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
878 collection.font_subset_callback = font_subset_callback;
879 collection.font_subset_callback_closure = closure;
880 collection.status = CAIRO_STATUS_SUCCESS;
882 if (is_scaled)
883 sub_font = font_subsets->scaled_sub_fonts_list;
884 else
885 sub_font = font_subsets->unscaled_sub_fonts_list;
887 while (sub_font) {
888 if (sub_font->is_user == is_user)
889 _cairo_sub_font_collect (sub_font, &collection);
891 sub_font = sub_font->next;
893 free (collection.utf8);
894 free (collection.glyphs);
896 return collection.status;
899 cairo_status_t
900 _cairo_scaled_font_subsets_foreach_scaled (cairo_scaled_font_subsets_t *font_subsets,
901 cairo_scaled_font_subset_callback_func_t font_subset_callback,
902 void *closure)
904 return _cairo_scaled_font_subsets_foreach_internal (font_subsets,
905 font_subset_callback,
906 closure,
907 CAIRO_SUBSETS_FOREACH_SCALED);
910 cairo_status_t
911 _cairo_scaled_font_subsets_foreach_unscaled (cairo_scaled_font_subsets_t *font_subsets,
912 cairo_scaled_font_subset_callback_func_t font_subset_callback,
913 void *closure)
915 return _cairo_scaled_font_subsets_foreach_internal (font_subsets,
916 font_subset_callback,
917 closure,
918 CAIRO_SUBSETS_FOREACH_UNSCALED);
921 cairo_status_t
922 _cairo_scaled_font_subsets_foreach_user (cairo_scaled_font_subsets_t *font_subsets,
923 cairo_scaled_font_subset_callback_func_t font_subset_callback,
924 void *closure)
926 return _cairo_scaled_font_subsets_foreach_internal (font_subsets,
927 font_subset_callback,
928 closure,
929 CAIRO_SUBSETS_FOREACH_USER);
932 static cairo_bool_t
933 _cairo_string_equal (const void *key_a, const void *key_b)
935 const cairo_string_entry_t *a = key_a;
936 const cairo_string_entry_t *b = key_b;
938 if (strcmp (a->string, b->string) == 0)
939 return TRUE;
940 else
941 return FALSE;
944 static void
945 _cairo_string_init_key (cairo_string_entry_t *key, char *s)
947 unsigned long sum = 0;
948 unsigned int i;
950 for (i = 0; i < strlen(s); i++)
951 sum += s[i];
952 key->base.hash = sum;
953 key->string = s;
956 static cairo_status_t
957 create_string_entry (char *s, cairo_string_entry_t **entry)
959 *entry = malloc (sizeof (cairo_string_entry_t));
960 if (*entry == NULL)
961 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
963 _cairo_string_init_key (*entry, s);
965 return CAIRO_STATUS_SUCCESS;
968 cairo_int_status_t
969 _cairo_scaled_font_subset_create_glyph_names (cairo_scaled_font_subset_t *subset)
971 unsigned int i;
972 cairo_status_t status;
973 cairo_hash_table_t *names;
974 cairo_string_entry_t key, *entry;
975 char buf[30];
976 char *utf8;
977 uint16_t *utf16;
978 int utf16_len;
980 names = _cairo_hash_table_create (_cairo_string_equal);
981 if (names == NULL)
982 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
984 subset->glyph_names = calloc (subset->num_glyphs, sizeof (char *));
985 if (subset->glyph_names == NULL) {
986 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
987 goto CLEANUP_HASH;
990 i = 0;
991 if (! _cairo_font_face_is_user (subset->scaled_font->font_face)) {
992 subset->glyph_names[0] = strdup (".notdef");
993 if (subset->glyph_names[0] == NULL) {
994 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
995 goto CLEANUP_HASH;
998 status = create_string_entry (subset->glyph_names[0], &entry);
999 if (status)
1000 goto CLEANUP_HASH;
1002 status = _cairo_hash_table_insert (names, &entry->base);
1003 if (status) {
1004 free (entry);
1005 goto CLEANUP_HASH;
1007 i++;
1010 for (; i < subset->num_glyphs; i++) {
1011 utf8 = subset->utf8[i];
1012 utf16 = NULL;
1013 utf16_len = 0;
1014 if (utf8 && *utf8) {
1015 status = _cairo_utf8_to_utf16 (utf8, -1, &utf16, &utf16_len);
1016 if (status)
1017 return status; /* FIXME */
1020 if (utf16_len == 1) {
1021 snprintf (buf, sizeof(buf), "uni%04X", (int)(utf16[0]));
1022 _cairo_string_init_key (&key, buf);
1023 if (_cairo_hash_table_lookup (names, &key.base,
1024 (cairo_hash_entry_t **) &entry)) {
1025 snprintf (buf, sizeof(buf), "g%d", i);
1027 } else {
1028 snprintf (buf, sizeof(buf), "g%d", i);
1030 if (utf16)
1031 free (utf16);
1033 subset->glyph_names[i] = strdup (buf);
1034 if (subset->glyph_names[i] == NULL) {
1035 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1036 goto CLEANUP_HASH;
1039 status = create_string_entry (subset->glyph_names[i], &entry);
1040 if (status)
1041 goto CLEANUP_HASH;
1043 status = _cairo_hash_table_insert (names, &entry->base);
1044 if (status) {
1045 free (entry);
1046 goto CLEANUP_HASH;
1050 CLEANUP_HASH:
1051 while (1) {
1052 entry = _cairo_hash_table_random_entry (names, NULL);
1053 if (entry == NULL)
1054 break;
1056 _cairo_hash_table_remove (names, (cairo_hash_entry_t *) entry);
1057 free (entry);
1059 _cairo_hash_table_destroy (names);
1061 if (status == CAIRO_STATUS_SUCCESS)
1062 return CAIRO_STATUS_SUCCESS;
1064 if (subset->glyph_names != NULL) {
1065 for (i = 0; i < subset->num_glyphs; i++) {
1066 if (subset->glyph_names[i] != NULL)
1067 free (subset->glyph_names[i]);
1070 free (subset->glyph_names);
1071 subset->glyph_names = NULL;
1074 return status;
1077 #endif /* CAIRO_HAS_FONT_SUBSET */