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