1
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
2
/* cairo - a vector graphics library with display and print output
3
 *
4
 * Copyright © 2003 University of Southern California
5
 * Copyright © 2005 Red Hat, Inc
6
 * Copyright © 2006 Keith Packard
7
 * Copyright © 2006 Red Hat, Inc
8
 *
9
 * This library is free software; you can redistribute it and/or
10
 * modify it either under the terms of the GNU Lesser General Public
11
 * License version 2.1 as published by the Free Software Foundation
12
 * (the "LGPL") or, at your option, under the terms of the Mozilla
13
 * Public License Version 1.1 (the "MPL"). If you do not alter this
14
 * notice, a recipient may use your version of this file under either
15
 * the MPL or the LGPL.
16
 *
17
 * You should have received a copy of the LGPL along with this library
18
 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
20
 * You should have received a copy of the MPL along with this library
21
 * in the file COPYING-MPL-1.1
22
 *
23
 * The contents of this file are subject to the Mozilla Public License
24
 * Version 1.1 (the "License"); you may not use this file except in
25
 * compliance with the License. You may obtain a copy of the License at
26
 * http://www.mozilla.org/MPL/
27
 *
28
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
29
 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
30
 * the specific language governing rights and limitations.
31
 *
32
 * The Original Code is the cairo graphics library.
33
 *
34
 * The Initial Developer of the Original Code is University of Southern
35
 * California.
36
 *
37
 * Contributor(s):
38
 *	Carl D. Worth <cworth@cworth.org>
39
 *	Kristian Høgsberg <krh@redhat.com>
40
 *	Keith Packard <keithp@keithp.com>
41
 *	Adrian Johnson <ajohnson@redneon.com>
42
 */
43

            
44
#define _DEFAULT_SOURCE /* for snprintf(), strdup() */
45
#include "cairoint.h"
46
#include "cairo-error-private.h"
47

            
48
#if CAIRO_HAS_FONT_SUBSET
49

            
50
#include "cairo-scaled-font-subsets-private.h"
51
#include "cairo-user-font-private.h"
52

            
53
#define MAX_GLYPHS_PER_SIMPLE_FONT 256
54
#define MAX_GLYPHS_PER_COMPOSITE_FONT 65536
55

            
56
typedef enum {
57
    CAIRO_SUBSETS_SCALED,
58
    CAIRO_SUBSETS_SIMPLE,
59
    CAIRO_SUBSETS_COMPOSITE
60
} cairo_subsets_type_t;
61

            
62
typedef enum {
63
    CAIRO_SUBSETS_FOREACH_UNSCALED,
64
    CAIRO_SUBSETS_FOREACH_SCALED,
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 use_latin_subset;
73
    cairo_bool_t reserve_notdef;
74
    cairo_scaled_font_subsets_t *parent;
75
    cairo_scaled_font_t *scaled_font;
76
    unsigned int font_id;
77

            
78
    int current_subset;
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];
83

            
84
    cairo_hash_table_t *sub_font_glyphs;
85
    struct _cairo_sub_font *next;
