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., 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
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
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() */
45 #include "cairo-error-private.h"
47 #if CAIRO_HAS_FONT_SUBSET
49 #include "cairo-scaled-font-subsets-private.h"
50 #include "cairo-user-font-private.h"
52 #define MAX_GLYPHS_PER_SIMPLE_FONT 256
53 #define MAX_GLYPHS_PER_COMPOSITE_FONT 65536
58 CAIRO_SUBSETS_COMPOSITE
59 } cairo_subsets_type_t
;
62 CAIRO_SUBSETS_FOREACH_UNSCALED
,
63 CAIRO_SUBSETS_FOREACH_SCALED
,
64 CAIRO_SUBSETS_FOREACH_USER
65 } cairo_subsets_foreach_type_t
;
67 typedef struct _cairo_sub_font
{
68 cairo_hash_entry_t base
;
70 cairo_bool_t is_scaled
;
71 cairo_bool_t is_composite
;
73 cairo_bool_t use_latin_subset
;
74 cairo_scaled_font_subsets_t
*parent
;
75 cairo_scaled_font_t
*scaled_font
;
79 int num_glyphs_in_current_subset
;
80 int num_glyphs_in_latin_subset
;
81 int max_glyphs_per_subset
;
82 char latin_char_map
[256];
84 cairo_hash_table_t
*sub_font_glyphs
;
85 struct _cairo_sub_font
*next
;
88 struct _cairo_scaled_font_subsets
{
89 cairo_subsets_type_t type
;
90 cairo_bool_t use_latin_subset
;
92 int max_glyphs_per_unscaled_subset_used
;
93 cairo_hash_table_t
*unscaled_sub_fonts
;
94 cairo_sub_font_t
*unscaled_sub_fonts_list
;
95 cairo_sub_font_t
*unscaled_sub_fonts_list_end
;
97 int max_glyphs_per_scaled_subset_used
;
98 cairo_hash_table_t
*scaled_sub_fonts
;
99 cairo_sub_font_t
*scaled_sub_fonts_list
;
100 cairo_sub_font_t
*scaled_sub_fonts_list_end
;
105 typedef struct _cairo_sub_font_glyph
{
106 cairo_hash_entry_t base
;
108 unsigned int subset_id
;
109 unsigned int subset_glyph_index
;
113 cairo_bool_t is_latin
;
115 cairo_bool_t is_mapped
;
119 } cairo_sub_font_glyph_t
;
121 typedef struct _cairo_sub_font_collection
{
122 unsigned long *glyphs
; /* scaled_font_glyph_index */
124 unsigned int glyphs_size
;
126 unsigned long *latin_to_subset_glyph_index
;
127 unsigned int max_glyph
;
128 unsigned int num_glyphs
;
130 unsigned int subset_id
;
132 cairo_status_t status
;
133 cairo_scaled_font_subset_callback_func_t font_subset_callback
;
134 void *font_subset_callback_closure
;
135 } cairo_sub_font_collection_t
;
137 typedef struct _cairo_string_entry
{
138 cairo_hash_entry_t base
;
140 } cairo_string_entry_t
;
142 static cairo_status_t
143 _cairo_sub_font_map_glyph (cairo_sub_font_t
*sub_font
,
144 unsigned long scaled_font_glyph_index
,
147 cairo_scaled_font_subsets_glyph_t
*subset_glyph
);
150 _cairo_sub_font_glyph_init_key (cairo_sub_font_glyph_t
*sub_font_glyph
,
151 unsigned long scaled_font_glyph_index
)
153 sub_font_glyph
->base
.hash
= scaled_font_glyph_index
;
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
,
167 cairo_sub_font_glyph_t
*sub_font_glyph
;
169 sub_font_glyph
= malloc (sizeof (cairo_sub_font_glyph_t
));
170 if (unlikely (sub_font_glyph
== NULL
)) {
171 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY
);
175 _cairo_sub_font_glyph_init_key (sub_font_glyph
, scaled_font_glyph_index
);
176 sub_font_glyph
->subset_id
= subset_id
;
177 sub_font_glyph
->subset_glyph_index
= subset_glyph_index
;
178 sub_font_glyph
->x_advance
= x_advance
;
179 sub_font_glyph
->y_advance
= y_advance
;
180 sub_font_glyph
->is_latin
= (latin_character
>= 0);
181 sub_font_glyph
->latin_character
= latin_character
;
182 sub_font_glyph
->is_mapped
= FALSE
;
183 sub_font_glyph
->unicode
= unicode
;
184 sub_font_glyph
->utf8
= utf8
;
185 sub_font_glyph
->utf8_len
= utf8_len
;
187 return sub_font_glyph
;
191 _cairo_sub_font_glyph_destroy (cairo_sub_font_glyph_t
*sub_font_glyph
)
193 free (sub_font_glyph
->utf8
);
195 free (sub_font_glyph
);
199 _cairo_sub_font_glyph_pluck (void *entry
, void *closure
)
201 cairo_sub_font_glyph_t
*sub_font_glyph
= entry
;
202 cairo_hash_table_t
*sub_font_glyphs
= closure
;
204 _cairo_hash_table_remove (sub_font_glyphs
, &sub_font_glyph
->base
);
205 _cairo_sub_font_glyph_destroy (sub_font_glyph
);
209 _cairo_sub_font_glyph_collect (void *entry
, void *closure
)
211 cairo_sub_font_glyph_t
*sub_font_glyph
= entry
;
212 cairo_sub_font_collection_t
*collection
= closure
;
213 unsigned long scaled_font_glyph_index
;
214 unsigned int subset_glyph_index
;
216 if (sub_font_glyph
->subset_id
!= collection
->subset_id
)
219 scaled_font_glyph_index
= sub_font_glyph
->base
.hash
;
220 subset_glyph_index
= sub_font_glyph
->subset_glyph_index
;
222 /* Ensure we don't exceed the allocated bounds. */
223 assert (subset_glyph_index
< collection
->glyphs_size
);
225 collection
->glyphs
[subset_glyph_index
] = scaled_font_glyph_index
;
226 collection
->utf8
[subset_glyph_index
] = sub_font_glyph
->utf8
;
227 collection
->to_latin_char
[subset_glyph_index
] = sub_font_glyph
->latin_character
;
228 if (sub_font_glyph
->is_latin
)
229 collection
->latin_to_subset_glyph_index
[sub_font_glyph
->latin_character
] = subset_glyph_index
;
231 if (subset_glyph_index
> collection
->max_glyph
)
232 collection
->max_glyph
= subset_glyph_index
;
234 collection
->num_glyphs
++;
238 _cairo_sub_fonts_equal (const void *key_a
, const void *key_b
)
240 const cairo_sub_font_t
*sub_font_a
= key_a
;
241 const cairo_sub_font_t
*sub_font_b
= key_b
;
242 cairo_scaled_font_t
*a
= sub_font_a
->scaled_font
;
243 cairo_scaled_font_t
*b
= sub_font_b
->scaled_font
;
245 if (sub_font_a
->is_scaled
)
248 return a
->font_face
== b
->font_face
|| a
->original_font_face
== b
->original_font_face
;
252 _cairo_sub_font_init_key (cairo_sub_font_t
*sub_font
,
253 cairo_scaled_font_t
*scaled_font
)
255 if (sub_font
->is_scaled
)
257 sub_font
->base
.hash
= (unsigned long) scaled_font
;
258 sub_font
->scaled_font
= scaled_font
;
262 sub_font
->base
.hash
= (unsigned long) scaled_font
->font_face
;
263 sub_font
->scaled_font
= scaled_font
;
267 static cairo_status_t
268 _cairo_sub_font_create (cairo_scaled_font_subsets_t
*parent
,
269 cairo_scaled_font_t
*scaled_font
,
270 unsigned int font_id
,
271 int max_glyphs_per_subset
,
272 cairo_bool_t is_scaled
,
273 cairo_bool_t is_composite
,
274 cairo_sub_font_t
**sub_font_out
)
276 cairo_sub_font_t
*sub_font
;
279 sub_font
= malloc (sizeof (cairo_sub_font_t
));
280 if (unlikely (sub_font
== NULL
))
281 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
283 sub_font
->is_scaled
= is_scaled
;
284 sub_font
->is_composite
= is_composite
;
285 sub_font
->is_user
= _cairo_font_face_is_user (scaled_font
->font_face
);
286 _cairo_sub_font_init_key (sub_font
, scaled_font
);
288 sub_font
->parent
= parent
;
289 sub_font
->scaled_font
= scaled_font
;
290 sub_font
->font_id
= font_id
;
292 sub_font
->use_latin_subset
= parent
->use_latin_subset
;
294 /* latin subsets of Type 3 and CID CFF fonts are not supported */
295 if (sub_font
->is_user
|| sub_font
->is_scaled
||
296 _cairo_cff_scaled_font_is_cid_cff (scaled_font
) )
298 sub_font
->use_latin_subset
= FALSE
;
301 if (sub_font
->use_latin_subset
)
302 sub_font
->current_subset
= 1; /* reserve subset 0 for latin glyphs */
304 sub_font
->current_subset
= 0;
306 sub_font
->num_glyphs_in_current_subset
= 0;
307 sub_font
->num_glyphs_in_latin_subset
= 0;
308 sub_font
->max_glyphs_per_subset
= max_glyphs_per_subset
;
309 for (i
= 0; i
< 256; i
++)
310 sub_font
->latin_char_map
[i
] = FALSE
;
312 sub_font
->sub_font_glyphs
= _cairo_hash_table_create (NULL
);
313 if (unlikely (sub_font
->sub_font_glyphs
== NULL
)) {
315 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
317 sub_font
->next
= NULL
;
318 *sub_font_out
= sub_font
;
319 return CAIRO_STATUS_SUCCESS
;
323 _cairo_sub_font_destroy (cairo_sub_font_t
*sub_font
)
325 _cairo_hash_table_foreach (sub_font
->sub_font_glyphs
,
326 _cairo_sub_font_glyph_pluck
,
327 sub_font
->sub_font_glyphs
);
328 _cairo_hash_table_destroy (sub_font
->sub_font_glyphs
);
329 cairo_scaled_font_destroy (sub_font
->scaled_font
);
334 _cairo_sub_font_pluck (void *entry
, void *closure
)
336 cairo_sub_font_t
*sub_font
= entry
;
337 cairo_hash_table_t
*sub_fonts
= closure
;
339 _cairo_hash_table_remove (sub_fonts
, &sub_font
->base
);
340 _cairo_sub_font_destroy (sub_font
);
343 /* Characters 0x80 to 0x9f in the winansi encoding.
344 * All other characters in the range 0x00 to 0xff map 1:1 to unicode */
345 static unsigned int _winansi_0x80_to_0x9f
[] = {
346 0x20ac, 0x0000, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021,
347 0x02c6, 0x2030, 0x0160, 0x2039, 0x0152, 0x0000, 0x017d, 0x0000,
348 0x0000, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
349 0x02dc, 0x2122, 0x0161, 0x203a, 0x0153, 0x0000, 0x017e, 0x0178
353 _cairo_unicode_to_winansi (unsigned long uni
)
357 /* exclude the extra "hyphen" at 0xad to avoid duplicate glyphnames */
358 if ((uni
>= 0x20 && uni
<= 0x7e) ||
359 (uni
>= 0xa1 && uni
<= 0xff && uni
!= 0xad) ||
363 for (i
= 0; i
< 32; i
++)
364 if (_winansi_0x80_to_0x9f
[i
] == uni
)
370 static cairo_status_t
371 _cairo_sub_font_glyph_lookup_unicode (cairo_scaled_font_t
*scaled_font
,
372 unsigned long scaled_font_glyph_index
,
373 uint32_t *unicode_out
,
380 cairo_status_t status
;
382 /* Do a reverse lookup on the glyph index. unicode is -1 if the
383 * index could not be mapped to a unicode character. */
385 status
= _cairo_truetype_index_to_ucs4 (scaled_font
,
386 scaled_font_glyph_index
,
388 if (_cairo_status_is_error (status
))
391 if (unicode
== (uint32_t)-1 && scaled_font
->backend
->index_to_ucs4
) {
392 status
= scaled_font
->backend
->index_to_ucs4 (scaled_font
,
393 scaled_font_glyph_index
,
395 if (unlikely (status
))
399 *unicode_out
= unicode
;
402 if (unicode
!= (uint32_t) -1) {
403 len
= _cairo_ucs4_to_utf8 (unicode
, buf
);
405 *utf8_out
= malloc (len
+ 1);
406 if (unlikely (*utf8_out
== NULL
))
407 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
409 memcpy (*utf8_out
, buf
, len
);
410 (*utf8_out
)[len
] = 0;
415 return CAIRO_STATUS_SUCCESS
;
418 static cairo_status_t
419 _cairo_sub_font_glyph_map_to_unicode (cairo_sub_font_glyph_t
*sub_font_glyph
,
422 cairo_bool_t
*is_mapped
)
427 return CAIRO_STATUS_SUCCESS
;
429 if (utf8
!= NULL
&& utf8_len
!= 0 && utf8
[utf8_len
- 1] == '\0')
432 if (utf8
!= NULL
&& utf8_len
!= 0) {
433 if (sub_font_glyph
->utf8
!= NULL
) {
434 if (utf8_len
== sub_font_glyph
->utf8_len
&&
435 memcmp (utf8
, sub_font_glyph
->utf8
, utf8_len
) == 0)
437 /* Requested utf8 mapping matches the existing mapping */
441 /* No existing mapping. Use the requested mapping */
442 sub_font_glyph
->utf8
= malloc (utf8_len
+ 1);
443 if (unlikely (sub_font_glyph
->utf8
== NULL
))
444 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
446 memcpy (sub_font_glyph
->utf8
, utf8
, utf8_len
);
447 sub_font_glyph
->utf8
[utf8_len
] = 0;
448 sub_font_glyph
->utf8_len
= utf8_len
;
453 return CAIRO_STATUS_SUCCESS
;
456 static cairo_int_status_t
457 _cairo_sub_font_lookup_glyph (cairo_sub_font_t
*sub_font
,
458 unsigned long scaled_font_glyph_index
,
461 cairo_scaled_font_subsets_glyph_t
*subset_glyph
)
463 cairo_sub_font_glyph_t key
, *sub_font_glyph
;
464 cairo_int_status_t status
;
466 _cairo_sub_font_glyph_init_key (&key
, scaled_font_glyph_index
);
467 sub_font_glyph
= _cairo_hash_table_lookup (sub_font
->sub_font_glyphs
,
469 if (sub_font_glyph
!= NULL
) {
470 subset_glyph
->font_id
= sub_font
->font_id
;
471 subset_glyph
->subset_id
= sub_font_glyph
->subset_id
;
472 if (sub_font_glyph
->is_latin
)
473 subset_glyph
->subset_glyph_index
= sub_font_glyph
->latin_character
;
475 subset_glyph
->subset_glyph_index
= sub_font_glyph
->subset_glyph_index
;
477 subset_glyph
->is_scaled
= sub_font
->is_scaled
;
478 subset_glyph
->is_composite
= sub_font
->is_composite
;
479 subset_glyph
->is_latin
= sub_font_glyph
->is_latin
;
480 subset_glyph
->x_advance
= sub_font_glyph
->x_advance
;
481 subset_glyph
->y_advance
= sub_font_glyph
->y_advance
;
482 status
= _cairo_sub_font_glyph_map_to_unicode (sub_font_glyph
,
484 &subset_glyph
->utf8_is_mapped
);
485 subset_glyph
->unicode
= sub_font_glyph
->unicode
;
490 return CAIRO_INT_STATUS_UNSUPPORTED
;
493 static cairo_status_t
494 _cairo_sub_font_add_glyph (cairo_sub_font_t
*sub_font
,
495 unsigned long scaled_font_glyph_index
,
496 cairo_bool_t is_latin
,
501 cairo_sub_font_glyph_t
**sub_font_glyph_out
)
503 cairo_scaled_glyph_t
*scaled_glyph
;
504 cairo_sub_font_glyph_t
*sub_font_glyph
;
505 int *num_glyphs_in_subset_ptr
;
508 cairo_int_status_t status
;
510 _cairo_scaled_font_freeze_cache (sub_font
->scaled_font
);
511 status
= _cairo_scaled_glyph_lookup (sub_font
->scaled_font
,
512 scaled_font_glyph_index
,
513 CAIRO_SCALED_GLYPH_INFO_METRICS
,
515 assert (status
!= CAIRO_INT_STATUS_UNSUPPORTED
);
516 if (unlikely (status
)) {
517 _cairo_scaled_font_thaw_cache (sub_font
->scaled_font
);
521 x_advance
= scaled_glyph
->metrics
.x_advance
;
522 y_advance
= scaled_glyph
->metrics
.y_advance
;
523 _cairo_scaled_font_thaw_cache (sub_font
->scaled_font
);
525 if (!is_latin
&& sub_font
->num_glyphs_in_current_subset
== sub_font
->max_glyphs_per_subset
)
527 sub_font
->current_subset
++;
528 sub_font
->num_glyphs_in_current_subset
= 0;
532 num_glyphs_in_subset_ptr
= &sub_font
->num_glyphs_in_latin_subset
;
534 num_glyphs_in_subset_ptr
= &sub_font
->num_glyphs_in_current_subset
;
536 /* Reserve first glyph in subset for the .notdef glyph except for
538 if (*num_glyphs_in_subset_ptr
== 0 &&
539 scaled_font_glyph_index
!= 0 &&
540 ! _cairo_font_face_is_user (sub_font
->scaled_font
->font_face
))
542 status
= _cairo_sub_font_add_glyph (sub_font
,
550 if (unlikely (status
))
554 sub_font_glyph
= _cairo_sub_font_glyph_create (scaled_font_glyph_index
,
555 is_latin
? 0 : sub_font
->current_subset
,
556 *num_glyphs_in_subset_ptr
,
559 is_latin
? latin_character
: -1,
564 if (unlikely (sub_font_glyph
== NULL
))
565 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
567 status
= _cairo_hash_table_insert (sub_font
->sub_font_glyphs
, &sub_font_glyph
->base
);
568 if (unlikely (status
)) {
569 _cairo_sub_font_glyph_destroy (sub_font_glyph
);
573 (*num_glyphs_in_subset_ptr
)++;
574 if (sub_font
->is_scaled
) {
575 if (*num_glyphs_in_subset_ptr
> sub_font
->parent
->max_glyphs_per_scaled_subset_used
)
576 sub_font
->parent
->max_glyphs_per_scaled_subset_used
= *num_glyphs_in_subset_ptr
;
578 if (*num_glyphs_in_subset_ptr
> sub_font
->parent
->max_glyphs_per_unscaled_subset_used
)
579 sub_font
->parent
->max_glyphs_per_unscaled_subset_used
= *num_glyphs_in_subset_ptr
;
582 *sub_font_glyph_out
= sub_font_glyph
;
584 return CAIRO_STATUS_SUCCESS
;
587 static cairo_status_t
588 _cairo_sub_font_map_glyph (cairo_sub_font_t
*sub_font
,
589 unsigned long scaled_font_glyph_index
,
590 const char *text_utf8
,
592 cairo_scaled_font_subsets_glyph_t
*subset_glyph
)
594 cairo_sub_font_glyph_t key
, *sub_font_glyph
;
595 cairo_status_t status
;
597 _cairo_sub_font_glyph_init_key (&key
, scaled_font_glyph_index
);
598 sub_font_glyph
= _cairo_hash_table_lookup (sub_font
->sub_font_glyphs
,
600 if (sub_font_glyph
== NULL
) {
601 uint32_t font_unicode
;
604 cairo_bool_t is_latin
;
607 status
= _cairo_sub_font_glyph_lookup_unicode (sub_font
->scaled_font
,
608 scaled_font_glyph_index
,
612 if (unlikely(status
))
615 /* If the supplied utf8 is a valid single character, use it
616 * instead of the font lookup */
617 if (text_utf8
!= NULL
&& text_utf8_len
> 0) {
621 status
= _cairo_utf8_to_ucs4 (text_utf8
, text_utf8_len
,
623 if (status
== CAIRO_STATUS_SUCCESS
) {
625 font_unicode
= ucs4
[0];
627 font_utf8
= malloc (text_utf8_len
+ 1);
628 if (font_utf8
== NULL
) {
630 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
632 memcpy (font_utf8
, text_utf8
, text_utf8_len
);
633 font_utf8
[text_utf8_len
] = 0;
634 font_utf8_len
= text_utf8_len
;
640 /* If glyph is in the winansi encoding and font is not a user
641 * font, put glyph in the latin subset. If glyph is .notdef
642 * the latin subset is preferred but only if the latin subset
643 * already contains at least one glyph. We don't want to
644 * create a separate subset just for the .notdef glyph.
647 latin_character
= -1;
648 if (sub_font
->use_latin_subset
&&
649 (! _cairo_font_face_is_user (sub_font
->scaled_font
->font_face
)))
651 latin_character
= _cairo_unicode_to_winansi (font_unicode
);
652 if (latin_character
> 0 ||
653 (latin_character
== 0 && sub_font
->num_glyphs_in_latin_subset
> 0))
655 if (!sub_font
->latin_char_map
[latin_character
]) {
656 sub_font
->latin_char_map
[latin_character
] = TRUE
;
662 status
= _cairo_sub_font_add_glyph (sub_font
,
663 scaled_font_glyph_index
,
670 if (unlikely(status
))
674 subset_glyph
->font_id
= sub_font
->font_id
;
675 subset_glyph
->subset_id
= sub_font_glyph
->subset_id
;
676 if (sub_font_glyph
->is_latin
)
677 subset_glyph
->subset_glyph_index
= sub_font_glyph
->latin_character
;
679 subset_glyph
->subset_glyph_index
= sub_font_glyph
->subset_glyph_index
;
681 subset_glyph
->is_scaled
= sub_font
->is_scaled
;
682 subset_glyph
->is_composite
= sub_font
->is_composite
;
683 subset_glyph
->is_latin
= sub_font_glyph
->is_latin
;
684 subset_glyph
->x_advance
= sub_font_glyph
->x_advance
;
685 subset_glyph
->y_advance
= sub_font_glyph
->y_advance
;
686 status
= _cairo_sub_font_glyph_map_to_unicode (sub_font_glyph
,
687 text_utf8
, text_utf8_len
,
688 &subset_glyph
->utf8_is_mapped
);
689 subset_glyph
->unicode
= sub_font_glyph
->unicode
;
695 _cairo_sub_font_collect (void *entry
, void *closure
)
697 cairo_sub_font_t
*sub_font
= entry
;
698 cairo_sub_font_collection_t
*collection
= closure
;
699 cairo_scaled_font_subset_t subset
;
703 if (collection
->status
)
706 collection
->status
= sub_font
->scaled_font
->status
;
707 if (collection
->status
)
710 for (i
= 0; i
<= sub_font
->current_subset
; i
++) {
711 collection
->subset_id
= i
;
712 collection
->num_glyphs
= 0;
713 collection
->max_glyph
= 0;
714 memset (collection
->latin_to_subset_glyph_index
, 0, 256*sizeof(unsigned long));
716 _cairo_hash_table_foreach (sub_font
->sub_font_glyphs
,
717 _cairo_sub_font_glyph_collect
, collection
);
718 if (collection
->status
)
720 if (collection
->num_glyphs
== 0)
723 /* Ensure the resulting array has no uninitialized holes */
724 assert (collection
->num_glyphs
== collection
->max_glyph
+ 1);
726 subset
.scaled_font
= sub_font
->scaled_font
;
727 subset
.is_composite
= sub_font
->is_composite
;
728 subset
.is_scaled
= sub_font
->is_scaled
;
729 subset
.font_id
= sub_font
->font_id
;
730 subset
.subset_id
= i
;
731 subset
.glyphs
= collection
->glyphs
;
732 subset
.utf8
= collection
->utf8
;
733 subset
.num_glyphs
= collection
->num_glyphs
;
734 subset
.glyph_names
= NULL
;
736 subset
.is_latin
= FALSE
;
737 if (sub_font
->use_latin_subset
&& i
== 0) {
738 subset
.is_latin
= TRUE
;
739 subset
.to_latin_char
= collection
->to_latin_char
;
740 subset
.latin_to_subset_glyph_index
= collection
->latin_to_subset_glyph_index
;
742 subset
.to_latin_char
= NULL
;
743 subset
.latin_to_subset_glyph_index
= NULL
;
746 collection
->status
= (collection
->font_subset_callback
) (&subset
,
747 collection
->font_subset_callback_closure
);
749 if (subset
.glyph_names
!= NULL
) {
750 for (j
= 0; j
< collection
->num_glyphs
; j
++)
751 free (subset
.glyph_names
[j
]);
752 free (subset
.glyph_names
);
755 if (collection
->status
)
760 static cairo_scaled_font_subsets_t
*
761 _cairo_scaled_font_subsets_create_internal (cairo_subsets_type_t type
)
763 cairo_scaled_font_subsets_t
*subsets
;
765 subsets
= malloc (sizeof (cairo_scaled_font_subsets_t
));
766 if (unlikely (subsets
== NULL
)) {
767 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY
);
771 subsets
->type
= type
;
772 subsets
->use_latin_subset
= FALSE
;
773 subsets
->max_glyphs_per_unscaled_subset_used
= 0;
774 subsets
->max_glyphs_per_scaled_subset_used
= 0;
775 subsets
->num_sub_fonts
= 0;
777 subsets
->unscaled_sub_fonts
= _cairo_hash_table_create (_cairo_sub_fonts_equal
);
778 if (! subsets
->unscaled_sub_fonts
) {
782 subsets
->unscaled_sub_fonts_list
= NULL
;
783 subsets
->unscaled_sub_fonts_list_end
= NULL
;
785 subsets
->scaled_sub_fonts
= _cairo_hash_table_create (_cairo_sub_fonts_equal
);
786 if (! subsets
->scaled_sub_fonts
) {
787 _cairo_hash_table_destroy (subsets
->unscaled_sub_fonts
);
791 subsets
->scaled_sub_fonts_list
= NULL
;
792 subsets
->scaled_sub_fonts_list_end
= NULL
;
797 cairo_scaled_font_subsets_t
*
798 _cairo_scaled_font_subsets_create_scaled (void)
800 return _cairo_scaled_font_subsets_create_internal (CAIRO_SUBSETS_SCALED
);
803 cairo_scaled_font_subsets_t
*
804 _cairo_scaled_font_subsets_create_simple (void)
806 return _cairo_scaled_font_subsets_create_internal (CAIRO_SUBSETS_SIMPLE
);
809 cairo_scaled_font_subsets_t
*
810 _cairo_scaled_font_subsets_create_composite (void)
812 return _cairo_scaled_font_subsets_create_internal (CAIRO_SUBSETS_COMPOSITE
);
816 _cairo_scaled_font_subsets_destroy (cairo_scaled_font_subsets_t
*subsets
)
818 _cairo_hash_table_foreach (subsets
->scaled_sub_fonts
, _cairo_sub_font_pluck
, subsets
->scaled_sub_fonts
);
819 _cairo_hash_table_destroy (subsets
->scaled_sub_fonts
);
821 _cairo_hash_table_foreach (subsets
->unscaled_sub_fonts
, _cairo_sub_font_pluck
, subsets
->unscaled_sub_fonts
);
822 _cairo_hash_table_destroy (subsets
->unscaled_sub_fonts
);
828 _cairo_scaled_font_subsets_enable_latin_subset (cairo_scaled_font_subsets_t
*font_subsets
,
829 cairo_bool_t use_latin
)
831 font_subsets
->use_latin_subset
= use_latin
;
835 _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t
*subsets
,
836 cairo_scaled_font_t
*scaled_font
,
837 unsigned long scaled_font_glyph_index
,
840 cairo_scaled_font_subsets_glyph_t
*subset_glyph
)
842 cairo_sub_font_t key
, *sub_font
;
843 cairo_scaled_glyph_t
*scaled_glyph
;
844 cairo_font_face_t
*font_face
;
845 cairo_matrix_t identity
;
846 cairo_font_options_t font_options
;
847 cairo_scaled_font_t
*unscaled_font
;
848 cairo_int_status_t status
;
850 cairo_bool_t type1_font
;
852 /* Lookup glyph in unscaled subsets */
853 if (subsets
->type
!= CAIRO_SUBSETS_SCALED
) {
854 key
.is_scaled
= FALSE
;
855 _cairo_sub_font_init_key (&key
, scaled_font
);
856 sub_font
= _cairo_hash_table_lookup (subsets
->unscaled_sub_fonts
,
858 if (sub_font
!= NULL
) {
859 status
= _cairo_sub_font_lookup_glyph (sub_font
,
860 scaled_font_glyph_index
,
863 if (status
!= CAIRO_INT_STATUS_UNSUPPORTED
)
868 /* Lookup glyph in scaled subsets */
869 key
.is_scaled
= TRUE
;
870 _cairo_sub_font_init_key (&key
, scaled_font
);
871 sub_font
= _cairo_hash_table_lookup (subsets
->scaled_sub_fonts
,
873 if (sub_font
!= NULL
) {
874 status
= _cairo_sub_font_lookup_glyph (sub_font
,
875 scaled_font_glyph_index
,
878 if (status
!= CAIRO_INT_STATUS_UNSUPPORTED
)
882 /* Glyph not found. Determine whether the glyph is outline or
883 * bitmap and add to the appropriate subset.
885 * glyph_index 0 (the .notdef glyph) is a special case. Some fonts
886 * will return CAIRO_INT_STATUS_UNSUPPORTED when doing a
887 * _scaled_glyph_lookup(_GLYPH_INFO_PATH). Type1-fallback creates
888 * empty glyphs in this case so we can put the glyph in a unscaled
890 if (scaled_font_glyph_index
== 0 ||
891 _cairo_font_face_is_user (scaled_font
->font_face
)) {
892 status
= CAIRO_STATUS_SUCCESS
;
894 _cairo_scaled_font_freeze_cache (scaled_font
);
895 status
= _cairo_scaled_glyph_lookup (scaled_font
,
896 scaled_font_glyph_index
,
897 CAIRO_SCALED_GLYPH_INFO_PATH
,
899 _cairo_scaled_font_thaw_cache (scaled_font
);
901 if (_cairo_int_status_is_error (status
))
904 if (status
== CAIRO_INT_STATUS_SUCCESS
&&
905 subsets
->type
!= CAIRO_SUBSETS_SCALED
&&
906 ! _cairo_font_face_is_user (scaled_font
->font_face
))
908 /* Path available. Add to unscaled subset. */
909 key
.is_scaled
= FALSE
;
910 _cairo_sub_font_init_key (&key
, scaled_font
);
911 sub_font
= _cairo_hash_table_lookup (subsets
->unscaled_sub_fonts
,
913 if (sub_font
== NULL
) {
914 font_face
= cairo_scaled_font_get_font_face (scaled_font
);
915 cairo_matrix_init_identity (&identity
);
916 _cairo_font_options_init_default (&font_options
);
917 cairo_font_options_set_hint_style (&font_options
, CAIRO_HINT_STYLE_NONE
);
918 cairo_font_options_set_hint_metrics (&font_options
, CAIRO_HINT_METRICS_OFF
);
919 unscaled_font
= cairo_scaled_font_create (font_face
,
923 if (unlikely (unscaled_font
->status
))
924 return unscaled_font
->status
;
926 subset_glyph
->is_scaled
= FALSE
;
927 type1_font
= _cairo_type1_scaled_font_is_type1 (unscaled_font
);
928 if (subsets
->type
== CAIRO_SUBSETS_COMPOSITE
&& !type1_font
) {
929 max_glyphs
= MAX_GLYPHS_PER_COMPOSITE_FONT
;
930 subset_glyph
->is_composite
= TRUE
;
932 max_glyphs
= MAX_GLYPHS_PER_SIMPLE_FONT
;
933 subset_glyph
->is_composite
= FALSE
;
936 status
= _cairo_sub_font_create (subsets
,
938 subsets
->num_sub_fonts
,
940 subset_glyph
->is_scaled
,
941 subset_glyph
->is_composite
,
944 if (unlikely (status
)) {
945 cairo_scaled_font_destroy (unscaled_font
);
949 status
= _cairo_hash_table_insert (subsets
->unscaled_sub_fonts
,
952 if (unlikely (status
)) {
953 _cairo_sub_font_destroy (sub_font
);
956 if (!subsets
->unscaled_sub_fonts_list
)
957 subsets
->unscaled_sub_fonts_list
= sub_font
;
959 subsets
->unscaled_sub_fonts_list_end
->next
= sub_font
;
960 subsets
->unscaled_sub_fonts_list_end
= sub_font
;
961 subsets
->num_sub_fonts
++;
964 /* No path available. Add to scaled subset. */
965 key
.is_scaled
= TRUE
;
966 _cairo_sub_font_init_key (&key
, scaled_font
);
967 sub_font
= _cairo_hash_table_lookup (subsets
->scaled_sub_fonts
,
969 if (sub_font
== NULL
) {
970 subset_glyph
->is_scaled
= TRUE
;
971 subset_glyph
->is_composite
= FALSE
;
972 if (subsets
->type
== CAIRO_SUBSETS_SCALED
)
973 max_glyphs
= INT_MAX
;
975 max_glyphs
= MAX_GLYPHS_PER_SIMPLE_FONT
;
977 status
= _cairo_sub_font_create (subsets
,
978 cairo_scaled_font_reference (scaled_font
),
979 subsets
->num_sub_fonts
,
981 subset_glyph
->is_scaled
,
982 subset_glyph
->is_composite
,
984 if (unlikely (status
)) {
985 cairo_scaled_font_destroy (scaled_font
);
989 status
= _cairo_hash_table_insert (subsets
->scaled_sub_fonts
,
991 if (unlikely (status
)) {
992 _cairo_sub_font_destroy (sub_font
);
995 if (!subsets
->scaled_sub_fonts_list
)
996 subsets
->scaled_sub_fonts_list
= sub_font
;
998 subsets
->scaled_sub_fonts_list_end
->next
= sub_font
;
999 subsets
->scaled_sub_fonts_list_end
= sub_font
;
1000 subsets
->num_sub_fonts
++;
1004 return _cairo_sub_font_map_glyph (sub_font
,
1005 scaled_font_glyph_index
,
1010 static cairo_status_t
1011 _cairo_scaled_font_subsets_foreach_internal (cairo_scaled_font_subsets_t
*font_subsets
,
1012 cairo_scaled_font_subset_callback_func_t font_subset_callback
,
1014 cairo_subsets_foreach_type_t type
)
1016 cairo_sub_font_collection_t collection
;
1017 cairo_sub_font_t
*sub_font
;
1018 cairo_bool_t is_scaled
, is_user
;
1023 if (type
== CAIRO_SUBSETS_FOREACH_USER
)
1026 if (type
== CAIRO_SUBSETS_FOREACH_SCALED
||
1027 type
== CAIRO_SUBSETS_FOREACH_USER
)
1033 collection
.glyphs_size
= font_subsets
->max_glyphs_per_scaled_subset_used
;
1035 collection
.glyphs_size
= font_subsets
->max_glyphs_per_unscaled_subset_used
;
1037 if (! collection
.glyphs_size
)
1038 return CAIRO_STATUS_SUCCESS
;
1040 collection
.glyphs
= _cairo_malloc_ab (collection
.glyphs_size
, sizeof(unsigned long));
1041 collection
.utf8
= _cairo_malloc_ab (collection
.glyphs_size
, sizeof(char *));
1042 collection
.to_latin_char
= _cairo_malloc_ab (collection
.glyphs_size
, sizeof(int));
1043 collection
.latin_to_subset_glyph_index
= _cairo_malloc_ab (256, sizeof(unsigned long));
1044 if (unlikely (collection
.glyphs
== NULL
||
1045 collection
.utf8
== NULL
||
1046 collection
.to_latin_char
== NULL
||
1047 collection
.latin_to_subset_glyph_index
== NULL
)) {
1048 free (collection
.glyphs
);
1049 free (collection
.utf8
);
1050 free (collection
.to_latin_char
);
1051 free (collection
.latin_to_subset_glyph_index
);
1053 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
1056 collection
.font_subset_callback
= font_subset_callback
;
1057 collection
.font_subset_callback_closure
= closure
;
1058 collection
.status
= CAIRO_STATUS_SUCCESS
;
1061 sub_font
= font_subsets
->scaled_sub_fonts_list
;
1063 sub_font
= font_subsets
->unscaled_sub_fonts_list
;
1066 if (sub_font
->is_user
== is_user
)
1067 _cairo_sub_font_collect (sub_font
, &collection
);
1069 sub_font
= sub_font
->next
;
1071 free (collection
.utf8
);
1072 free (collection
.glyphs
);
1073 free (collection
.to_latin_char
);
1074 free (collection
.latin_to_subset_glyph_index
);
1076 return collection
.status
;
1080 _cairo_scaled_font_subsets_foreach_scaled (cairo_scaled_font_subsets_t
*font_subsets
,
1081 cairo_scaled_font_subset_callback_func_t font_subset_callback
,
1084 return _cairo_scaled_font_subsets_foreach_internal (font_subsets
,
1085 font_subset_callback
,
1087 CAIRO_SUBSETS_FOREACH_SCALED
);
1091 _cairo_scaled_font_subsets_foreach_unscaled (cairo_scaled_font_subsets_t
*font_subsets
,
1092 cairo_scaled_font_subset_callback_func_t font_subset_callback
,
1095 return _cairo_scaled_font_subsets_foreach_internal (font_subsets
,
1096 font_subset_callback
,
1098 CAIRO_SUBSETS_FOREACH_UNSCALED
);
1102 _cairo_scaled_font_subsets_foreach_user (cairo_scaled_font_subsets_t
*font_subsets
,
1103 cairo_scaled_font_subset_callback_func_t font_subset_callback
,
1106 return _cairo_scaled_font_subsets_foreach_internal (font_subsets
,
1107 font_subset_callback
,
1109 CAIRO_SUBSETS_FOREACH_USER
);
1113 _cairo_string_equal (const void *key_a
, const void *key_b
)
1115 const cairo_string_entry_t
*a
= key_a
;
1116 const cairo_string_entry_t
*b
= key_b
;
1118 if (strcmp (a
->string
, b
->string
) == 0)
1125 _cairo_string_init_key (cairo_string_entry_t
*key
, char *s
)
1127 unsigned long sum
= 0;
1130 for (i
= 0; i
< strlen(s
); i
++)
1132 key
->base
.hash
= sum
;
1136 static cairo_status_t
1137 create_string_entry (char *s
, cairo_string_entry_t
**entry
)
1139 *entry
= malloc (sizeof (cairo_string_entry_t
));
1140 if (unlikely (*entry
== NULL
))
1141 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
1143 _cairo_string_init_key (*entry
, s
);
1145 return CAIRO_STATUS_SUCCESS
;
1149 _pluck_entry (void *entry
, void *closure
)
1151 _cairo_hash_table_remove (closure
, entry
);
1156 _cairo_scaled_font_subset_create_glyph_names (cairo_scaled_font_subset_t
*subset
)
1159 cairo_hash_table_t
*names
;
1160 cairo_string_entry_t key
, *entry
;
1165 cairo_status_t status
= CAIRO_STATUS_SUCCESS
;
1167 names
= _cairo_hash_table_create (_cairo_string_equal
);
1168 if (unlikely (names
== NULL
))
1169 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
1171 subset
->glyph_names
= calloc (subset
->num_glyphs
, sizeof (char *));
1172 if (unlikely (subset
->glyph_names
== NULL
)) {
1173 status
= _cairo_error (CAIRO_STATUS_NO_MEMORY
);
1178 if (! subset
->is_scaled
) {
1179 subset
->glyph_names
[0] = strdup (".notdef");
1180 if (unlikely (subset
->glyph_names
[0] == NULL
)) {
1181 status
= _cairo_error (CAIRO_STATUS_NO_MEMORY
);
1185 status
= create_string_entry (subset
->glyph_names
[0], &entry
);
1186 if (unlikely (status
))
1189 status
= _cairo_hash_table_insert (names
, &entry
->base
);
1190 if (unlikely (status
)) {
1197 for (; i
< subset
->num_glyphs
; i
++) {
1198 utf8
= subset
->utf8
[i
];
1201 if (utf8
&& *utf8
) {
1202 status
= _cairo_utf8_to_utf16 (utf8
, -1, &utf16
, &utf16_len
);
1203 if (unlikely (status
))
1207 if (utf16_len
== 1) {
1208 int ch
= _cairo_unicode_to_winansi (utf16
[0]);
1209 if (ch
> 0 && _cairo_winansi_to_glyphname (ch
)) {
1210 strncpy (buf
, _cairo_winansi_to_glyphname (ch
), sizeof (buf
));
1211 buf
[sizeof (buf
)-1] = '\0';
1213 snprintf (buf
, sizeof (buf
), "uni%04X", (int) utf16
[0]);
1216 _cairo_string_init_key (&key
, buf
);
1217 entry
= _cairo_hash_table_lookup (names
, &key
.base
);
1219 snprintf (buf
, sizeof (buf
), "g%d", i
);
1221 snprintf (buf
, sizeof (buf
), "g%d", i
);
1225 subset
->glyph_names
[i
] = strdup (buf
);
1226 if (unlikely (subset
->glyph_names
[i
] == NULL
)) {
1227 status
= _cairo_error (CAIRO_STATUS_NO_MEMORY
);
1231 status
= create_string_entry (subset
->glyph_names
[i
], &entry
);
1232 if (unlikely (status
))
1235 status
= _cairo_hash_table_insert (names
, &entry
->base
);
1236 if (unlikely (status
)) {
1243 _cairo_hash_table_foreach (names
, _pluck_entry
, names
);
1244 _cairo_hash_table_destroy (names
);
1246 if (likely (status
== CAIRO_STATUS_SUCCESS
))
1247 return CAIRO_STATUS_SUCCESS
;
1249 if (subset
->glyph_names
!= NULL
) {
1250 for (i
= 0; i
< subset
->num_glyphs
; i
++) {
1251 free (subset
->glyph_names
[i
]);
1254 free (subset
->glyph_names
);
1255 subset
->glyph_names
= NULL
;
1262 _cairo_escape_ps_name (char **ps_name
)
1264 cairo_status_t status
= CAIRO_STATUS_SUCCESS
;
1266 /* Ensure PS name is a valid PDF/PS name object. In PDF names are
1267 * treated as UTF8 and non ASCII bytes, ' ', and '#' are encoded
1268 * as '#' followed by 2 hex digits that encode the byte. By also
1269 * encoding the characters in the reserved string we ensure the
1270 * name is also PS compatible. */
1272 static const char *reserved
= "()<>[]{}/%#\\";
1273 char buf
[128]; /* max name length is 127 bytes */
1274 char *src
= *ps_name
;
1277 while (*src
&& dst
< buf
+ 127) {
1278 unsigned char c
= *src
;
1279 if (c
< 0x21 || c
> 0x7e || strchr (reserved
, c
)) {
1280 if (dst
+ 4 > buf
+ 127)
1283 snprintf (dst
, 4, "#%02X", c
);
1292 *ps_name
= strdup (buf
);
1293 if (*ps_name
== NULL
) {
1294 status
= _cairo_error (CAIRO_STATUS_NO_MEMORY
);
1301 #endif /* CAIRO_HAS_FONT_SUBSET */