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
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() */
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
57 CAIRO_SUBSETS_COMPOSITE
58 } cairo_subsets_type_t
;
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
;
72 cairo_scaled_font_subsets_t
*parent
;
73 cairo_scaled_font_t
*scaled_font
;
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
;
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
;
100 typedef struct _cairo_sub_font_glyph
{
101 cairo_hash_entry_t base
;
103 unsigned int subset_id
;
104 unsigned int subset_glyph_index
;
108 cairo_bool_t is_mapped
;
112 } cairo_sub_font_glyph_t
;
114 typedef struct _cairo_sub_font_collection
{
115 unsigned long *glyphs
; /* scaled_font_glyph_index */
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
;
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
,
138 cairo_scaled_font_subsets_glyph_t
*subset_glyph
);
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
;
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
,
163 cairo_sub_font_glyph_t
*sub_font_glyph
;
165 sub_font_glyph
= malloc (sizeof (cairo_sub_font_glyph_t
));
166 if (unlikely (sub_font_glyph
== NULL
)) {
167 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY
);
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
;
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
);
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
);
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
)
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
++;
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
;
233 cairo_scaled_font_t
*a
= sub_font_a
->scaled_font
;
234 cairo_scaled_font_t
*b
= sub_font_b
->scaled_font
;
236 if (sub_font_a
->is_scaled
)
239 return a
->font_face
== b
->font_face
|| a
->original_font_face
== b
->original_font_face
;
243 _cairo_sub_font_init_key (cairo_sub_font_t
*sub_font
,
244 cairo_scaled_font_t
*scaled_font
)
246 if (sub_font
->is_scaled
)
248 sub_font
->base
.hash
= (unsigned long) scaled_font
;
249 sub_font
->scaled_font
= scaled_font
;
253 sub_font
->base
.hash
= (unsigned long) scaled_font
->font_face
;
254 sub_font
->scaled_font
= scaled_font
;
258 static cairo_status_t
259 _cairo_sub_font_create (cairo_scaled_font_subsets_t
*parent
,
260 cairo_scaled_font_t
*scaled_font
,
261 unsigned int font_id
,
262 int max_glyphs_per_subset
,
263 cairo_bool_t is_scaled
,
264 cairo_bool_t is_composite
,
265 cairo_sub_font_t
**sub_font_out
)
267 cairo_sub_font_t
*sub_font
;
268 cairo_status_t status
;
269 cairo_scaled_font_subsets_glyph_t subset_glyph
;
271 sub_font
= malloc (sizeof (cairo_sub_font_t
));
272 if (unlikely (sub_font
== NULL
))
273 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
275 sub_font
->is_scaled
= is_scaled
;
276 sub_font
->is_composite
= is_composite
;
277 sub_font
->is_user
= _cairo_font_face_is_user (scaled_font
->font_face
);
278 _cairo_sub_font_init_key (sub_font
, scaled_font
);
280 sub_font
->parent
= parent
;
281 sub_font
->scaled_font
= scaled_font
;
282 sub_font
->font_id
= font_id
;
284 sub_font
->current_subset
= 0;
285 sub_font
->num_glyphs_in_current_subset
= 0;
286 sub_font
->max_glyphs_per_subset
= max_glyphs_per_subset
;
288 sub_font
->sub_font_glyphs
= _cairo_hash_table_create (_cairo_sub_font_glyphs_equal
);
289 if (unlikely (sub_font
->sub_font_glyphs
== NULL
)) {
291 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
293 sub_font
->next
= NULL
;
295 /* Reserve first glyph in subset for the .notdef glyph except for
297 if (! _cairo_font_face_is_user (scaled_font
->font_face
)) {
298 status
= _cairo_sub_font_map_glyph (sub_font
, 0, NULL
, -1, &subset_glyph
);
299 if (unlikely (status
)) {
300 _cairo_hash_table_destroy (sub_font
->sub_font_glyphs
);
306 *sub_font_out
= sub_font
;
307 return CAIRO_STATUS_SUCCESS
;
311 _cairo_sub_font_destroy (cairo_sub_font_t
*sub_font
)
313 _cairo_hash_table_foreach (sub_font
->sub_font_glyphs
,
314 _cairo_sub_font_glyph_pluck
,
315 sub_font
->sub_font_glyphs
);
316 _cairo_hash_table_destroy (sub_font
->sub_font_glyphs
);
317 cairo_scaled_font_destroy (sub_font
->scaled_font
);
322 _cairo_sub_font_pluck (void *entry
, void *closure
)
324 cairo_sub_font_t
*sub_font
= entry
;
325 cairo_hash_table_t
*sub_fonts
= closure
;
327 _cairo_hash_table_remove (sub_fonts
, &sub_font
->base
);
328 _cairo_sub_font_destroy (sub_font
);
331 static cairo_status_t
332 _cairo_sub_font_glyph_lookup_unicode (cairo_sub_font_glyph_t
*sub_font_glyph
,
333 cairo_scaled_font_t
*scaled_font
,
334 unsigned long scaled_font_glyph_index
)
339 cairo_status_t status
;
341 /* Do a reverse lookup on the glyph index. unicode is -1 if the
342 * index could not be mapped to a unicode character. */
344 status
= _cairo_truetype_index_to_ucs4 (scaled_font
,
345 scaled_font_glyph_index
,
347 if (_cairo_status_is_error (status
))
350 if (unicode
== (uint32_t)-1 && scaled_font
->backend
->index_to_ucs4
) {
351 status
= scaled_font
->backend
->index_to_ucs4 (scaled_font
,
352 scaled_font_glyph_index
,
354 if (unlikely (status
))
358 sub_font_glyph
->unicode
= unicode
;
359 sub_font_glyph
->utf8
= NULL
;
360 sub_font_glyph
->utf8_len
= 0;
361 if (unicode
!= (uint32_t) -1) {
362 len
= _cairo_ucs4_to_utf8 (unicode
, buf
);
364 sub_font_glyph
->utf8
= malloc (len
+ 1);
365 if (unlikely (sub_font_glyph
->utf8
== NULL
))
366 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
368 memcpy (sub_font_glyph
->utf8
, buf
, len
);
369 sub_font_glyph
->utf8
[len
] = 0;
370 sub_font_glyph
->utf8_len
= len
;
374 return CAIRO_STATUS_SUCCESS
;
377 static cairo_status_t
378 _cairo_sub_font_glyph_map_to_unicode (cairo_sub_font_glyph_t
*sub_font_glyph
,
381 cairo_bool_t
*is_mapped
)
386 return CAIRO_STATUS_SUCCESS
;
388 if (utf8
!= NULL
&& utf8_len
!= 0 && utf8
[utf8_len
- 1] == '\0')
391 if (utf8
!= NULL
&& utf8_len
!= 0) {
392 if (sub_font_glyph
->utf8
!= NULL
) {
393 if (utf8_len
== sub_font_glyph
->utf8_len
&&
394 memcmp (utf8
, sub_font_glyph
->utf8
, utf8_len
) == 0)
396 /* Requested utf8 mapping matches the existing mapping */
400 /* No existing mapping. Use the requested mapping */
401 sub_font_glyph
->utf8
= malloc (utf8_len
+ 1);
402 if (unlikely (sub_font_glyph
->utf8
== NULL
))
403 return CAIRO_STATUS_NO_MEMORY
;
405 memcpy (sub_font_glyph
->utf8
, utf8
, utf8_len
);
406 sub_font_glyph
->utf8
[utf8_len
] = 0;
407 sub_font_glyph
->utf8_len
= utf8_len
;
412 return CAIRO_STATUS_SUCCESS
;
415 static cairo_int_status_t
416 _cairo_sub_font_lookup_glyph (cairo_sub_font_t
*sub_font
,
417 unsigned long scaled_font_glyph_index
,
420 cairo_scaled_font_subsets_glyph_t
*subset_glyph
)
422 cairo_sub_font_glyph_t key
, *sub_font_glyph
;
423 cairo_int_status_t status
;
425 _cairo_sub_font_glyph_init_key (&key
, scaled_font_glyph_index
);
426 sub_font_glyph
= _cairo_hash_table_lookup (sub_font
->sub_font_glyphs
,
428 if (sub_font_glyph
!= NULL
) {
429 subset_glyph
->font_id
= sub_font
->font_id
;
430 subset_glyph
->subset_id
= sub_font_glyph
->subset_id
;
431 subset_glyph
->subset_glyph_index
= sub_font_glyph
->subset_glyph_index
;
432 subset_glyph
->is_scaled
= sub_font
->is_scaled
;
433 subset_glyph
->is_composite
= sub_font
->is_composite
;
434 subset_glyph
->x_advance
= sub_font_glyph
->x_advance
;
435 subset_glyph
->y_advance
= sub_font_glyph
->y_advance
;
436 status
= _cairo_sub_font_glyph_map_to_unicode (sub_font_glyph
,
438 &subset_glyph
->utf8_is_mapped
);
439 subset_glyph
->unicode
= sub_font_glyph
->unicode
;
444 return CAIRO_INT_STATUS_UNSUPPORTED
;
447 static cairo_status_t
448 _cairo_sub_font_map_glyph (cairo_sub_font_t
*sub_font
,
449 unsigned long scaled_font_glyph_index
,
452 cairo_scaled_font_subsets_glyph_t
*subset_glyph
)
454 cairo_sub_font_glyph_t key
, *sub_font_glyph
;
455 cairo_status_t status
;
457 _cairo_sub_font_glyph_init_key (&key
, scaled_font_glyph_index
);
458 sub_font_glyph
= _cairo_hash_table_lookup (sub_font
->sub_font_glyphs
,
460 if (sub_font_glyph
== NULL
) {
461 cairo_scaled_glyph_t
*scaled_glyph
;
463 if (sub_font
->num_glyphs_in_current_subset
== sub_font
->max_glyphs_per_subset
)
465 cairo_scaled_font_subsets_glyph_t tmp_subset_glyph
;
467 sub_font
->current_subset
++;
468 sub_font
->num_glyphs_in_current_subset
= 0;
470 /* Reserve first glyph in subset for the .notdef glyph
471 * except for Type 3 fonts */
472 if (! _cairo_font_face_is_user (sub_font
->scaled_font
->font_face
)) {
473 status
= _cairo_sub_font_map_glyph (sub_font
, 0, NULL
, -1, &tmp_subset_glyph
);
474 if (unlikely (status
))
479 _cairo_scaled_font_freeze_cache (sub_font
->scaled_font
);
480 status
= _cairo_scaled_glyph_lookup (sub_font
->scaled_font
,
481 scaled_font_glyph_index
,
482 CAIRO_SCALED_GLYPH_INFO_METRICS
,
484 assert (status
!= CAIRO_INT_STATUS_UNSUPPORTED
);
485 if (unlikely (status
)) {
486 _cairo_scaled_font_thaw_cache (sub_font
->scaled_font
);
490 sub_font_glyph
= _cairo_sub_font_glyph_create (scaled_font_glyph_index
,
491 sub_font
->current_subset
,
492 sub_font
->num_glyphs_in_current_subset
,
493 scaled_glyph
->metrics
.x_advance
,
494 scaled_glyph
->metrics
.y_advance
);
495 _cairo_scaled_font_thaw_cache (sub_font
->scaled_font
);
497 if (unlikely (sub_font_glyph
== NULL
))
498 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
500 status
= _cairo_sub_font_glyph_lookup_unicode (sub_font_glyph
,
501 sub_font
->scaled_font
,
502 scaled_font_glyph_index
);
503 if (unlikely (status
)) {
504 _cairo_sub_font_glyph_destroy (sub_font_glyph
);
508 status
= _cairo_hash_table_insert (sub_font
->sub_font_glyphs
, &sub_font_glyph
->base
);
509 if (unlikely (status
)) {
510 _cairo_sub_font_glyph_destroy (sub_font_glyph
);
514 sub_font
->num_glyphs_in_current_subset
++;
516 if (sub_font
->is_scaled
) {
517 if (sub_font
->num_glyphs_in_current_subset
> sub_font
->parent
->max_glyphs_per_scaled_subset_used
)
518 sub_font
->parent
->max_glyphs_per_scaled_subset_used
= sub_font
->num_glyphs_in_current_subset
;
520 if (sub_font
->num_glyphs_in_current_subset
> sub_font
->parent
->max_glyphs_per_unscaled_subset_used
)
521 sub_font
->parent
->max_glyphs_per_unscaled_subset_used
= sub_font
->num_glyphs_in_current_subset
;
525 subset_glyph
->font_id
= sub_font
->font_id
;
526 subset_glyph
->subset_id
= sub_font_glyph
->subset_id
;
527 subset_glyph
->subset_glyph_index
= sub_font_glyph
->subset_glyph_index
;
528 subset_glyph
->is_scaled
= sub_font
->is_scaled
;
529 subset_glyph
->is_composite
= sub_font
->is_composite
;
530 subset_glyph
->x_advance
= sub_font_glyph
->x_advance
;
531 subset_glyph
->y_advance
= sub_font_glyph
->y_advance
;
532 status
= _cairo_sub_font_glyph_map_to_unicode (sub_font_glyph
,
534 &subset_glyph
->utf8_is_mapped
);
535 subset_glyph
->unicode
= sub_font_glyph
->unicode
;
541 _cairo_sub_font_collect (void *entry
, void *closure
)
543 cairo_sub_font_t
*sub_font
= entry
;
544 cairo_sub_font_collection_t
*collection
= closure
;
545 cairo_scaled_font_subset_t subset
;
549 if (collection
->status
)
552 collection
->status
= sub_font
->scaled_font
->status
;
553 if (collection
->status
)
556 for (i
= 0; i
<= sub_font
->current_subset
; i
++) {
557 collection
->subset_id
= i
;
558 collection
->num_glyphs
= 0;
559 collection
->max_glyph
= 0;
561 _cairo_hash_table_foreach (sub_font
->sub_font_glyphs
,
562 _cairo_sub_font_glyph_collect
, collection
);
563 if (collection
->status
)
565 if (collection
->num_glyphs
== 0)
568 /* Ensure the resulting array has no uninitialized holes */
569 assert (collection
->num_glyphs
== collection
->max_glyph
+ 1);
571 subset
.scaled_font
= sub_font
->scaled_font
;
572 subset
.is_composite
= sub_font
->is_composite
;
573 subset
.font_id
= sub_font
->font_id
;
574 subset
.subset_id
= i
;
575 subset
.glyphs
= collection
->glyphs
;
576 subset
.utf8
= collection
->utf8
;
577 subset
.num_glyphs
= collection
->num_glyphs
;
578 subset
.glyph_names
= NULL
;
579 /* No need to check for out of memory here. If to_unicode is NULL, the PDF
580 * surface does not emit an ToUnicode stream */
581 subset
.to_unicode
= _cairo_malloc_ab (collection
->num_glyphs
, sizeof (unsigned long));
582 if (subset
.to_unicode
) {
583 for (j
= 0; j
< collection
->num_glyphs
; j
++) {
584 /* default unicode character required when mapping fails */
585 subset
.to_unicode
[j
] = 0xfffd;
588 collection
->status
= (collection
->font_subset_callback
) (&subset
,
589 collection
->font_subset_callback_closure
);
591 if (subset
.to_unicode
!= NULL
)
592 free (subset
.to_unicode
);
594 if (subset
.glyph_names
!= NULL
) {
595 for (j
= 0; j
< collection
->num_glyphs
; j
++)
596 free (subset
.glyph_names
[j
]);
597 free (subset
.glyph_names
);
600 if (collection
->status
)
605 static cairo_scaled_font_subsets_t
*
606 _cairo_scaled_font_subsets_create_internal (cairo_subsets_type_t type
)
608 cairo_scaled_font_subsets_t
*subsets
;
610 subsets
= malloc (sizeof (cairo_scaled_font_subsets_t
));
611 if (unlikely (subsets
== NULL
)) {
612 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY
);
616 subsets
->type
= type
;
617 subsets
->max_glyphs_per_unscaled_subset_used
= 0;
618 subsets
->max_glyphs_per_scaled_subset_used
= 0;
619 subsets
->num_sub_fonts
= 0;
621 subsets
->unscaled_sub_fonts
= _cairo_hash_table_create (_cairo_sub_fonts_equal
);
622 if (! subsets
->unscaled_sub_fonts
) {
626 subsets
->unscaled_sub_fonts_list
= NULL
;
627 subsets
->unscaled_sub_fonts_list_end
= NULL
;
629 subsets
->scaled_sub_fonts
= _cairo_hash_table_create (_cairo_sub_fonts_equal
);
630 if (! subsets
->scaled_sub_fonts
) {
631 _cairo_hash_table_destroy (subsets
->unscaled_sub_fonts
);
635 subsets
->scaled_sub_fonts_list
= NULL
;
636 subsets
->scaled_sub_fonts_list_end
= NULL
;
641 cairo_scaled_font_subsets_t
*
642 _cairo_scaled_font_subsets_create_scaled (void)
644 return _cairo_scaled_font_subsets_create_internal (CAIRO_SUBSETS_SCALED
);
647 cairo_scaled_font_subsets_t
*
648 _cairo_scaled_font_subsets_create_simple (void)
650 return _cairo_scaled_font_subsets_create_internal (CAIRO_SUBSETS_SIMPLE
);
653 cairo_scaled_font_subsets_t
*
654 _cairo_scaled_font_subsets_create_composite (void)
656 return _cairo_scaled_font_subsets_create_internal (CAIRO_SUBSETS_COMPOSITE
);
660 _cairo_scaled_font_subsets_destroy (cairo_scaled_font_subsets_t
*subsets
)
662 _cairo_hash_table_foreach (subsets
->scaled_sub_fonts
, _cairo_sub_font_pluck
, subsets
->scaled_sub_fonts
);
663 _cairo_hash_table_destroy (subsets
->scaled_sub_fonts
);
665 _cairo_hash_table_foreach (subsets
->unscaled_sub_fonts
, _cairo_sub_font_pluck
, subsets
->unscaled_sub_fonts
);
666 _cairo_hash_table_destroy (subsets
->unscaled_sub_fonts
);
672 _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t
*subsets
,
673 cairo_scaled_font_t
*scaled_font
,
674 unsigned long scaled_font_glyph_index
,
677 cairo_scaled_font_subsets_glyph_t
*subset_glyph
)
679 cairo_sub_font_t key
, *sub_font
;
680 cairo_scaled_glyph_t
*scaled_glyph
;
681 cairo_font_face_t
*font_face
;
682 cairo_matrix_t identity
;
683 cairo_font_options_t font_options
;
684 cairo_scaled_font_t
*unscaled_font
;
685 cairo_status_t status
;
687 cairo_bool_t type1_font
;
689 /* Lookup glyph in unscaled subsets */
690 if (subsets
->type
!= CAIRO_SUBSETS_SCALED
) {
691 key
.is_scaled
= FALSE
;
692 _cairo_sub_font_init_key (&key
, scaled_font
);
693 sub_font
= _cairo_hash_table_lookup (subsets
->unscaled_sub_fonts
,
695 if (sub_font
!= NULL
) {
696 status
= _cairo_sub_font_lookup_glyph (sub_font
,
697 scaled_font_glyph_index
,
700 if (status
!= CAIRO_INT_STATUS_UNSUPPORTED
)
705 /* Lookup glyph in scaled subsets */
706 key
.is_scaled
= TRUE
;
707 _cairo_sub_font_init_key (&key
, scaled_font
);
708 sub_font
= _cairo_hash_table_lookup (subsets
->scaled_sub_fonts
,
710 if (sub_font
!= NULL
) {
711 status
= _cairo_sub_font_lookup_glyph (sub_font
,
712 scaled_font_glyph_index
,
715 if (status
!= CAIRO_INT_STATUS_UNSUPPORTED
)
719 /* Glyph not found. Determine whether the glyph is outline or
720 * bitmap and add to the appropriate subset.
722 * glyph_index 0 (the .notdef glyph) is a special case. Some fonts
723 * will return CAIRO_INT_STATUS_UNSUPPORTED when doing a
724 * _scaled_glyph_lookup(_GLYPH_INFO_PATH). Type1-fallback creates
725 * empty glyphs in this case so we can put the glyph in a unscaled
727 if (scaled_font_glyph_index
== 0 ||
728 _cairo_font_face_is_user (scaled_font
->font_face
)) {
729 status
= CAIRO_STATUS_SUCCESS
;
731 _cairo_scaled_font_freeze_cache (scaled_font
);
732 status
= _cairo_scaled_glyph_lookup (scaled_font
,
733 scaled_font_glyph_index
,
734 CAIRO_SCALED_GLYPH_INFO_PATH
,
736 _cairo_scaled_font_thaw_cache (scaled_font
);
738 if (_cairo_status_is_error (status
))
741 if (status
== CAIRO_STATUS_SUCCESS
&&
742 subsets
->type
!= CAIRO_SUBSETS_SCALED
&&
743 ! _cairo_font_face_is_user (scaled_font
->font_face
))
745 /* Path available. Add to unscaled subset. */
746 key
.is_scaled
= FALSE
;
747 _cairo_sub_font_init_key (&key
, scaled_font
);
748 sub_font
= _cairo_hash_table_lookup (subsets
->unscaled_sub_fonts
,
750 if (sub_font
== NULL
) {
751 font_face
= cairo_scaled_font_get_font_face (scaled_font
);
752 cairo_matrix_init_identity (&identity
);
753 _cairo_font_options_init_default (&font_options
);
754 cairo_font_options_set_hint_style (&font_options
, CAIRO_HINT_STYLE_NONE
);
755 cairo_font_options_set_hint_metrics (&font_options
, CAIRO_HINT_METRICS_OFF
);
756 unscaled_font
= cairo_scaled_font_create (font_face
,
760 if (unlikely (unscaled_font
->status
))
761 return unscaled_font
->status
;
763 subset_glyph
->is_scaled
= FALSE
;
765 #if CAIRO_HAS_FT_FONT
766 type1_font
= _cairo_type1_scaled_font_is_type1 (unscaled_font
);
768 if (subsets
->type
== CAIRO_SUBSETS_COMPOSITE
&& !type1_font
) {
769 max_glyphs
= MAX_GLYPHS_PER_COMPOSITE_FONT
;
770 subset_glyph
->is_composite
= TRUE
;
772 max_glyphs
= MAX_GLYPHS_PER_SIMPLE_FONT
;
773 subset_glyph
->is_composite
= FALSE
;
776 status
= _cairo_sub_font_create (subsets
,
778 subsets
->num_sub_fonts
,
780 subset_glyph
->is_scaled
,
781 subset_glyph
->is_composite
,
784 if (unlikely (status
)) {
785 cairo_scaled_font_destroy (unscaled_font
);
789 status
= _cairo_hash_table_insert (subsets
->unscaled_sub_fonts
,
792 if (unlikely (status
)) {
793 _cairo_sub_font_destroy (sub_font
);
796 if (!subsets
->unscaled_sub_fonts_list
)
797 subsets
->unscaled_sub_fonts_list
= sub_font
;
799 subsets
->unscaled_sub_fonts_list_end
->next
= sub_font
;
800 subsets
->unscaled_sub_fonts_list_end
= sub_font
;
801 subsets
->num_sub_fonts
++;
804 /* No path available. Add to scaled subset. */
805 key
.is_scaled
= TRUE
;
806 _cairo_sub_font_init_key (&key
, scaled_font
);
807 sub_font
= _cairo_hash_table_lookup (subsets
->scaled_sub_fonts
,
809 if (sub_font
== NULL
) {
810 subset_glyph
->is_scaled
= TRUE
;
811 subset_glyph
->is_composite
= FALSE
;
812 if (subsets
->type
== CAIRO_SUBSETS_SCALED
)
813 max_glyphs
= INT_MAX
;
815 max_glyphs
= MAX_GLYPHS_PER_SIMPLE_FONT
;
817 status
= _cairo_sub_font_create (subsets
,
818 cairo_scaled_font_reference (scaled_font
),
819 subsets
->num_sub_fonts
,
821 subset_glyph
->is_scaled
,
822 subset_glyph
->is_composite
,
824 if (unlikely (status
)) {
825 cairo_scaled_font_destroy (scaled_font
);
829 status
= _cairo_hash_table_insert (subsets
->scaled_sub_fonts
,
831 if (unlikely (status
)) {
832 _cairo_sub_font_destroy (sub_font
);
835 if (!subsets
->scaled_sub_fonts_list
)
836 subsets
->scaled_sub_fonts_list
= sub_font
;
838 subsets
->scaled_sub_fonts_list_end
->next
= sub_font
;
839 subsets
->scaled_sub_fonts_list_end
= sub_font
;
840 subsets
->num_sub_fonts
++;
844 return _cairo_sub_font_map_glyph (sub_font
,
845 scaled_font_glyph_index
,
850 static cairo_status_t
851 _cairo_scaled_font_subsets_foreach_internal (cairo_scaled_font_subsets_t
*font_subsets
,
852 cairo_scaled_font_subset_callback_func_t font_subset_callback
,
854 cairo_subsets_foreach_type_t type
)
856 cairo_sub_font_collection_t collection
;
857 cairo_sub_font_t
*sub_font
;
858 cairo_bool_t is_scaled
, is_user
;
863 if (type
== CAIRO_SUBSETS_FOREACH_USER
)
866 if (type
== CAIRO_SUBSETS_FOREACH_SCALED
||
867 type
== CAIRO_SUBSETS_FOREACH_USER
)
873 collection
.glyphs_size
= font_subsets
->max_glyphs_per_scaled_subset_used
;
875 collection
.glyphs_size
= font_subsets
->max_glyphs_per_unscaled_subset_used
;
877 if (! collection
.glyphs_size
)
878 return CAIRO_STATUS_SUCCESS
;
880 collection
.glyphs
= _cairo_malloc_ab (collection
.glyphs_size
, sizeof(unsigned long));
881 collection
.utf8
= _cairo_malloc_ab (collection
.glyphs_size
, sizeof(char *));
882 if (unlikely (collection
.glyphs
== NULL
|| collection
.utf8
== NULL
)) {
883 if (collection
.glyphs
!= NULL
)
884 free (collection
.glyphs
);
885 if (collection
.utf8
!= NULL
)
886 free (collection
.utf8
);
888 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
891 collection
.font_subset_callback
= font_subset_callback
;
892 collection
.font_subset_callback_closure
= closure
;
893 collection
.status
= CAIRO_STATUS_SUCCESS
;
896 sub_font
= font_subsets
->scaled_sub_fonts_list
;
898 sub_font
= font_subsets
->unscaled_sub_fonts_list
;
901 if (sub_font
->is_user
== is_user
)
902 _cairo_sub_font_collect (sub_font
, &collection
);
904 sub_font
= sub_font
->next
;
906 free (collection
.utf8
);
907 free (collection
.glyphs
);
909 return collection
.status
;
913 _cairo_scaled_font_subsets_foreach_scaled (cairo_scaled_font_subsets_t
*font_subsets
,
914 cairo_scaled_font_subset_callback_func_t font_subset_callback
,
917 return _cairo_scaled_font_subsets_foreach_internal (font_subsets
,
918 font_subset_callback
,
920 CAIRO_SUBSETS_FOREACH_SCALED
);
924 _cairo_scaled_font_subsets_foreach_unscaled (cairo_scaled_font_subsets_t
*font_subsets
,
925 cairo_scaled_font_subset_callback_func_t font_subset_callback
,
928 return _cairo_scaled_font_subsets_foreach_internal (font_subsets
,
929 font_subset_callback
,
931 CAIRO_SUBSETS_FOREACH_UNSCALED
);
935 _cairo_scaled_font_subsets_foreach_user (cairo_scaled_font_subsets_t
*font_subsets
,
936 cairo_scaled_font_subset_callback_func_t font_subset_callback
,
939 return _cairo_scaled_font_subsets_foreach_internal (font_subsets
,
940 font_subset_callback
,
942 CAIRO_SUBSETS_FOREACH_USER
);
946 _cairo_string_equal (const void *key_a
, const void *key_b
)
948 const cairo_string_entry_t
*a
= key_a
;
949 const cairo_string_entry_t
*b
= key_b
;
951 if (strcmp (a
->string
, b
->string
) == 0)
958 _cairo_string_init_key (cairo_string_entry_t
*key
, char *s
)
960 unsigned long sum
= 0;
963 for (i
= 0; i
< strlen(s
); i
++)
965 key
->base
.hash
= sum
;
969 static cairo_status_t
970 create_string_entry (char *s
, cairo_string_entry_t
**entry
)
972 *entry
= malloc (sizeof (cairo_string_entry_t
));
973 if (unlikely (*entry
== NULL
))
974 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
976 _cairo_string_init_key (*entry
, s
);
978 return CAIRO_STATUS_SUCCESS
;
982 _pluck_entry (void *entry
, void *closure
)
984 _cairo_hash_table_remove (closure
, entry
);
989 _cairo_scaled_font_subset_create_glyph_names (cairo_scaled_font_subset_t
*subset
)
992 cairo_hash_table_t
*names
;
993 cairo_string_entry_t key
, *entry
;
998 cairo_status_t status
= CAIRO_STATUS_SUCCESS
;
1000 names
= _cairo_hash_table_create (_cairo_string_equal
);
1001 if (unlikely (names
== NULL
))
1002 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
1004 subset
->glyph_names
= calloc (subset
->num_glyphs
, sizeof (char *));
1005 if (unlikely (subset
->glyph_names
== NULL
)) {
1006 status
= _cairo_error (CAIRO_STATUS_NO_MEMORY
);
1011 if (! _cairo_font_face_is_user (subset
->scaled_font
->font_face
)) {
1012 subset
->glyph_names
[0] = strdup (".notdef");
1013 if (unlikely (subset
->glyph_names
[0] == NULL
)) {
1014 status
= _cairo_error (CAIRO_STATUS_NO_MEMORY
);
1018 status
= create_string_entry (subset
->glyph_names
[0], &entry
);
1019 if (unlikely (status
))
1022 status
= _cairo_hash_table_insert (names
, &entry
->base
);
1023 if (unlikely (status
)) {
1030 for (; i
< subset
->num_glyphs
; i
++) {
1031 utf8
= subset
->utf8
[i
];
1034 if (utf8
&& *utf8
) {
1035 status
= _cairo_utf8_to_utf16 (utf8
, -1, &utf16
, &utf16_len
);
1036 if (unlikely (status
))
1040 if (utf16_len
== 1) {
1041 snprintf (buf
, sizeof (buf
), "uni%04X", (int) utf16
[0]);
1042 _cairo_string_init_key (&key
, buf
);
1043 entry
= _cairo_hash_table_lookup (names
, &key
.base
);
1045 snprintf (buf
, sizeof (buf
), "g%d", i
);
1047 snprintf (buf
, sizeof (buf
), "g%d", i
);
1052 subset
->glyph_names
[i
] = strdup (buf
);
1053 if (unlikely (subset
->glyph_names
[i
] == NULL
)) {
1054 status
= _cairo_error (CAIRO_STATUS_NO_MEMORY
);
1058 status
= create_string_entry (subset
->glyph_names
[i
], &entry
);
1059 if (unlikely (status
))
1062 status
= _cairo_hash_table_insert (names
, &entry
->base
);
1063 if (unlikely (status
)) {
1070 _cairo_hash_table_foreach (names
, _pluck_entry
, names
);
1071 _cairo_hash_table_destroy (names
);
1073 if (likely (status
== CAIRO_STATUS_SUCCESS
))
1074 return CAIRO_STATUS_SUCCESS
;
1076 if (subset
->glyph_names
!= NULL
) {
1077 for (i
= 0; i
< subset
->num_glyphs
; i
++) {
1078 if (subset
->glyph_names
[i
] != NULL
)
1079 free (subset
->glyph_names
[i
]);
1082 free (subset
->glyph_names
);
1083 subset
->glyph_names
= NULL
;
1089 #endif /* CAIRO_HAS_FONT_SUBSET */