Subversion Repositories Kolibri OS

Rev

Rev 1897 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1897 serge 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 
38
 *	Kristian Høgsberg 
39
 *	Keith Packard 
40
 *	Adrian Johnson 
41
 */
42
 
43
#define _BSD_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;
3959 Serge 73
    cairo_bool_t use_latin_subset;
1897 serge 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;
3959 Serge 80
    int num_glyphs_in_latin_subset;
1897 serge 81
    int max_glyphs_per_subset;
3959 Serge 82
    char latin_char_map[256];
1897 serge 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;
3959 Serge 90
    cairo_bool_t use_latin_subset;
1897 serge 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
 
3959 Serge 113
    cairo_bool_t is_latin;
114
    int		 latin_character;
1897 serge 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;
3959 Serge 125
    int           *to_latin_char;
126
    unsigned long *latin_to_subset_glyph_index;
1897 serge 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,
3959 Serge 161
                              double            y_advance,
162
			      int	        latin_character,
163
			      uint32_t          unicode,
164
			      char             *utf8,
165
			      int          	utf8_len)
1897 serge 166
{
167
    cairo_sub_font_glyph_t *sub_font_glyph;
168
 
169
    sub_font_glyph = malloc (sizeof (cairo_sub_font_glyph_t));
170
    if (unlikely (sub_font_glyph == NULL)) {
171
	_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
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;
3959 Serge 180
    sub_font_glyph->is_latin = (latin_character >= 0);
181
    sub_font_glyph->latin_character = latin_character;
1897 serge 182
    sub_font_glyph->is_mapped = FALSE;
3959 Serge 183
    sub_font_glyph->unicode = unicode;
184
    sub_font_glyph->utf8 = utf8;
185
    sub_font_glyph->utf8_len = utf8_len;
1897 serge 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
{
3959 Serge 193
    free (sub_font_glyph->utf8);
1897 serge 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;
3959 Serge 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
 
1897 serge 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 = (unsigned long) scaled_font;
258
        sub_font->scaled_font = scaled_font;
259
    }
260
    else
261
    {
262
        sub_font->base.hash = (unsigned long) 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;
3959 Serge 277
    int i;
1897 serge 278
 
279
    sub_font = malloc (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->is_user = _cairo_font_face_is_user (scaled_font->font_face);
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
 
3959 Serge 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_user || 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
 
1897 serge 306
    sub_font->num_glyphs_in_current_subset = 0;
3959 Serge 307
    sub_font->num_glyphs_in_latin_subset = 0;
1897 serge 308
    sub_font->max_glyphs_per_subset = max_glyphs_per_subset;
3959 Serge 309
    for (i = 0; i < 256; i++)
310
	sub_font->latin_char_map[i] = FALSE;
1897 serge 311
 
3959 Serge 312
    sub_font->sub_font_glyphs = _cairo_hash_table_create (NULL);
1897 serge 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
 
3959 Serge 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
 
1897 serge 370
static cairo_status_t
3959 Serge 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)
1897 serge 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
 
3959 Serge 399
    *unicode_out = unicode;
400
    *utf8_out = NULL;
401
    *utf8_len_out = 0;
1897 serge 402
    if (unicode != (uint32_t) -1) {
403
	len = _cairo_ucs4_to_utf8 (unicode, buf);
404
	if (len > 0) {
3959 Serge 405
	    *utf8_out = malloc (len + 1);
406
	    if (unlikely (*utf8_out == NULL))
1897 serge 407
		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
408
 
3959 Serge 409
	    memcpy (*utf8_out, buf, len);
410
	    (*utf8_out)[len] = 0;
411
	    *utf8_len_out = len;
1897 serge 412
	}
413
    }
414
 
415
    return CAIRO_STATUS_SUCCESS;
416
}
417
 
418
static cairo_status_t
419
_cairo_sub_font_glyph_map_to_unicode (cairo_sub_font_glyph_t *sub_font_glyph,
420
				      const char	     *utf8,
421
				      int		      utf8_len,
422
				      cairo_bool_t	     *is_mapped)
423
{
424
    *is_mapped = FALSE;
425
 
426
    if (utf8_len < 0)
427
	return CAIRO_STATUS_SUCCESS;
428
 
429
    if (utf8 != NULL && utf8_len != 0 && utf8[utf8_len - 1] == '\0')
430
	utf8_len--;
431
 
432
    if (utf8 != NULL && utf8_len != 0) {
433
	if (sub_font_glyph->utf8 != NULL) {
434
	    if (utf8_len == sub_font_glyph->utf8_len &&
435
		memcmp (utf8, sub_font_glyph->utf8, utf8_len) == 0)
436
	    {
437
		/* Requested utf8 mapping matches the existing mapping */
438
		*is_mapped = TRUE;
439
	    }
440
	} else {
441
	    /* No existing mapping. Use the requested mapping */
442
	    sub_font_glyph->utf8 = malloc (utf8_len + 1);
443
	    if (unlikely (sub_font_glyph->utf8 == NULL))
444
		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
445
 
446
	    memcpy (sub_font_glyph->utf8, utf8, utf8_len);
447
	    sub_font_glyph->utf8[utf8_len] = 0;
448
	    sub_font_glyph->utf8_len = utf8_len;
449
	    *is_mapped = TRUE;
450
	}
451
    }
452
 
453
    return CAIRO_STATUS_SUCCESS;
454
}
455
 
456
static cairo_int_status_t
457
_cairo_sub_font_lookup_glyph (cairo_sub_font_t	                *sub_font,
458
                              unsigned long	                 scaled_font_glyph_index,
459
			      const char			*utf8,
460
			      int				 utf8_len,
461
                              cairo_scaled_font_subsets_glyph_t *subset_glyph)
462
{
463
    cairo_sub_font_glyph_t key, *sub_font_glyph;
464
    cairo_int_status_t status;
465
 
466
    _cairo_sub_font_glyph_init_key (&key, scaled_font_glyph_index);
467
    sub_font_glyph = _cairo_hash_table_lookup (sub_font->sub_font_glyphs,
468
					      &key.base);
469
    if (sub_font_glyph != NULL) {
470
        subset_glyph->font_id = sub_font->font_id;
471
        subset_glyph->subset_id = sub_font_glyph->subset_id;
3959 Serge 472
	if (sub_font_glyph->is_latin)
473
	    subset_glyph->subset_glyph_index = sub_font_glyph->latin_character;
474
	else
475
	    subset_glyph->subset_glyph_index = sub_font_glyph->subset_glyph_index;
476
 
1897 serge 477
        subset_glyph->is_scaled = sub_font->is_scaled;
478
        subset_glyph->is_composite = sub_font->is_composite;
3959 Serge 479
	subset_glyph->is_latin = sub_font_glyph->is_latin;
1897 serge 480
        subset_glyph->x_advance = sub_font_glyph->x_advance;
481
        subset_glyph->y_advance = sub_font_glyph->y_advance;
482
	status = _cairo_sub_font_glyph_map_to_unicode (sub_font_glyph,
483
						       utf8, utf8_len,
484
						       &subset_glyph->utf8_is_mapped);
485
	subset_glyph->unicode = sub_font_glyph->unicode;
486
 
487
	return status;
488
    }
489
 
490
    return CAIRO_INT_STATUS_UNSUPPORTED;
491
}
492
 
493
static cairo_status_t
3959 Serge 494
_cairo_sub_font_add_glyph (cairo_sub_font_t	   *sub_font,
495
			   unsigned long	    scaled_font_glyph_index,
496
			   cairo_bool_t		    is_latin,
497
			   int			    latin_character,
498
			   uint32_t 		    unicode,
499
			   char 		   *utf8,
500
			   int 			    utf8_len,
501
			   cairo_sub_font_glyph_t **sub_font_glyph_out)
502
{
503
    cairo_scaled_glyph_t *scaled_glyph;
504
    cairo_sub_font_glyph_t *sub_font_glyph;
505
    int *num_glyphs_in_subset_ptr;
506
    double x_advance;
507
    double y_advance;
508
    cairo_int_status_t status;
509
 
510
    _cairo_scaled_font_freeze_cache (sub_font->scaled_font);
511
    status = _cairo_scaled_glyph_lookup (sub_font->scaled_font,
512
					 scaled_font_glyph_index,
513
					 CAIRO_SCALED_GLYPH_INFO_METRICS,
514
					 &scaled_glyph);
515
    assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
516
    if (unlikely (status)) {
517
	_cairo_scaled_font_thaw_cache (sub_font->scaled_font);
518
	return status;
519
    }
520
 
521
    x_advance = scaled_glyph->metrics.x_advance;
522
    y_advance = scaled_glyph->metrics.y_advance;
523
    _cairo_scaled_font_thaw_cache (sub_font->scaled_font);
524
 
525
    if (!is_latin && sub_font->num_glyphs_in_current_subset == sub_font->max_glyphs_per_subset)
526
    {
527
	sub_font->current_subset++;
528
	sub_font->num_glyphs_in_current_subset = 0;
529
    }
530
 
531
    if (is_latin)
532
	num_glyphs_in_subset_ptr = &sub_font->num_glyphs_in_latin_subset;
533
    else
534
	num_glyphs_in_subset_ptr = &sub_font->num_glyphs_in_current_subset;
535
 
536
    /* Reserve first glyph in subset for the .notdef glyph except for
537
     * Type 3 fonts */
538
    if (*num_glyphs_in_subset_ptr == 0 &&
539
	scaled_font_glyph_index != 0 &&
540
	! _cairo_font_face_is_user (sub_font->scaled_font->font_face))
541
    {
542
	status = _cairo_sub_font_add_glyph (sub_font,
543
					    0,
544
					    is_latin,
545
					    0,
546
					    0,
547
					    NULL,
548
					    -1,
549
					    &sub_font_glyph);
550
	if (unlikely (status))
551
	    return status;
552
    }
553
 
554
    sub_font_glyph = _cairo_sub_font_glyph_create (scaled_font_glyph_index,
555
						   is_latin ? 0 : sub_font->current_subset,
556
						   *num_glyphs_in_subset_ptr,
557
						   x_advance,
558
						   y_advance,
559
						   is_latin ? latin_character : -1,
560
						   unicode,
561
						   utf8,
562
						   utf8_len);
563
 
564
    if (unlikely (sub_font_glyph == NULL))
565
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
566
 
567
    status = _cairo_hash_table_insert (sub_font->sub_font_glyphs, &sub_font_glyph->base);
568
    if (unlikely (status)) {
569
	_cairo_sub_font_glyph_destroy (sub_font_glyph);
570
	return status;
571
    }
572
 
573
    (*num_glyphs_in_subset_ptr)++;
574
    if (sub_font->is_scaled) {
575
	if (*num_glyphs_in_subset_ptr > sub_font->parent->max_glyphs_per_scaled_subset_used)
576
	    sub_font->parent->max_glyphs_per_scaled_subset_used = *num_glyphs_in_subset_ptr;
577
    } else {
578
	if (*num_glyphs_in_subset_ptr > sub_font->parent->max_glyphs_per_unscaled_subset_used)
579
	    sub_font->parent->max_glyphs_per_unscaled_subset_used = *num_glyphs_in_subset_ptr;
580
    }
581
 
582
    *sub_font_glyph_out = sub_font_glyph;
583
 
584
    return CAIRO_STATUS_SUCCESS;
585
}
586
 
587
static cairo_status_t
1897 serge 588
_cairo_sub_font_map_glyph (cairo_sub_font_t	*sub_font,
589
			   unsigned long	 scaled_font_glyph_index,
3959 Serge 590
			   const char		*text_utf8,
591
			   int			 text_utf8_len,
1897 serge 592
                           cairo_scaled_font_subsets_glyph_t *subset_glyph)
593
{
594
    cairo_sub_font_glyph_t key, *sub_font_glyph;
595
    cairo_status_t status;
596
 
597
    _cairo_sub_font_glyph_init_key (&key, scaled_font_glyph_index);
598
    sub_font_glyph = _cairo_hash_table_lookup (sub_font->sub_font_glyphs,
599
					       &key.base);
600
    if (sub_font_glyph == NULL) {
3959 Serge 601
	uint32_t font_unicode;
602
	char *font_utf8;
603
	int font_utf8_len;
604
	cairo_bool_t is_latin;
605
	int latin_character;
1897 serge 606
 
3959 Serge 607
	status = _cairo_sub_font_glyph_lookup_unicode (sub_font->scaled_font,
608
							   scaled_font_glyph_index,
609
							   &font_unicode,
610
							   &font_utf8,
611
							   &font_utf8_len);
612
	if (unlikely(status))
613
	    return status;
1897 serge 614
 
3959 Serge 615
	/* If the supplied utf8 is a valid single character, use it
616
	 * instead of the font lookup */
617
	if (text_utf8 != NULL && text_utf8_len > 0) {
618
	    uint32_t  *ucs4;
619
	    int	ucs4_len;
1897 serge 620
 
3959 Serge 621
	    status = _cairo_utf8_to_ucs4 (text_utf8, text_utf8_len,
622
					  &ucs4, &ucs4_len);
623
	    if (status == CAIRO_STATUS_SUCCESS) {
624
		if (ucs4_len == 1) {
625
		    font_unicode = ucs4[0];
626
		    free (font_utf8);
627
		    font_utf8 = malloc (text_utf8_len + 1);
628
		    if (font_utf8 == NULL) {
629
			free (ucs4);
630
			return _cairo_error (CAIRO_STATUS_NO_MEMORY);
631
		    }
632
		    memcpy (font_utf8, text_utf8, text_utf8_len);
633
		    font_utf8[text_utf8_len] = 0;
634
		    font_utf8_len = text_utf8_len;
635
		}
636
		free (ucs4);
1897 serge 637
	    }
638
	}
639
 
3959 Serge 640
	/* If glyph is in the winansi encoding and font is not a user
641
	 * font, put glyph in the latin subset. If glyph is .notdef
642
	 * the latin subset is preferred but only if the latin subset
643
	 * already contains at least one glyph. We don't want to
644
	 * create a separate subset just for the .notdef glyph.
645
	 */
646
	is_latin = FALSE;
647
	latin_character = -1;
648
	if (sub_font->use_latin_subset &&
649
	    (! _cairo_font_face_is_user (sub_font->scaled_font->font_face)))
650
	{
651
	    latin_character = _cairo_unicode_to_winansi (font_unicode);
652
	    if (latin_character > 0 ||
653
		(latin_character == 0 && sub_font->num_glyphs_in_latin_subset > 0))
654
	    {
655
		if (!sub_font->latin_char_map[latin_character]) {
656
		    sub_font->latin_char_map[latin_character] = TRUE;
657
		    is_latin = TRUE;
658
		}
659
	    }
1897 serge 660
	}
661
 
3959 Serge 662
	status = _cairo_sub_font_add_glyph (sub_font,
663
					    scaled_font_glyph_index,
664
					    is_latin,
665
					    latin_character,
666
					    font_unicode,
667
					    font_utf8,
668
					    font_utf8_len,
669
					    &sub_font_glyph);
670
	if (unlikely(status))
1897 serge 671
	    return status;
672
    }
673
 
674
    subset_glyph->font_id = sub_font->font_id;
675
    subset_glyph->subset_id = sub_font_glyph->subset_id;
3959 Serge 676
    if (sub_font_glyph->is_latin)
677
	subset_glyph->subset_glyph_index = sub_font_glyph->latin_character;
678
    else
679
	subset_glyph->subset_glyph_index = sub_font_glyph->subset_glyph_index;
680
 
1897 serge 681
    subset_glyph->is_scaled = sub_font->is_scaled;
682
    subset_glyph->is_composite = sub_font->is_composite;
3959 Serge 683
    subset_glyph->is_latin = sub_font_glyph->is_latin;
1897 serge 684
    subset_glyph->x_advance = sub_font_glyph->x_advance;
685
    subset_glyph->y_advance = sub_font_glyph->y_advance;
686
    status = _cairo_sub_font_glyph_map_to_unicode (sub_font_glyph,
3959 Serge 687
						   text_utf8, text_utf8_len,
1897 serge 688
						   &subset_glyph->utf8_is_mapped);
689
    subset_glyph->unicode = sub_font_glyph->unicode;
690
 
691
    return status;
692
}
693
 
694
static void
695
_cairo_sub_font_collect (void *entry, void *closure)
696
{
697
    cairo_sub_font_t *sub_font = entry;
698
    cairo_sub_font_collection_t *collection = closure;
699
    cairo_scaled_font_subset_t subset;
700
    int i;
701
    unsigned int j;
702
 
703
    if (collection->status)
704
	return;
705
 
706
    collection->status = sub_font->scaled_font->status;
707
    if (collection->status)
708
	return;
709
 
710
    for (i = 0; i <= sub_font->current_subset; i++) {
711
	collection->subset_id = i;
712
	collection->num_glyphs = 0;
713
	collection->max_glyph = 0;
3959 Serge 714
	memset (collection->latin_to_subset_glyph_index, 0, 256*sizeof(unsigned long));
1897 serge 715
 
716
	_cairo_hash_table_foreach (sub_font->sub_font_glyphs,
717
				   _cairo_sub_font_glyph_collect, collection);
718
	if (collection->status)
719
	    break;
720
	if (collection->num_glyphs == 0)
721
	    continue;
722
 
723
        /* Ensure the resulting array has no uninitialized holes */
724
	assert (collection->num_glyphs == collection->max_glyph + 1);
725
 
726
	subset.scaled_font = sub_font->scaled_font;
727
	subset.is_composite = sub_font->is_composite;
728
	subset.is_scaled = sub_font->is_scaled;
729
	subset.font_id = sub_font->font_id;
730
	subset.subset_id = i;
731
	subset.glyphs = collection->glyphs;
732
	subset.utf8 = collection->utf8;
733
	subset.num_glyphs = collection->num_glyphs;
734
        subset.glyph_names = NULL;
3959 Serge 735
 
736
	subset.is_latin = FALSE;
737
	if (sub_font->use_latin_subset && i == 0) {
738
	    subset.is_latin = TRUE;
739
	    subset.to_latin_char = collection->to_latin_char;
740
	    subset.latin_to_subset_glyph_index = collection->latin_to_subset_glyph_index;
741
	} else {
742
	    subset.to_latin_char = NULL;
743
	    subset.latin_to_subset_glyph_index = NULL;
744
	}
745
 
1897 serge 746
        collection->status = (collection->font_subset_callback) (&subset,
747
					    collection->font_subset_callback_closure);
748
 
749
	if (subset.glyph_names != NULL) {
750
            for (j = 0; j < collection->num_glyphs; j++)
751
		free (subset.glyph_names[j]);
752
	    free (subset.glyph_names);
753
	}
754
 
755
	if (collection->status)
756
	    break;
757
    }
758
}
759
 
760
static cairo_scaled_font_subsets_t *
761
_cairo_scaled_font_subsets_create_internal (cairo_subsets_type_t type)
762
{
763
    cairo_scaled_font_subsets_t *subsets;
764
 
765
    subsets = malloc (sizeof (cairo_scaled_font_subsets_t));
766
    if (unlikely (subsets == NULL)) {
767
	_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
768
	return NULL;
769
    }
770
 
771
    subsets->type = type;
3959 Serge 772
    subsets->use_latin_subset = FALSE;
1897 serge 773
    subsets->max_glyphs_per_unscaled_subset_used = 0;
774
    subsets->max_glyphs_per_scaled_subset_used = 0;
775
    subsets->num_sub_fonts = 0;
776
 
777
    subsets->unscaled_sub_fonts = _cairo_hash_table_create (_cairo_sub_fonts_equal);
778
    if (! subsets->unscaled_sub_fonts) {
779
	free (subsets);
780
	return NULL;
781
    }
782
    subsets->unscaled_sub_fonts_list = NULL;
783
    subsets->unscaled_sub_fonts_list_end = NULL;
784
 
785
    subsets->scaled_sub_fonts = _cairo_hash_table_create (_cairo_sub_fonts_equal);
786
    if (! subsets->scaled_sub_fonts) {
787
	_cairo_hash_table_destroy (subsets->unscaled_sub_fonts);
788
	free (subsets);
789
	return NULL;
790
    }
791
    subsets->scaled_sub_fonts_list = NULL;
792
    subsets->scaled_sub_fonts_list_end = NULL;
793
 
794
    return subsets;
795
}
796
 
797
cairo_scaled_font_subsets_t *
798
_cairo_scaled_font_subsets_create_scaled (void)
799
{
800
    return _cairo_scaled_font_subsets_create_internal (CAIRO_SUBSETS_SCALED);
801
}
802
 
803
cairo_scaled_font_subsets_t *
804
_cairo_scaled_font_subsets_create_simple (void)
805
{
806
    return _cairo_scaled_font_subsets_create_internal (CAIRO_SUBSETS_SIMPLE);
807
}
808
 
809
cairo_scaled_font_subsets_t *
810
_cairo_scaled_font_subsets_create_composite (void)
811
{
812
    return _cairo_scaled_font_subsets_create_internal (CAIRO_SUBSETS_COMPOSITE);
813
}
814
 
815
void
816
_cairo_scaled_font_subsets_destroy (cairo_scaled_font_subsets_t *subsets)
817
{
818
    _cairo_hash_table_foreach (subsets->scaled_sub_fonts, _cairo_sub_font_pluck, subsets->scaled_sub_fonts);
819
    _cairo_hash_table_destroy (subsets->scaled_sub_fonts);
820
 
821
    _cairo_hash_table_foreach (subsets->unscaled_sub_fonts, _cairo_sub_font_pluck, subsets->unscaled_sub_fonts);
822
    _cairo_hash_table_destroy (subsets->unscaled_sub_fonts);
823
 
824
    free (subsets);
825
}
826
 
3959 Serge 827
void
828
_cairo_scaled_font_subsets_enable_latin_subset (cairo_scaled_font_subsets_t *font_subsets,
829
						cairo_bool_t                 use_latin)
830
{
831
    font_subsets->use_latin_subset = use_latin;
832
}
833
 
1897 serge 834
cairo_status_t
835
_cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t	*subsets,
836
				      cairo_scaled_font_t		*scaled_font,
837
				      unsigned long			 scaled_font_glyph_index,
838
				      const char *			 utf8,
839
				      int				 utf8_len,
840
                                      cairo_scaled_font_subsets_glyph_t *subset_glyph)
841
{
842
    cairo_sub_font_t key, *sub_font;
843
    cairo_scaled_glyph_t *scaled_glyph;
844
    cairo_font_face_t *font_face;
845
    cairo_matrix_t identity;
846
    cairo_font_options_t font_options;
847
    cairo_scaled_font_t	*unscaled_font;
3959 Serge 848
    cairo_int_status_t status;
1897 serge 849
    int max_glyphs;
850
    cairo_bool_t type1_font;
851
 
852
    /* Lookup glyph in unscaled subsets */
853
    if (subsets->type != CAIRO_SUBSETS_SCALED) {
854
        key.is_scaled = FALSE;
855
        _cairo_sub_font_init_key (&key, scaled_font);
856
	sub_font = _cairo_hash_table_lookup (subsets->unscaled_sub_fonts,
857
					     &key.base);
858
        if (sub_font != NULL) {
859
            status = _cairo_sub_font_lookup_glyph (sub_font,
860
						   scaled_font_glyph_index,
861
						   utf8, utf8_len,
862
						   subset_glyph);
863
	    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
864
                return status;
865
        }
866
    }
867
 
868
    /* Lookup glyph in scaled subsets */
869
    key.is_scaled = TRUE;
870
    _cairo_sub_font_init_key (&key, scaled_font);
871
    sub_font = _cairo_hash_table_lookup (subsets->scaled_sub_fonts,
872
					 &key.base);
873
    if (sub_font != NULL) {
874
	status = _cairo_sub_font_lookup_glyph (sub_font,
875
					       scaled_font_glyph_index,
876
					       utf8, utf8_len,
877
					       subset_glyph);
878
	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
879
	    return status;
880
    }
881
 
882
    /* Glyph not found. Determine whether the glyph is outline or
883
     * bitmap and add to the appropriate subset.
884
     *
885
     * glyph_index 0 (the .notdef glyph) is a special case. Some fonts
886
     * will return CAIRO_INT_STATUS_UNSUPPORTED when doing a
887
     * _scaled_glyph_lookup(_GLYPH_INFO_PATH). Type1-fallback creates
888
     * empty glyphs in this case so we can put the glyph in a unscaled
889
     * subset. */
890
    if (scaled_font_glyph_index == 0 ||
891
	_cairo_font_face_is_user (scaled_font->font_face)) {
892
	status = CAIRO_STATUS_SUCCESS;
893
    } else {
894
	_cairo_scaled_font_freeze_cache (scaled_font);
895
	status = _cairo_scaled_glyph_lookup (scaled_font,
896
					     scaled_font_glyph_index,
897
					     CAIRO_SCALED_GLYPH_INFO_PATH,
898
					     &scaled_glyph);
899
	_cairo_scaled_font_thaw_cache (scaled_font);
900
    }
3959 Serge 901
    if (_cairo_int_status_is_error (status))
1897 serge 902
        return status;
903
 
3959 Serge 904
    if (status == CAIRO_INT_STATUS_SUCCESS &&
1897 serge 905
	subsets->type != CAIRO_SUBSETS_SCALED &&
906
	! _cairo_font_face_is_user (scaled_font->font_face))
907
    {
908
        /* Path available. Add to unscaled subset. */
909
        key.is_scaled = FALSE;
910
        _cairo_sub_font_init_key (&key, scaled_font);
911
	sub_font = _cairo_hash_table_lookup (subsets->unscaled_sub_fonts,
912
					     &key.base);
913
        if (sub_font == NULL) {
914
            font_face = cairo_scaled_font_get_font_face (scaled_font);
915
            cairo_matrix_init_identity (&identity);
916
            _cairo_font_options_init_default (&font_options);
917
            cairo_font_options_set_hint_style (&font_options, CAIRO_HINT_STYLE_NONE);
918
            cairo_font_options_set_hint_metrics (&font_options, CAIRO_HINT_METRICS_OFF);
919
            unscaled_font = cairo_scaled_font_create (font_face,
920
                                                      &identity,
921
                                                      &identity,
922
                                                      &font_options);
923
	    if (unlikely (unscaled_font->status))
924
		return unscaled_font->status;
925
 
926
            subset_glyph->is_scaled = FALSE;
927
            type1_font = _cairo_type1_scaled_font_is_type1 (unscaled_font);
928
            if (subsets->type == CAIRO_SUBSETS_COMPOSITE && !type1_font) {
929
                max_glyphs = MAX_GLYPHS_PER_COMPOSITE_FONT;
930
                subset_glyph->is_composite = TRUE;
931
            } else {
932
                max_glyphs = MAX_GLYPHS_PER_SIMPLE_FONT;
933
                subset_glyph->is_composite = FALSE;
934
            }
935
 
936
            status = _cairo_sub_font_create (subsets,
937
					     unscaled_font,
938
					     subsets->num_sub_fonts,
939
					     max_glyphs,
940
					     subset_glyph->is_scaled,
941
					     subset_glyph->is_composite,
942
					     &sub_font);
943
 
944
            if (unlikely (status)) {
945
		cairo_scaled_font_destroy (unscaled_font);
946
                return status;
947
	    }
948
 
949
            status = _cairo_hash_table_insert (subsets->unscaled_sub_fonts,
950
                                               &sub_font->base);
951
 
952
            if (unlikely (status)) {
953
		_cairo_sub_font_destroy (sub_font);
954
                return status;
955
	    }
956
	    if (!subsets->unscaled_sub_fonts_list)
957
		subsets->unscaled_sub_fonts_list = sub_font;
958
	    else
959
		subsets->unscaled_sub_fonts_list_end->next = sub_font;
960
	    subsets->unscaled_sub_fonts_list_end = sub_font;
961
	    subsets->num_sub_fonts++;
962
        }
963
    } else {
964
        /* No path available. Add to scaled subset. */
965
        key.is_scaled = TRUE;
966
        _cairo_sub_font_init_key (&key, scaled_font);
967
	sub_font = _cairo_hash_table_lookup (subsets->scaled_sub_fonts,
968
					     &key.base);
969
        if (sub_font == NULL) {
970
            subset_glyph->is_scaled = TRUE;
971
            subset_glyph->is_composite = FALSE;
972
            if (subsets->type == CAIRO_SUBSETS_SCALED)
973
                max_glyphs = INT_MAX;
974
            else
975
                max_glyphs = MAX_GLYPHS_PER_SIMPLE_FONT;
976
 
977
            status = _cairo_sub_font_create (subsets,
978
					     cairo_scaled_font_reference (scaled_font),
979
					     subsets->num_sub_fonts,
980
					     max_glyphs,
981
					     subset_glyph->is_scaled,
982
					     subset_glyph->is_composite,
983
					     &sub_font);
984
            if (unlikely (status)) {
985
		cairo_scaled_font_destroy (scaled_font);
986
                return status;
987
	    }
988
 
989
            status = _cairo_hash_table_insert (subsets->scaled_sub_fonts,
990
                                               &sub_font->base);
991
            if (unlikely (status)) {
992
		_cairo_sub_font_destroy (sub_font);
993
                return status;
994
	    }
995
	    if (!subsets->scaled_sub_fonts_list)
996
		subsets->scaled_sub_fonts_list = sub_font;
997
	    else
998
		subsets->scaled_sub_fonts_list_end->next = sub_font;
999
	    subsets->scaled_sub_fonts_list_end = sub_font;
1000
	    subsets->num_sub_fonts++;
1001
        }
1002
    }
1003
 
1004
    return _cairo_sub_font_map_glyph (sub_font,
1005
				      scaled_font_glyph_index,
1006
				      utf8, utf8_len,
1007
				      subset_glyph);
1008
}
1009
 
1010
static cairo_status_t
1011
_cairo_scaled_font_subsets_foreach_internal (cairo_scaled_font_subsets_t              *font_subsets,
1012
                                             cairo_scaled_font_subset_callback_func_t  font_subset_callback,
1013
                                             void				      *closure,
1014
					     cairo_subsets_foreach_type_t	       type)
1015
{
1016
    cairo_sub_font_collection_t collection;
1017
    cairo_sub_font_t *sub_font;
1018
    cairo_bool_t is_scaled, is_user;
1019
 
1020
    is_scaled = FALSE;
1021
    is_user = FALSE;
1022
 
1023
    if (type == CAIRO_SUBSETS_FOREACH_USER)
1024
	is_user = TRUE;
1025
 
1026
    if (type == CAIRO_SUBSETS_FOREACH_SCALED ||
1027
	type == CAIRO_SUBSETS_FOREACH_USER)
1028
    {
1029
	is_scaled = TRUE;
1030
    }
1031
 
1032
    if (is_scaled)
1033
        collection.glyphs_size = font_subsets->max_glyphs_per_scaled_subset_used;
1034
    else
1035
        collection.glyphs_size = font_subsets->max_glyphs_per_unscaled_subset_used;
1036
 
1037
    if (! collection.glyphs_size)
1038
	return CAIRO_STATUS_SUCCESS;
1039
 
1040
    collection.glyphs = _cairo_malloc_ab (collection.glyphs_size, sizeof(unsigned long));
1041
    collection.utf8 = _cairo_malloc_ab (collection.glyphs_size, sizeof(char *));
3959 Serge 1042
    collection.to_latin_char = _cairo_malloc_ab (collection.glyphs_size, sizeof(int));
1043
    collection.latin_to_subset_glyph_index = _cairo_malloc_ab (256, sizeof(unsigned long));
1044
    if (unlikely (collection.glyphs == NULL ||
1045
		  collection.utf8 == NULL ||
1046
		  collection.to_latin_char == NULL ||
1047
		  collection.latin_to_subset_glyph_index == NULL)) {
1048
	free (collection.glyphs);
1049
	free (collection.utf8);
1050
	free (collection.to_latin_char);
1051
	free (collection.latin_to_subset_glyph_index);
1897 serge 1052
 
1053
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1054
    }
1055
 
1056
    collection.font_subset_callback = font_subset_callback;
1057
    collection.font_subset_callback_closure = closure;
1058
    collection.status = CAIRO_STATUS_SUCCESS;
1059
 
1060
    if (is_scaled)
1061
	sub_font = font_subsets->scaled_sub_fonts_list;
1062
    else
1063
	sub_font = font_subsets->unscaled_sub_fonts_list;
1064
 
1065
    while (sub_font) {
1066
	if (sub_font->is_user == is_user)
1067
	    _cairo_sub_font_collect (sub_font, &collection);
1068
 
1069
	sub_font = sub_font->next;
1070
    }
1071
    free (collection.utf8);
1072
    free (collection.glyphs);
3959 Serge 1073
    free (collection.to_latin_char);
1074
    free (collection.latin_to_subset_glyph_index);
1897 serge 1075
 
1076
    return collection.status;
1077
}
1078
 
1079
cairo_status_t
1080
_cairo_scaled_font_subsets_foreach_scaled (cairo_scaled_font_subsets_t		    *font_subsets,
1081
                                           cairo_scaled_font_subset_callback_func_t  font_subset_callback,
1082
                                           void					    *closure)
1083
{
1084
    return _cairo_scaled_font_subsets_foreach_internal (font_subsets,
1085
                                                        font_subset_callback,
1086
                                                        closure,
1087
							CAIRO_SUBSETS_FOREACH_SCALED);
1088
}
1089
 
1090
cairo_status_t
1091
_cairo_scaled_font_subsets_foreach_unscaled (cairo_scaled_font_subsets_t	    *font_subsets,
1092
                                           cairo_scaled_font_subset_callback_func_t  font_subset_callback,
1093
                                           void					    *closure)
1094
{
1095
    return _cairo_scaled_font_subsets_foreach_internal (font_subsets,
1096
                                                        font_subset_callback,
1097
                                                        closure,
1098
							CAIRO_SUBSETS_FOREACH_UNSCALED);
1099
}
1100
 
1101
cairo_status_t
1102
_cairo_scaled_font_subsets_foreach_user (cairo_scaled_font_subsets_t		  *font_subsets,
1103
					 cairo_scaled_font_subset_callback_func_t  font_subset_callback,
1104
					 void					  *closure)
1105
{
1106
    return _cairo_scaled_font_subsets_foreach_internal (font_subsets,
1107
                                                        font_subset_callback,
1108
                                                        closure,
1109
							CAIRO_SUBSETS_FOREACH_USER);
1110
}
1111
 
1112
static cairo_bool_t
1113
_cairo_string_equal (const void *key_a, const void *key_b)
1114
{
1115
    const cairo_string_entry_t *a = key_a;
1116
    const cairo_string_entry_t *b = key_b;
1117
 
1118
    if (strcmp (a->string, b->string) == 0)
1119
	return TRUE;
1120
    else
1121
	return FALSE;
1122
}
1123
 
1124
static void
1125
_cairo_string_init_key (cairo_string_entry_t *key, char *s)
1126
{
1127
    unsigned long sum = 0;
1128
    unsigned int i;
1129
 
1130
    for (i = 0; i < strlen(s); i++)
1131
        sum += s[i];
1132
    key->base.hash = sum;
1133
    key->string = s;
1134
}
1135
 
1136
static cairo_status_t
1137
create_string_entry (char *s, cairo_string_entry_t **entry)
1138
{
1139
    *entry = malloc (sizeof (cairo_string_entry_t));
1140
    if (unlikely (*entry == NULL))
1141
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1142
 
1143
    _cairo_string_init_key (*entry, s);
1144
 
1145
    return CAIRO_STATUS_SUCCESS;
1146
}
1147
 
1148
static void
1149
_pluck_entry (void *entry, void *closure)
1150
{
1151
    _cairo_hash_table_remove (closure, entry);
1152
    free (entry);
1153
}
1154
 
1155
cairo_int_status_t
1156
_cairo_scaled_font_subset_create_glyph_names (cairo_scaled_font_subset_t *subset)
1157
{
1158
    unsigned int i;
1159
    cairo_hash_table_t *names;
1160
    cairo_string_entry_t key, *entry;
1161
    char buf[30];
1162
    char *utf8;
1163
    uint16_t *utf16;
1164
    int utf16_len;
1165
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
1166
 
1167
    names = _cairo_hash_table_create (_cairo_string_equal);
1168
    if (unlikely (names == NULL))
1169
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1170
 
1171
    subset->glyph_names = calloc (subset->num_glyphs, sizeof (char *));
1172
    if (unlikely (subset->glyph_names == NULL)) {
1173
	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1174
	goto CLEANUP_HASH;
1175
    }
1176
 
1177
    i = 0;
1178
    if (! subset->is_scaled) {
1179
	subset->glyph_names[0] = strdup (".notdef");
1180
	if (unlikely (subset->glyph_names[0] == NULL)) {
1181
	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1182
	    goto CLEANUP_HASH;
1183
	}
1184
 
1185
	status = create_string_entry (subset->glyph_names[0], &entry);
1186
	if (unlikely (status))
1187
	    goto CLEANUP_HASH;
1188
 
1189
	status = _cairo_hash_table_insert (names, &entry->base);
1190
	if (unlikely (status)) {
1191
	    free (entry);
1192
	    goto CLEANUP_HASH;
1193
	}
1194
	i++;
1195
    }
1196
 
1197
    for (; i < subset->num_glyphs; i++) {
1198
	utf8 = subset->utf8[i];
1199
	utf16 = NULL;
1200
	utf16_len = 0;
1201
	if (utf8 && *utf8) {
1202
	    status = _cairo_utf8_to_utf16 (utf8, -1, &utf16, &utf16_len);
1203
	    if (unlikely (status))
1204
		goto CLEANUP_HASH;
1205
	}
1206
 
1207
	if (utf16_len == 1) {
3959 Serge 1208
	    int ch = _cairo_unicode_to_winansi (utf16[0]);
1209
	    if (ch > 0 && _cairo_winansi_to_glyphname (ch))
1210
		strncpy (buf, _cairo_winansi_to_glyphname (ch), sizeof (buf));
1211
	    else
1212
		snprintf (buf, sizeof (buf), "uni%04X", (int) utf16[0]);
1213
 
1897 serge 1214
	    _cairo_string_init_key (&key, buf);
1215
	    entry = _cairo_hash_table_lookup (names, &key.base);
1216
	    if (entry != NULL)
1217
		snprintf (buf, sizeof (buf), "g%d", i);
1218
	} else {
1219
	    snprintf (buf, sizeof (buf), "g%d", i);
1220
	}
3959 Serge 1221
	free (utf16);
1897 serge 1222
 
1223
	subset->glyph_names[i] = strdup (buf);
1224
	if (unlikely (subset->glyph_names[i] == NULL)) {
1225
	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1226
	    goto CLEANUP_HASH;
1227
	}
1228
 
1229
	status = create_string_entry (subset->glyph_names[i], &entry);
1230
	if (unlikely (status))
1231
	    goto CLEANUP_HASH;
1232
 
1233
	status = _cairo_hash_table_insert (names, &entry->base);
1234
	if (unlikely (status)) {
1235
	    free (entry);
1236
	    goto CLEANUP_HASH;
1237
	}
1238
    }
1239
 
1240
CLEANUP_HASH:
1241
    _cairo_hash_table_foreach (names, _pluck_entry, names);
1242
    _cairo_hash_table_destroy (names);
1243
 
1244
    if (likely (status == CAIRO_STATUS_SUCCESS))
1245
	return CAIRO_STATUS_SUCCESS;
1246
 
1247
    if (subset->glyph_names != NULL) {
1248
	for (i = 0; i < subset->num_glyphs; i++) {
3959 Serge 1249
	    free (subset->glyph_names[i]);
1897 serge 1250
	}
1251
 
1252
	free (subset->glyph_names);
1253
	subset->glyph_names = NULL;
1254
    }
1255
 
1256
    return status;
1257
}
1258
 
1259
#endif /* CAIRO_HAS_FONT_SUBSET */