86
} cairo_sub_font_t;
87

            
88
struct _cairo_scaled_font_subsets {
89
    cairo_subsets_type_t type;
90
    cairo_bool_t use_latin_subset;
91

            
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;
96

            
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;
101

            
102
    int num_sub_fonts;
103
};
104

            
105
typedef struct _cairo_sub_font_glyph {
106
    cairo_hash_entry_t base;
107

            
108
    unsigned int subset_id;
109
    unsigned int subset_glyph_index;
110
    double       x_advance;
111
    double       y_advance;
112

            
113
    cairo_bool_t is_latin;
114
    int		 latin_character;
115
    cairo_bool_t is_mapped;
116
    uint32_t     unicode;
117
    char  	*utf8;
118
    int          utf8_len;
119
} cairo_sub_font_glyph_t;
120

            
121
typedef struct _cairo_sub_font_collection {
122
    unsigned long *glyphs; /* scaled_font_glyph_index */
123
    char       **utf8;
124
    unsigned int glyphs_size;
125
    int           *to_latin_char;
126
    unsigned long *latin_to_subset_glyph_index;
127
    unsigned int max_glyph;
128
    unsigned int num_glyphs;
129

            
130
    unsigned int subset_id;
131

            
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;
136

            
137
typedef struct _cairo_string_entry {
138
    cairo_hash_entry_t base;
139
    char *string;
140
} cairo_string_entry_t;
141

            
142
static cairo_status_t
143
_cairo_sub_font_map_glyph (cairo_sub_font_t	*sub_font,
144
			   unsigned long	 scaled_font_glyph_index,
145
			   const char *		 utf8,
146
			   int			 utf8_len,
147
                           cairo_scaled_font_subsets_glyph_t *subset_glyph);
148

            
149
static void
150
_cairo_sub_font_glyph_init_key (cairo_sub_font_glyph_t  *sub_font_glyph,
151
				unsigned long		 scaled_font_glyph_index)
152
{
153
    sub_font_glyph->base.hash = scaled_font_glyph_index;
154
}
155

            
156
static cairo_sub_font_glyph_t *
157
_cairo_sub_font_glyph_create (unsigned long	scaled_font_glyph_index,
158
			      unsigned int	subset_id,
159
			      unsigned int	subset_glyph_index,
160
                              double            x_advance,
161
                              double            y_advance,
162
			      int	        latin_character,
163
			      uint32_t          unicode,
164
			      char             *utf8,
165
			      int          	utf8_len)
166
{
167
    cairo_sub_font_glyph_t *sub_font_glyph;
168

            
169
    sub_font_glyph = _cairo_calloc (sizeof (cairo_sub_font_glyph_t));
170
    if (unlikely (sub_font_glyph == NULL)) {
171
	_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
172
	return NULL;
173
    }
174

            
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;
186

            
187
    return sub_font_glyph;
188
}
189

            
190
static void
191
_cairo_sub_font_glyph_destroy (cairo_sub_font_glyph_t *sub_font_glyph)
192
{
193
    free (sub_font_glyph->utf8);
194

            
195
    free (sub_font_glyph);
196
}
197

            
198
static void
199
_cairo_sub_font_glyph_pluck (void *entry, void *closure)
200
{
201
    cairo_sub_font_glyph_t *sub_font_glyph = entry;
202
    cairo_hash_table_t *sub_font_glyphs = closure;
203

            
204
    _cairo_hash_table_remove (sub_font_glyphs, &sub_font_glyph->base);
205
    _cairo_sub_font_glyph_destroy (sub_font_glyph);
206
}
207

            
208
static void
209
_cairo_sub_font_glyph_collect (void *entry, void *closure)
210
{
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;
215

            
216
    if (sub_font_glyph->subset_id != collection->subset_id)
217
	return;
218

            
219
    scaled_font_glyph_index = sub_font_glyph->base.hash;
220
    subset_glyph_index = sub_font_glyph->subset_glyph_index;
221

            
222
    /* Ensure we don't exceed the allocated bounds. */
223
    assert (subset_glyph_index < collection->glyphs_size);
224

            
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;
230

            
231
    if (subset_glyph_index > collection->max_glyph)
232
	collection->max_glyph = subset_glyph_index;
233

            
234
    collection->num_glyphs++;
235
}
236

            
237
static cairo_bool_t
238
_cairo_sub_fonts_equal (const void *key_a, const void *key_b)
239
{
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;
244

            
245
    if (sub_font_a->is_scaled)
246
        return a == b;
247
    else
248
	return a->font_face == b->font_face || a->original_font_face == b->original_font_face;
249
}
250

            
251
static void
252
_cairo_sub_font_init_key (cairo_sub_font_t	*sub_font,
253
			  cairo_scaled_font_t	*scaled_font)
254
{
255
    if (sub_font->is_scaled)
256
    {
257
        sub_font->base.hash = (uintptr_t) scaled_font;
258
        sub_font->scaled_font = scaled_font;
259
    }
260
    else
261
    {
262
        sub_font->base.hash = (uintptr_t) scaled_font->font_face;
263
        sub_font->scaled_font = scaled_font;
264
    }
265
}
266

            
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)
275
{
276
    cairo_sub_font_t *sub_font;
277
    int i;
278

            
279
    sub_font = _cairo_calloc (sizeof (cairo_sub_font_t));
280
    if (unlikely (sub_font == NULL))
281
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
282

            
283
    sub_font->is_scaled = is_scaled;
284
    sub_font->is_composite = is_composite;
285
    sub_font->reserve_notdef = !sub_font->is_scaled;
286
    _cairo_sub_font_init_key (sub_font, scaled_font);
287

            
288
    sub_font->parent = parent;
289
    sub_font->scaled_font = scaled_font;
290
    sub_font->font_id = font_id;
291

            
292
    sub_font->use_latin_subset = parent->use_latin_subset;
293

            
294
    /* latin subsets of Type 3 and CID CFF fonts are not supported */
295
    if (sub_font->is_scaled ||
296
	_cairo_cff_scaled_font_is_cid_cff (scaled_font) )
297
    {
298
	sub_font->use_latin_subset = FALSE;
299
    }
300

            
301
    if (sub_font->use_latin_subset)
302
	sub_font->current_subset = 1; /* reserve subset 0 for latin glyphs */
303
    else
304
	sub_font->current_subset = 0;
305

            
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;
311

            
312
    sub_font->sub_font_glyphs = _cairo_hash_table_create (NULL);
313
    if (unlikely (sub_font->sub_font_glyphs == NULL)) {
314
	free (sub_font);
315
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
316
    }
317
    sub_font->next = NULL;
318
    *sub_font_out = sub_font;
319
    return CAIRO_STATUS_SUCCESS;
320
}
321

            
322
static void
323
_cairo_sub_font_destroy (cairo_sub_font_t *sub_font)
324
{
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);
330
    free (sub_font);
331
}
332

            
333
static void
334
_cairo_sub_font_pluck (void *entry, void *closure)
335
{
336
    cairo_sub_font_t *sub_font = entry;
337
    cairo_hash_table_t *sub_fonts = closure;
338

            
339
    _cairo_hash_table_remove (sub_fonts, &sub_font->base);
340
    _cairo_sub_font_destroy (sub_font);
341
}
342

            
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
350
};
351

            
352
int
353
_cairo_unicode_to_winansi (unsigned long uni)
354
{
355
    int i;
356

            
357
    /* exclude the extra "hyphen" at 0xad to avoid duplicate glyphnames */
358
    if ((uni >= 0x20 && uni <= 0x7e) ||
359
	(uni >= 0xa1 && uni <= 0xff && uni != 0xad) ||
360
	uni == 0)
361
        return uni;
362

            
363
    for (i = 0; i < 32; i++)
364
	if (_winansi_0x80_to_0x9f[i] == uni)
365
	    return i + 0x80;
366

            
367
    return -1;
368
}
369

            
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,
374
				      char  		    **utf8_out,
375
				      int          	     *utf8_len_out)
376
{
377
    uint32_t unicode;
378
    char buf[8];
379
    int len;
380
    cairo_status_t status;
381

            
382
    /* Do a reverse lookup on the glyph index. unicode is -1 if the
383
     * index could not be mapped to a unicode character. */
384
    unicode = -1;
385
    status = _cairo_truetype_index_to_ucs4 (scaled_font,
386
					    scaled_font_glyph_index,
387
					    &unicode);
388
    if (_cairo_status_is_error (status))
389
	return status;
390

            
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,
394
						      &unicode);
395
	if (unlikely (status))
396
	    return status;
397
    }
398

            
399
    *unicode_out = unicode;
400
    *utf8_out = NULL;
401
    *utf8_len_out = 0;
402
    if (unicode != (uint32_t) -1) {
403
	len = _cairo_ucs4_to_utf8 (unicode, buf);
404
	if (len > 0) {
405
            *utf8_out = _cairo_strndup (buf, len);
406
            if (unlikely (*utf8_out == NULL))
407
                return _cairo_error (CAIRO_STATUS_NO_MEMORY);
408

            
409
	    *utf8_len_out = len;
410
	}
411
    }
412

            
413
    return CAIRO_STATUS_SUCCESS;
414
}
415

            
416
static cairo_status_t
417
_cairo_sub_font_glyph_map_to_unicode (cairo_sub_font_glyph_t *sub_font_glyph,
418
				      const char	     *utf8,
419
				      int		      utf8_len,
420
				      cairo_bool_t	     *is_mapped)
421
{
422
    *is_mapped = FALSE;
423

            
424
    if (utf8_len < 0)
425
	return CAIRO_STATUS_SUCCESS;
426

            
427
    if (utf8 != NULL && utf8_len != 0 && utf8[utf8_len - 1] == '\0')
428
	utf8_len--;
429

            
430
    if (utf8 != NULL && utf8_len != 0) {
431
	if (sub_font_glyph->utf8 != NULL) {
432
	    if (utf8_len == sub_font_glyph->utf8_len &&
433
		strncmp (utf8, sub_font_glyph->utf8, utf8_len) == 0)
434
	    {
435
		/* Requested utf8 mapping matches the existing mapping */
436
		*is_mapped = TRUE;
437
	    }
438
	} else {
439
	    /* No existing mapping. Use the requested mapping */
440
            sub_font_glyph->utf8 = _cairo_strndup (utf8, utf8_len);
441
            if (unlikely (sub_font_glyph->utf8 == NULL))
442
                return _cairo_error (CAIRO_STATUS_NO_MEMORY);
443

            
444
	    sub_font_glyph->utf8_len = utf8_len;
445
	    *is_mapped = TRUE;
446
	}
447
    }
448

            
449
    return CAIRO_STATUS_SUCCESS;
450
}
451

            
452
static cairo_int_status_t
453
_cairo_sub_font_lookup_glyph (cairo_sub_font_t	                *sub_font,
454
                              unsigned long	                 scaled_font_glyph_index,
455
			      const char			*utf8,
456
			      int				 utf8_len,
457
                              cairo_scaled_font_subsets_glyph_t *subset_glyph)
458
{
459
    cairo_sub_font_glyph_t key, *sub_font_glyph;
460
    cairo_int_status_t status;
461

            
462
    _cairo_sub_font_glyph_init_key (&key, scaled_font_glyph_index);
463
    sub_font_glyph = _cairo_hash_table_lookup (sub_font->sub_font_glyphs,
464
					      &key.base);
465
    if (sub_font_glyph != NULL) {
466
        subset_glyph->font_id = sub_font->font_id;
467
        subset_glyph->subset_id = sub_font_glyph->subset_id;
468
	if (sub_font_glyph->is_latin)
469
	    subset_glyph->subset_glyph_index = sub_font_glyph->latin_character;
470
	else
471
	    subset_glyph->subset_glyph_index = sub_font_glyph->subset_glyph_index;
472

            
473
        subset_glyph->is_scaled = sub_font->is_scaled;
474
        subset_glyph->is_composite = sub_font->is_composite;
475
	subset_glyph->is_latin = sub_font_glyph->is_latin;
476
        subset_glyph->x_advance = sub_font_glyph->x_advance;
477
        subset_glyph->y_advance = sub_font_glyph->y_advance;
478
	status = _cairo_sub_font_glyph_map_to_unicode (sub_font_glyph,
479
						       utf8, utf8_len,
480
						       &subset_glyph->utf8_is_mapped);
481
	subset_glyph->unicode = sub_font_glyph->unicode;
482

            
483
	return status;
484
    }
485

            
486
    return CAIRO_INT_STATUS_UNSUPPORTED;
487
}
488

            
489
static cairo_status_t
490
_cairo_sub_font_add_glyph (cairo_sub_font_t	   *sub_font,
491
			   unsigned long	    scaled_font_glyph_index,
492
			   cairo_bool_t		    is_latin,
493
			   int			    latin_character,
494
			   uint32_t 		    unicode,
495
			   char 		   *utf8,
496
			   int 			    utf8_len,
497
			   cairo_sub_font_glyph_t **sub_font_glyph_out)
498
{
499
    cairo_scaled_glyph_t *scaled_glyph;
500
    cairo_sub_font_glyph_t *sub_font_glyph;
501
    int *num_glyphs_in_subset_ptr;
502
    double x_advance;
503
    double y_advance;
504
    cairo_int_status_t status;
505

            
506
    _cairo_scaled_font_freeze_cache (sub_font->scaled_font);
507
    status = _cairo_scaled_glyph_lookup (sub_font->scaled_font,
508
					 scaled_font_glyph_index,
509
					 CAIRO_SCALED_GLYPH_INFO_METRICS,
510
					 NULL, /* foreground color */
511
					 &scaled_glyph);
512
    assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
513
    if (unlikely (status)) {
514
	_cairo_scaled_font_thaw_cache (sub_font->scaled_font);
515
	return status;
516
    }
517

            
518
    x_advance = scaled_glyph->metrics.x_advance;
519
    y_advance = scaled_glyph->metrics.y_advance;
520
    _cairo_scaled_font_thaw_cache (sub_font->scaled_font);
521

            
522
    if (!is_latin && sub_font->num_glyphs_in_current_subset == sub_font->max_glyphs_per_subset)
523
    {
524
	sub_font->current_subset++;
525
	sub_font->num_glyphs_in_current_subset = 0;
526
    }
527

            
528
    if (is_latin)
529
	num_glyphs_in_subset_ptr = &sub_font->num_glyphs_in_latin_subset;
530
    else
531
	num_glyphs_in_subset_ptr = &sub_font->num_glyphs_in_current_subset;
532

            
533
    if ((*num_glyphs_in_subset_ptr == 0) && sub_font->reserve_notdef)
534
	(*num_glyphs_in_subset_ptr)++;
535

            
536
    sub_font_glyph = _cairo_sub_font_glyph_create (scaled_font_glyph_index,
537
						   is_latin ? 0 : sub_font->current_subset,
538
						   *num_glyphs_in_subset_ptr,
539
						   x_advance,
540
						   y_advance,
541
						   is_latin ? latin_character : -1,
542
						   unicode,
543
						   utf8,
544
						   utf8_len);
545

            
546
    if (unlikely (sub_font_glyph == NULL))
547
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
548

            
549
    status = _cairo_hash_table_insert (sub_font->sub_font_glyphs, &sub_font_glyph->base);
550
    if (unlikely (status)) {
551
	_cairo_sub_font_glyph_destroy (sub_font_glyph);
552
	return status;
553
    }
554

            
555
    (*num_glyphs_in_subset_ptr)++;
556
    if (sub_font->is_scaled) {
557
	if (*num_glyphs_in_subset_ptr > sub_font->parent->max_glyphs_per_scaled_subset_used)
558
	    sub_font->parent->max_glyphs_per_scaled_subset_used = *num_glyphs_in_subset_ptr;
559
    } else {
560
	if (*num_glyphs_in_subset_ptr > sub_font->parent->max_glyphs_per_unscaled_subset_used)
561
	    sub_font->parent->max_glyphs_per_unscaled_subset_used = *num_glyphs_in_subset_ptr;
562
    }
563

            
564
    *sub_font_glyph_out = sub_font_glyph;
565

            
566
    return CAIRO_STATUS_SUCCESS;
567
}
568

            
569
static cairo_status_t
570
_cairo_sub_font_map_glyph (cairo_sub_font_t	*sub_font,
571
			   unsigned long	 scaled_font_glyph_index,
572
			   const char		*text_utf8,
573
			   int			 text_utf8_len,
574
                           cairo_scaled_font_subsets_glyph_t *subset_glyph)
575
{
576
    cairo_sub_font_glyph_t key, *sub_font_glyph;
577
    cairo_status_t status;
578

            
579
    _cairo_sub_font_glyph_init_key (&key, scaled_font_glyph_index);
580
    sub_font_glyph = _cairo_hash_table_lookup (sub_font->sub_font_glyphs,
581
					       &key.base);
582
    if (sub_font_glyph == NULL) {
583
	uint32_t font_unicode;
584
	char *font_utf8;
585
	int font_utf8_len;
586
	cairo_bool_t is_latin;
587
	int latin_character;
588

            
589
	status = _cairo_sub_font_glyph_lookup_unicode (sub_font->scaled_font,
590
							   scaled_font_glyph_index,
591
							   &font_unicode,
592
							   &font_utf8,
593
							   &font_utf8_len);
594
	if (unlikely(status))
595
	    return status;
596

            
597
	/* If the supplied utf8 is a valid single character, use it
598
	 * instead of the font lookup */
599
	if (text_utf8 != NULL && text_utf8_len > 0) {
600
	    uint32_t  *ucs4;
601
	    int	ucs4_len;
602

            
603
	    status = _cairo_utf8_to_ucs4 (text_utf8, text_utf8_len,
604
					  &ucs4, &ucs4_len);
605
	    if (status == CAIRO_STATUS_SUCCESS) {
606
		if (ucs4_len == 1) {
607
		    font_unicode = ucs4[0];
608
		    free (font_utf8);
609
                    font_utf8 = _cairo_strndup (text_utf8, text_utf8_len);
610
                    if (font_utf8 == NULL) {
611
                        free (ucs4);
612
                        return _cairo_error (CAIRO_STATUS_NO_MEMORY);
613
		    }
614
		    font_utf8_len = text_utf8_len;
615
		}
616
		free (ucs4);
617
	    }
618
	}
619

            
620
	/* If glyph is in the winansi encoding and font is not a scaled
621
	 * font, put glyph in the latin subset. */
622
	is_latin = FALSE;
623
	latin_character = -1;
624
	if (sub_font->use_latin_subset && !sub_font->is_scaled)
625
	{
626
	    latin_character = _cairo_unicode_to_winansi (font_unicode);
627
	    if (latin_character > 0)
628
	    {
629
		if (!sub_font->latin_char_map[latin_character]) {
630
		    sub_font->latin_char_map[latin_character] = TRUE;
631
		    is_latin = TRUE;
632
		}
633
	    }
634
	}
635

            
636
	status = _cairo_sub_font_add_glyph (sub_font,
637
					    scaled_font_glyph_index,
638
					    is_latin,
639
					    latin_character,
640
					    font_unicode,
641
					    font_utf8,
642
					    font_utf8_len,
643
					    &sub_font_glyph);
644
	if (unlikely(status))
645
	    return status;
646
    }
647

            
648
    subset_glyph->font_id = sub_font->font_id;
649
    subset_glyph->subset_id = sub_font_glyph->subset_id;
650
    if (sub_font_glyph->is_latin)
651
	subset_glyph->subset_glyph_index = sub_font_glyph->latin_character;
652
    else
653
	subset_glyph->subset_glyph_index = sub_font_glyph->subset_glyph_index;
654

            
655
    subset_glyph->is_scaled = sub_font->is_scaled;
656
    subset_glyph->is_composite = sub_font->is_composite;
657
    subset_glyph->is_latin = sub_font_glyph->is_latin;
658
    subset_glyph->x_advance = sub_font_glyph->x_advance;
659
    subset_glyph->y_advance = sub_font_glyph->y_advance;
660
    status = _cairo_sub_font_glyph_map_to_unicode (sub_font_glyph,
661
						   text_utf8, text_utf8_len,
662
						   &subset_glyph->utf8_is_mapped);
663
    subset_glyph->unicode = sub_font_glyph->unicode;
664

            
665
    return status;
666
}
667

            
668
static void
669
_cairo_sub_font_collect (void *entry, void *closure)
670
{
671
    cairo_sub_font_t *sub_font = entry;
672
    cairo_sub_font_collection_t *collection = closure;
673
    cairo_scaled_font_subset_t subset;
674
    int i;
675
    unsigned int j;
676

            
677
    if (collection->status)
678
	return;
679

            
680
    collection->status = sub_font->scaled_font->status;
681
    if (collection->status)
682
	return;
683

            
684
    for (i = 0; i <= sub_font->current_subset; i++) {
685
	collection->subset_id = i;
686
	collection->num_glyphs = 0;
687
	collection->max_glyph = 0;
688
	memset (collection->latin_to_subset_glyph_index, 0, 256*sizeof(unsigned long));
689

            
690
	if (sub_font->reserve_notdef) {
691
	    // add .notdef
692
	    collection->glyphs[0] = 0;
693
	    collection->utf8[0] = 0;
694
	    collection->to_latin_char[0] = 0;
695
	    collection->latin_to_subset_glyph_index[0] = 0;
696
	    collection->num_glyphs++;
697
	}
698

            
699
	_cairo_hash_table_foreach (sub_font->sub_font_glyphs,
700
				   _cairo_sub_font_glyph_collect, collection);
701
	if (collection->status)
702
	    break;
703

            
704
	if (collection->num_glyphs == 0)
705
	    continue;
706

            
707
	if (sub_font->reserve_notdef && collection->num_glyphs == 1)
708
	    continue;
709

            
710
        /* Ensure the resulting array has no uninitialized holes */
711
	assert (collection->num_glyphs == collection->max_glyph + 1);
712

            
713
	subset.scaled_font = sub_font->scaled_font;
714
	subset.is_composite = sub_font->is_composite;
715
	subset.is_scaled = sub_font->is_scaled;
716
	subset.font_id = sub_font->font_id;
717
	subset.subset_id = i;
718
	subset.glyphs = collection->glyphs;
719
	subset.utf8 = collection->utf8;
720
	subset.num_glyphs = collection->num_glyphs;
721
        subset.glyph_names = NULL;
722

            
723
	subset.is_latin = FALSE;
724
	if (sub_font->use_latin_subset && i == 0) {
725
	    subset.is_latin = TRUE;
726
	    subset.to_latin_char = collection->to_latin_char;
727
	    subset.latin_to_subset_glyph_index = collection->latin_to_subset_glyph_index;
728
	} else {
729
	    subset.to_latin_char = NULL;
730
	    subset.latin_to_subset_glyph_index = NULL;
731
	}
732

            
733
        collection->status = (collection->font_subset_callback) (&subset,
734
					    collection->font_subset_callback_closure);
735

            
736
	if (subset.glyph_names != NULL) {
737
            for (j = 0; j < collection->num_glyphs; j++)
738
		free (subset.glyph_names[j]);
739
	    free (subset.glyph_names);
740
	}
741

            
742
	if (collection->status)
743
	    break;
744
    }
745
}
746

            
747
static cairo_scaled_font_subsets_t *
748
15
_cairo_scaled_font_subsets_create_internal (cairo_subsets_type_t type)
749
{
750
    cairo_scaled_font_subsets_t *subsets;
751

            
752
15
    subsets = _cairo_calloc (sizeof (cairo_scaled_font_subsets_t));
753
15
    if (unlikely (subsets == NULL)) {
754
	_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
755
	return NULL;
756
    }
757

            
758
15
    subsets->type = type;
759
15
    subsets->use_latin_subset = FALSE;
760
15
    subsets->max_glyphs_per_unscaled_subset_used = 0;
761
15
    subsets->max_glyphs_per_scaled_subset_used = 0;
762
15
    subsets->num_sub_fonts = 0;
763

            
764
15
    subsets->unscaled_sub_fonts = _cairo_hash_table_create (_cairo_sub_fonts_equal);
765
15
    if (! subsets->unscaled_sub_fonts) {
766
	free (subsets);
767
	return NULL;
768
    }
769
15
    subsets->unscaled_sub_fonts_list = NULL;
770
15
    subsets->unscaled_sub_fonts_list_end = NULL;
771

            
772
15
    subsets->scaled_sub_fonts = _cairo_hash_table_create (_cairo_sub_fonts_equal);
773
15
    if (! subsets->scaled_sub_fonts) {
774
	_cairo_hash_table_destroy (subsets->unscaled_sub_fonts);
775
	free (subsets);
776
	return NULL;
777
    }
778
15
    subsets->scaled_sub_fonts_list = NULL;
779
15
    subsets->scaled_sub_fonts_list_end = NULL;
780

            
781
15
    return subsets;
782
}
783

            
784
cairo_scaled_font_subsets_t *
785
5
_cairo_scaled_font_subsets_create_scaled (void)
786
{
787
5
    return _cairo_scaled_font_subsets_create_internal (CAIRO_SUBSETS_SCALED);
788
}
789

            
790
cairo_scaled_font_subsets_t *
791
5
_cairo_scaled_font_subsets_create_simple (void)
792
{
793
5
    return _cairo_scaled_font_subsets_create_internal (CAIRO_SUBSETS_SIMPLE);
794
}
795

            
796
cairo_scaled_font_subsets_t *
797
5
_cairo_scaled_font_subsets_create_composite (void)
798
{
799
5
    return _cairo_scaled_font_subsets_create_internal (CAIRO_SUBSETS_COMPOSITE);
800
}
801

            
802
void
803
15
_cairo_scaled_font_subsets_destroy (cairo_scaled_font_subsets_t *subsets)
804
{
805
15
    _cairo_hash_table_foreach (subsets->scaled_sub_fonts, _cairo_sub_font_pluck, subsets->scaled_sub_fonts);
806
15
    _cairo_hash_table_destroy (subsets->scaled_sub_fonts);
807

            
808
15
    _cairo_hash_table_foreach (subsets->unscaled_sub_fonts, _cairo_sub_font_pluck, subsets->unscaled_sub_fonts);
809
15
    _cairo_hash_table_destroy (subsets->unscaled_sub_fonts);
810

            
811
15
    free (subsets);
812
15
}
813

            
814
void
815
10
_cairo_scaled_font_subsets_enable_latin_subset (cairo_scaled_font_subsets_t *font_subsets,
816
						cairo_bool_t                 use_latin)
817
{
818
10
    font_subsets->use_latin_subset = use_latin;
819
10
}
820

            
821
cairo_status_t
822
_cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t	*subsets,
823
				      cairo_scaled_font_t		*scaled_font,
824
				      unsigned long			 scaled_font_glyph_index,
825
				      const char *			 utf8,
826
				      int				 utf8_len,
827
                                      cairo_scaled_font_subsets_glyph_t *subset_glyph)
828
{
829
    cairo_sub_font_t key, *sub_font;
830
    cairo_scaled_glyph_t *scaled_glyph;
831
    cairo_font_face_t *font_face;
832
    cairo_matrix_t identity;
833
    cairo_font_options_t font_options;
834
    cairo_scaled_font_t	*unscaled_font;
835
    cairo_int_status_t status;
836
    int max_glyphs;
837
    cairo_bool_t type1_font;
838
    cairo_bool_t has_path;
839
    cairo_bool_t has_color;
840
    cairo_bool_t is_user;
841

            
842
    /* Lookup glyph in unscaled subsets */
843
    if (subsets->type != CAIRO_SUBSETS_SCALED) {
844
        key.is_scaled = FALSE;
845
        _cairo_sub_font_init_key (&key, scaled_font);
846
	sub_font = _cairo_hash_table_lookup (subsets->unscaled_sub_fonts,
847
					     &key.base);
848
        if (sub_font != NULL) {
849
            status = _cairo_sub_font_lookup_glyph (sub_font,
850
						   scaled_font_glyph_index,
851
						   utf8, utf8_len,
852
						   subset_glyph);
853
	    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
854
                return status;
855
        }
856
    }
857

            
858
    /* Lookup glyph in scaled subsets */
859
    key.is_scaled = TRUE;
860
    _cairo_sub_font_init_key (&key, scaled_font);
861
    sub_font = _cairo_hash_table_lookup (subsets->scaled_sub_fonts,
862
					 &key.base);
863
    if (sub_font != NULL) {
864
	status = _cairo_sub_font_lookup_glyph (sub_font,
865
					       scaled_font_glyph_index,
866
					       utf8, utf8_len,
867
					       subset_glyph);
868
	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
869
	    return status;
870
    }
871

            
872
    /* Glyph not found. Determine whether the glyph is outline or
873
     * bitmap and add to the appropriate subset.
874
     */
875
    is_user = _cairo_font_face_is_user (scaled_font->font_face);
876
    _cairo_scaled_font_freeze_cache (scaled_font);
877
    /* Check if glyph is color */
878
    status = _cairo_scaled_glyph_lookup (scaled_font,
879
					 scaled_font_glyph_index,
880
					 CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE,
881
					 NULL, /* foreground color */
882
					 &scaled_glyph);
883
    has_color = (status == CAIRO_INT_STATUS_SUCCESS);
884

            
885
    /* Check if glyph has a path */
886
    status = _cairo_scaled_glyph_lookup (scaled_font,
887
					 scaled_font_glyph_index,
888
					 CAIRO_SCALED_GLYPH_INFO_PATH,
889
					 NULL, /* foreground color */
890
					 &scaled_glyph);
891
    has_path = (status == CAIRO_INT_STATUS_SUCCESS);
892

            
893
    /* glyph_index 0 (the .notdef glyph) is a special case. Some fonts
894
     * will return CAIRO_INT_STATUS_UNSUPPORTED when doing a
895
     * _scaled_glyph_lookup(_GLYPH_INFO_PATH). Type1-fallback creates
896
     * empty glyphs in this case so we can put the glyph in a unscaled
897
     * subset.
898
     */
899
    if (scaled_font_glyph_index == 0 && !is_user)
900
        has_path = TRUE;
901

            
902
    /* If this fails there is nothing we can do with this glyph. */
903
    status = _cairo_scaled_glyph_lookup (scaled_font,
904
					 scaled_font_glyph_index,
905
					 CAIRO_SCALED_GLYPH_INFO_SURFACE,
906
                                             NULL, /* foreground color */
907
					 &scaled_glyph);
908
    _cairo_scaled_font_thaw_cache (scaled_font);
909
    if (_cairo_int_status_is_error (status))
910
        return status;
911

            
912
    /* Type 3 glyphs (is_user and has_color) must be added to scaled subset */
913
    if (subsets->type != CAIRO_SUBSETS_SCALED &&
914
	has_path && !has_color && !is_user)
915
    {
916
        /* Path available. Add to unscaled subset. */
917
        key.is_scaled = FALSE;
918
        _cairo_sub_font_init_key (&key, scaled_font);
919
	sub_font = _cairo_hash_table_lookup (subsets->unscaled_sub_fonts,
920
					     &key.base);
921
        if (sub_font == NULL) {
922
            font_face = cairo_scaled_font_get_font_face (scaled_font);
923
            cairo_matrix_init_identity (&identity);
924
            _cairo_font_options_init_default (&font_options);
925
            cairo_scaled_font_get_font_options (scaled_font, &font_options);
926
            cairo_font_options_set_hint_style (&font_options, CAIRO_HINT_STYLE_NONE);
927
            cairo_font_options_set_hint_metrics (&font_options, CAIRO_HINT_METRICS_OFF);
928
            unscaled_font = cairo_scaled_font_create (font_face,
929
                                                      &identity,
930
                                                      &identity,
931
                                                      &font_options);
932
	    if (unlikely (unscaled_font->status))
933
		return unscaled_font->status;
934

            
935
            subset_glyph->is_scaled = FALSE;
936
            type1_font = _cairo_type1_scaled_font_is_type1 (unscaled_font);
937
            if (subsets->type == CAIRO_SUBSETS_COMPOSITE && !type1_font) {
938
                max_glyphs = MAX_GLYPHS_PER_COMPOSITE_FONT;
939
                subset_glyph->is_composite = TRUE;
940
            } else {
941
                max_glyphs = MAX_GLYPHS_PER_SIMPLE_FONT;
942
                subset_glyph->is_composite = FALSE;
943
            }
944

            
945
            status = _cairo_sub_font_create (subsets,
946
					     unscaled_font,
947
					     subsets->num_sub_fonts,
948
					     max_glyphs,
949
					     subset_glyph->is_scaled,
950
					     subset_glyph->is_composite,
951
					     &sub_font);
952

            
953
            if (unlikely (status)) {
954
		cairo_scaled_font_destroy (unscaled_font);
955
                return status;
956
	    }
957

            
958
            status = _cairo_hash_table_insert (subsets->unscaled_sub_fonts,
959
                                               &sub_font->base);
960

            
961
            if (unlikely (status)) {
962
		_cairo_sub_font_destroy (sub_font);
963
                return status;
964
	    }
965
	    if (!subsets->unscaled_sub_fonts_list)
966
		subsets->unscaled_sub_fonts_list = sub_font;
967
	    else
968
		subsets->unscaled_sub_fonts_list_end->next = sub_font;
969
	    subsets->unscaled_sub_fonts_list_end = sub_font;
970
	    subsets->num_sub_fonts++;
971
        }
972
    } else {
973
        /* No path available. Add to scaled subset. */
974
        key.is_scaled = TRUE;
975
        _cairo_sub_font_init_key (&key, scaled_font);
976
	sub_font = _cairo_hash_table_lookup (subsets->scaled_sub_fonts,
977
					     &key.base);
978
        if (sub_font == NULL) {
979
            subset_glyph->is_scaled = TRUE;
980
            subset_glyph->is_composite = FALSE;
981
            if (subsets->type == CAIRO_SUBSETS_SCALED)
982
                max_glyphs = INT_MAX;
983
            else
984
                max_glyphs = MAX_GLYPHS_PER_SIMPLE_FONT;
985

            
986
            status = _cairo_sub_font_create (subsets,
987
					     cairo_scaled_font_reference (scaled_font),
988
					     subsets->num_sub_fonts,
989
					     max_glyphs,
990
					     subset_glyph->is_scaled,
991
					     subset_glyph->is_composite,
992
					     &sub_font);
993
            if (unlikely (status)) {
994
		cairo_scaled_font_destroy (scaled_font);
995
                return status;
996
	    }
997

            
998
            status = _cairo_hash_table_insert (subsets->scaled_sub_fonts,
999
                                               &sub_font->base);
            if (unlikely (status)) {
		_cairo_sub_font_destroy (sub_font);
                return status;
	    }
	    if (!subsets->scaled_sub_fonts_list)
		subsets->scaled_sub_fonts_list = sub_font;
	    else
		subsets->scaled_sub_fonts_list_end->next = sub_font;
	    subsets->scaled_sub_fonts_list_end = sub_font;
	    subsets->num_sub_fonts++;
        }
    }
    return _cairo_sub_font_map_glyph (sub_font,
				      scaled_font_glyph_index,
				      utf8, utf8_len,
				      subset_glyph);
}
static cairo_status_t
25
_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)
{
    cairo_sub_font_collection_t collection;
    cairo_sub_font_t *sub_font;
    cairo_bool_t is_scaled;
25
    is_scaled = FALSE;
25
    if (type == CAIRO_SUBSETS_FOREACH_SCALED)
15
	is_scaled = TRUE;
25
    if (is_scaled)
15
        collection.glyphs_size = font_subsets->max_glyphs_per_scaled_subset_used;
    else
10
        collection.glyphs_size = font_subsets->max_glyphs_per_unscaled_subset_used;
25
    if (! collection.glyphs_size)
25
	return CAIRO_STATUS_SUCCESS;
    collection.glyphs = _cairo_malloc_ab (collection.glyphs_size, sizeof(unsigned long));
    collection.utf8 = _cairo_malloc_ab (collection.glyphs_size, sizeof(char *));
    collection.to_latin_char = _cairo_malloc_ab (collection.glyphs_size, sizeof(int));
    collection.latin_to_subset_glyph_index = _cairo_malloc_ab (256, sizeof(unsigned long));
    if (unlikely (collection.glyphs == NULL ||
		  collection.utf8 == NULL ||
		  collection.to_latin_char == NULL ||
		  collection.latin_to_subset_glyph_index == NULL)) {
	free (collection.glyphs);
	free (collection.utf8);
	free (collection.to_latin_char);
	free (collection.latin_to_subset_glyph_index);
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    }
    collection.font_subset_callback = font_subset_callback;
    collection.font_subset_callback_closure = closure;
    collection.status = CAIRO_STATUS_SUCCESS;
    if (is_scaled)
	sub_font = font_subsets->scaled_sub_fonts_list;
    else
	sub_font = font_subsets->unscaled_sub_fonts_list;
    while (sub_font) {
	_cairo_sub_font_collect (sub_font, &collection);
	sub_font = sub_font->next;
    }
    free (collection.utf8);
    free (collection.glyphs);
    free (collection.to_latin_char);
    free (collection.latin_to_subset_glyph_index);
    return collection.status;
}
cairo_status_t
15
_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)
{
15
    return _cairo_scaled_font_subsets_foreach_internal (font_subsets,
                                                        font_subset_callback,
                                                        closure,
							CAIRO_SUBSETS_FOREACH_SCALED);
}
cairo_status_t
10
_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)
{
10
    return _cairo_scaled_font_subsets_foreach_internal (font_subsets,
                                                        font_subset_callback,
                                                        closure,
							CAIRO_SUBSETS_FOREACH_UNSCALED);
}
static cairo_bool_t
_cairo_string_equal (const void *key_a, const void *key_b)
{
    const cairo_string_entry_t *a = key_a;
    const cairo_string_entry_t *b = key_b;
    if (strcmp (a->string, b->string) == 0)
	return TRUE;
    else
	return FALSE;
}
#if DEBUG_SUBSETS
static void
dump_glyph (void *entry, void *closure)
{
    cairo_sub_font_glyph_t *glyph = entry;
    char buf[10];
    int i;
    printf("    font_glyph_index: %ld\n", glyph->base.hash);
    printf("      subset_id: %d\n", glyph->subset_id);
    printf("      subset_glyph_index: %d\n", glyph->subset_glyph_index);
    printf("      x_advance: %f\n", glyph->x_advance);
    printf("      y_advance: %f\n", glyph->y_advance);
    printf("      is_latin: %d\n", glyph->is_latin);
    printf("      latin_character: '%c' (0x%02x)\n", glyph->latin_character, glyph->latin_character);
    printf("      is_latin: %d\n", glyph->is_latin);
    printf("      is_mapped: %d\n", glyph->is_mapped);
    printf("      unicode: U+%04x\n", glyph->unicode);
    memset(buf, 0, sizeof(buf));
    memcpy(buf, glyph->utf8, glyph->utf8_len);
    printf("      utf8: '%s'\n", buf);
    printf("      utf8 (hex):");
    for (i = 0; i < glyph->utf8_len; i++)
	printf(" 0x%02x", glyph->utf8[i]);
    printf("\n\n");
}
static void
dump_subfont (cairo_sub_font_t *sub_font)
{
    while (sub_font) {
	printf("    font_id: %d\n", sub_font->font_id);
	printf("    current_subset: %d\n", sub_font->current_subset);
	printf("    is_scaled: %d\n", sub_font->is_scaled);
	printf("    is_composite: %d\n", sub_font->is_composite);
	printf("    is_user: %d\n", sub_font->is_user);
	printf("    use_latin_subset: %d\n", sub_font->use_latin_subset);
	printf("    reserve_notdef: %d\n", sub_font->reserve_notdef);
	printf("    num_glyphs_in_current_subset: %d\n", sub_font->num_glyphs_in_current_subset);
	printf("    num_glyphs_in_latin_subset: %d\n", sub_font->num_glyphs_in_latin_subset);
	printf("    max_glyphs_per_subset: %d\n\n", sub_font->max_glyphs_per_subset);
	_cairo_hash_table_foreach (sub_font->sub_font_glyphs, dump_glyph, NULL);
	printf("\n");
	sub_font = sub_font->next;
    }
}
void
dump_scaled_font_subsets (cairo_scaled_font_subsets_t *font_subsets)
{
    printf("font subsets\n");
    switch (font_subsets->type)
    {
	case CAIRO_SUBSETS_SCALED:
	    printf("  type: CAIRO_SUBSETS_SCALED\n");
	    break;
	case CAIRO_SUBSETS_SIMPLE:
	    printf("  type: CAIRO_SUBSETS_SIMPLE\n");
	    break;
	case CAIRO_SUBSETS_COMPOSITE:
	    printf("  type: CAIRO_SUBSETS_COMPOSITE\n");
	    break;
    }
    printf("  use_latin_subset: %d\n", font_subsets->use_latin_subset);
    printf("  max_glyphs_per_unscaled_subset_used: %d\n", font_subsets->max_glyphs_per_unscaled_subset_used);
    printf("  max_glyphs_per_scaled_subset_used: %d\n", font_subsets->max_glyphs_per_scaled_subset_used);
    printf("  num_sub_fonts: %d\n\n", font_subsets->num_sub_fonts);
    printf("  scaled subsets:\n");
    dump_subfont (font_subsets->scaled_sub_fonts_list);
    printf("\n  unscaled subsets:\n");
    dump_subfont (font_subsets->unscaled_sub_fonts_list);
}
#endif
static void
_cairo_string_init_key (cairo_string_entry_t *key, char *s)
{
    unsigned long sum = 0;
    unsigned int i;
    for (i = 0; i < strlen(s); i++)
        sum += s[i];
    key->base.hash = sum;
    key->string = s;
}
static cairo_status_t
create_string_entry (char *s, cairo_string_entry_t **entry)
{
    *entry = _cairo_calloc (sizeof (cairo_string_entry_t));
    if (unlikely (*entry == NULL))
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    _cairo_string_init_key (*entry, s);
    return CAIRO_STATUS_SUCCESS;
}
static void
_pluck_entry (void *entry, void *closure)
{
    _cairo_hash_table_remove (closure, entry);
    free (entry);
}
cairo_int_status_t
_cairo_scaled_font_subset_create_glyph_names (cairo_scaled_font_subset_t *subset)
{
    unsigned int i;
    cairo_hash_table_t *names;
    cairo_string_entry_t key, *entry;
    char buf[30];
    char *utf8;
    uint16_t *utf16;
    int utf16_len;
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
    names = _cairo_hash_table_create (_cairo_string_equal);
    if (unlikely (names == NULL))
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    subset->glyph_names = _cairo_calloc_ab (subset->num_glyphs, sizeof (char *));
    if (unlikely (subset->glyph_names == NULL)) {
	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
	goto CLEANUP_HASH;
    }
    i = 0;
    if (! subset->is_scaled) {
	subset->glyph_names[0] = strdup (".notdef");
	if (unlikely (subset->glyph_names[0] == NULL)) {
	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
	    goto CLEANUP_HASH;
	}
	status = create_string_entry (subset->glyph_names[0], &entry);
	if (unlikely (status))
	    goto CLEANUP_HASH;
	status = _cairo_hash_table_insert (names, &entry->base);
	if (unlikely (status)) {
	    free (entry);
	    goto CLEANUP_HASH;
	}
	i++;
    }
    for (; i < subset->num_glyphs; i++) {
	utf8 = subset->utf8[i];
	utf16 = NULL;
	utf16_len = 0;
	if (utf8 && *utf8) {
	    status = _cairo_utf8_to_utf16 (utf8, -1, &utf16, &utf16_len);
	    if (status == CAIRO_STATUS_INVALID_STRING) {
		utf16 = NULL;
		utf16_len = 0;
	    } else if (unlikely (status)) {
		goto CLEANUP_HASH;
	    }
	}
	if (utf16_len == 1) {
	    int ch = _cairo_unicode_to_winansi (utf16[0]);
	    if (ch > 0 && _cairo_winansi_to_glyphname (ch)) {
		strncpy (buf, _cairo_winansi_to_glyphname (ch), sizeof (buf));
		buf[sizeof (buf)-1] = '\0';
	    } else {
		snprintf (buf, sizeof (buf), "uni%04X", (int) utf16[0]);
	    }
	    _cairo_string_init_key (&key, buf);
	    entry = _cairo_hash_table_lookup (names, &key.base);
	    if (entry != NULL)
		snprintf (buf, sizeof (buf), "g%d", i);
	} else {
	    snprintf (buf, sizeof (buf), "g%d", i);
	}
	free (utf16);
	subset->glyph_names[i] = strdup (buf);
	if (unlikely (subset->glyph_names[i] == NULL)) {
	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
	    goto CLEANUP_HASH;
	}
	status = create_string_entry (subset->glyph_names[i], &entry);
	if (unlikely (status))
	    goto CLEANUP_HASH;
	status = _cairo_hash_table_insert (names, &entry->base);
	if (unlikely (status)) {
	    free (entry);
	    goto CLEANUP_HASH;
	}
    }
CLEANUP_HASH:
    _cairo_hash_table_foreach (names, _pluck_entry, names);
    _cairo_hash_table_destroy (names);
    if (likely (status == CAIRO_STATUS_SUCCESS))
	return CAIRO_STATUS_SUCCESS;
    if (subset->glyph_names != NULL) {
	for (i = 0; i < subset->num_glyphs; i++) {
	    free (subset->glyph_names[i]);
	}
	free (subset->glyph_names);
	subset->glyph_names = NULL;
    }
    return status;
}
cairo_int_status_t
_cairo_escape_ps_name (char **ps_name)
{
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
    /* Ensure PS name is a valid PDF/PS name object. In PDF names are
     * treated as UTF8 and non ASCII bytes, ' ', and '#' are encoded
     * as '#' followed by 2 hex digits that encode the byte. By also
     * encoding the characters in the reserved string we ensure the
     * name is also PS compatible. */
    if (*ps_name) {
	static const char *reserved = "()<>[]{}/%#\\";
	char buf[128]; /* max name length is 127 bytes */
	char *src = *ps_name;
	char *dst = buf;
	while (*src && dst < buf + 127) {
	    unsigned char c = *src;
	    if (c < 0x21 || c > 0x7e || strchr (reserved, c)) {
		if (dst + 4 > buf + 127)
		    break;
		snprintf (dst, 4, "#%02X", c);
		src++;
		dst += 3;
	    } else {
		*dst++ = *src++;
	    }
	}
	*dst = 0;
	free (*ps_name);
	*ps_name = strdup (buf);
	if (*ps_name == NULL) {
	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
	}
    }
    return status;
}
#endif /* CAIRO_HAS_FONT_SUBSET */