Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | 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;
73
    cairo_scaled_font_subsets_t *parent;
74
    cairo_scaled_font_t *scaled_font;
75
    unsigned int font_id;
76
 
77
    int current_subset;
78
    int num_glyphs_in_current_subset;
79
    int max_glyphs_per_subset;
80
 
81
    cairo_hash_table_t *sub_font_glyphs;
82
    struct _cairo_sub_font *next;
83
} cairo_sub_font_t;
84
 
85
struct _cairo_scaled_font_subsets {
86
    cairo_subsets_type_t type;
87
 
88
    int max_glyphs_per_unscaled_subset_used;
89
    cairo_hash_table_t *unscaled_sub_fonts;
90
    cairo_sub_font_t *unscaled_sub_fonts_list;
91
    cairo_sub_font_t *unscaled_sub_fonts_list_end;
92
 
93
    int max_glyphs_per_scaled_subset_used;
94
    cairo_hash_table_t *scaled_sub_fonts;
95
    cairo_sub_font_t *scaled_sub_fonts_list;
96
    cairo_sub_font_t *scaled_sub_fonts_list_end;
97
 
98
    int num_sub_fonts;
99
};
100
 
101
typedef struct _cairo_sub_font_glyph {
102
    cairo_hash_entry_t base;
103
 
104
    unsigned int subset_id;
105
    unsigned int subset_glyph_index;
106
    double       x_advance;
107
    double       y_advance;
108
 
109
    cairo_bool_t is_mapped;
110
    uint32_t     unicode;
111
    char  	*utf8;
112
    int          utf8_len;
113
} cairo_sub_font_glyph_t;
114
 
115
typedef struct _cairo_sub_font_collection {
116
    unsigned long *glyphs; /* scaled_font_glyph_index */
117
    char       **utf8;
118
    unsigned int glyphs_size;
119
    unsigned int max_glyph;
120
    unsigned int num_glyphs;
121
 
122
    unsigned int subset_id;
123
 
124
    cairo_status_t status;
125
    cairo_scaled_font_subset_callback_func_t font_subset_callback;
126
    void *font_subset_callback_closure;
127
} cairo_sub_font_collection_t;
128
 
129
typedef struct _cairo_string_entry {
130
    cairo_hash_entry_t base;
131
    char *string;
132
} cairo_string_entry_t;
133
 
134
static cairo_status_t
135
_cairo_sub_font_map_glyph (cairo_sub_font_t	*sub_font,
136
			   unsigned long	 scaled_font_glyph_index,
137
			   const char *		 utf8,
138
			   int			 utf8_len,
139
                           cairo_scaled_font_subsets_glyph_t *subset_glyph);
140
 
141
static void
142
_cairo_sub_font_glyph_init_key (cairo_sub_font_glyph_t  *sub_font_glyph,
143
				unsigned long		 scaled_font_glyph_index)
144
{
145
    sub_font_glyph->base.hash = scaled_font_glyph_index;
146
}
147
 
148
static cairo_bool_t
149
_cairo_sub_font_glyphs_equal (const void *key_a, const void *key_b)
150
{
151
    const cairo_sub_font_glyph_t *sub_font_glyph_a = key_a;
152
    const cairo_sub_font_glyph_t *sub_font_glyph_b = key_b;
153
 
154
    return sub_font_glyph_a->base.hash == sub_font_glyph_b->base.hash;
155
}
156
 
157
static cairo_sub_font_glyph_t *
158
_cairo_sub_font_glyph_create (unsigned long	scaled_font_glyph_index,
159
			      unsigned int	subset_id,
160
			      unsigned int	subset_glyph_index,
161
                              double            x_advance,
162
                              double            y_advance)
163
{
164
    cairo_sub_font_glyph_t *sub_font_glyph;
165
 
166
    sub_font_glyph = malloc (sizeof (cairo_sub_font_glyph_t));
167
    if (unlikely (sub_font_glyph == NULL)) {
168
	_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
169
	return NULL;
170
    }
171
 
172
    _cairo_sub_font_glyph_init_key (sub_font_glyph, scaled_font_glyph_index);
173
    sub_font_glyph->subset_id = subset_id;
174
    sub_font_glyph->subset_glyph_index = subset_glyph_index;
175
    sub_font_glyph->x_advance = x_advance;
176
    sub_font_glyph->y_advance = y_advance;
177
    sub_font_glyph->is_mapped = FALSE;
178
    sub_font_glyph->unicode = -1;
179
    sub_font_glyph->utf8 = NULL;
180
    sub_font_glyph->utf8_len = 0;
181
 
182
    return sub_font_glyph;
183
}
184
 
185
static void
186
_cairo_sub_font_glyph_destroy (cairo_sub_font_glyph_t *sub_font_glyph)
187
{
188
    if (sub_font_glyph->utf8 != NULL)
189
	free (sub_font_glyph->utf8);
190
 
191
    free (sub_font_glyph);
192
}
193
 
194
static void
195
_cairo_sub_font_glyph_pluck (void *entry, void *closure)
196
{
197
    cairo_sub_font_glyph_t *sub_font_glyph = entry;
198
    cairo_hash_table_t *sub_font_glyphs = closure;
199
 
200
    _cairo_hash_table_remove (sub_font_glyphs, &sub_font_glyph->base);
201
    _cairo_sub_font_glyph_destroy (sub_font_glyph);
202
}
203
 
204
static void
205
_cairo_sub_font_glyph_collect (void *entry, void *closure)
206
{
207
    cairo_sub_font_glyph_t *sub_font_glyph = entry;
208
    cairo_sub_font_collection_t *collection = closure;
209
    unsigned long scaled_font_glyph_index;
210
    unsigned int subset_glyph_index;
211
 
212
    if (sub_font_glyph->subset_id != collection->subset_id)
213
	return;
214
 
215
    scaled_font_glyph_index = sub_font_glyph->base.hash;
216
    subset_glyph_index = sub_font_glyph->subset_glyph_index;
217
 
218
    /* Ensure we don't exceed the allocated bounds. */
219
    assert (subset_glyph_index < collection->glyphs_size);
220
 
221
    collection->glyphs[subset_glyph_index] = scaled_font_glyph_index;
222
    collection->utf8[subset_glyph_index] = sub_font_glyph->utf8;
223
    if (subset_glyph_index > collection->max_glyph)
224
	collection->max_glyph = subset_glyph_index;
225
 
226
    collection->num_glyphs++;
227
}
228
 
229
static cairo_bool_t
230
_cairo_sub_fonts_equal (const void *key_a, const void *key_b)
231
{
232
    const cairo_sub_font_t *sub_font_a = key_a;
233
    const cairo_sub_font_t *sub_font_b = key_b;
234
    cairo_scaled_font_t *a = sub_font_a->scaled_font;
235
    cairo_scaled_font_t *b = sub_font_b->scaled_font;
236
 
237
    if (sub_font_a->is_scaled)
238
        return a == b;
239
    else
240
	return a->font_face == b->font_face || a->original_font_face == b->original_font_face;
241
}
242
 
243
static void
244
_cairo_sub_font_init_key (cairo_sub_font_t	*sub_font,
245
			  cairo_scaled_font_t	*scaled_font)
246
{
247
    if (sub_font->is_scaled)
248
    {
249
        sub_font->base.hash = (unsigned long) scaled_font;
250
        sub_font->scaled_font = scaled_font;
251
    }
252
    else
253
    {
254
        sub_font->base.hash = (unsigned long) scaled_font->font_face;
255
        sub_font->scaled_font = scaled_font;
256
    }
257
}
258
 
259
static cairo_status_t
260
_cairo_sub_font_create (cairo_scaled_font_subsets_t	*parent,
261
			cairo_scaled_font_t		*scaled_font,
262
			unsigned int			 font_id,
263
			int				 max_glyphs_per_subset,
264
                        cairo_bool_t                     is_scaled,
265
			cairo_bool_t                     is_composite,
266
			cairo_sub_font_t               **sub_font_out)
267
{
268
    cairo_sub_font_t *sub_font;
269
    cairo_status_t status;
270
    cairo_scaled_font_subsets_glyph_t subset_glyph;
271
 
272
    sub_font = malloc (sizeof (cairo_sub_font_t));
273
    if (unlikely (sub_font == NULL))
274
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
275
 
276
    sub_font->is_scaled = is_scaled;
277
    sub_font->is_composite = is_composite;
278
    sub_font->is_user = _cairo_font_face_is_user (scaled_font->font_face);
279
    _cairo_sub_font_init_key (sub_font, scaled_font);
280
 
281
    sub_font->parent = parent;
282
    sub_font->scaled_font = scaled_font;
283
    sub_font->font_id = font_id;
284
 
285
    sub_font->current_subset = 0;
286
    sub_font->num_glyphs_in_current_subset = 0;
287
    sub_font->max_glyphs_per_subset = max_glyphs_per_subset;
288
 
289
    sub_font->sub_font_glyphs = _cairo_hash_table_create (_cairo_sub_font_glyphs_equal);
290
    if (unlikely (sub_font->sub_font_glyphs == NULL)) {
291
	free (sub_font);
292
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
293
    }
294
    sub_font->next = NULL;
295
 
296
    /* Reserve first glyph in subset for the .notdef glyph except for
297
     * Type 3 fonts */
298
    if (! is_scaled) {
299
	status = _cairo_sub_font_map_glyph (sub_font, 0, NULL, -1, &subset_glyph);
300
	if (unlikely (status)) {
301
	    _cairo_hash_table_destroy (sub_font->sub_font_glyphs);
302
	    free (sub_font);
303
	    return status;
304
	}
305
    }
306
 
307
    *sub_font_out = sub_font;
308
    return CAIRO_STATUS_SUCCESS;
309
}
310
 
311
static void
312
_cairo_sub_font_destroy (cairo_sub_font_t *sub_font)
313
{
314
    _cairo_hash_table_foreach (sub_font->sub_font_glyphs,
315
			       _cairo_sub_font_glyph_pluck,
316
			       sub_font->sub_font_glyphs);
317
    _cairo_hash_table_destroy (sub_font->sub_font_glyphs);
318
    cairo_scaled_font_destroy (sub_font->scaled_font);
319
    free (sub_font);
320
}
321
 
322
static void
323
_cairo_sub_font_pluck (void *entry, void *closure)
324
{
325
    cairo_sub_font_t *sub_font = entry;
326
    cairo_hash_table_t *sub_fonts = closure;
327
 
328
    _cairo_hash_table_remove (sub_fonts, &sub_font->base);
329
    _cairo_sub_font_destroy (sub_font);
330
}
331
 
332
static cairo_status_t
333
_cairo_sub_font_glyph_lookup_unicode (cairo_sub_font_glyph_t *sub_font_glyph,
334
				      cairo_scaled_font_t    *scaled_font,
335
				      unsigned long	      scaled_font_glyph_index)
336
{
337
    uint32_t unicode;
338
    char buf[8];
339
    int len;
340
    cairo_status_t status;
341
 
342
    /* Do a reverse lookup on the glyph index. unicode is -1 if the
343
     * index could not be mapped to a unicode character. */
344
    unicode = -1;
345
    status = _cairo_truetype_index_to_ucs4 (scaled_font,
346
					    scaled_font_glyph_index,
347
					    &unicode);
348
    if (_cairo_status_is_error (status))
349
	return status;
350
 
351
    if (unicode == (uint32_t)-1 && scaled_font->backend->index_to_ucs4) {
352
	status = scaled_font->backend->index_to_ucs4 (scaled_font,
353
						      scaled_font_glyph_index,
354
						      &unicode);
355
	if (unlikely (status))
356
	    return status;
357
    }
358
 
359
    sub_font_glyph->unicode = unicode;
360
    sub_font_glyph->utf8 = NULL;
361
    sub_font_glyph->utf8_len = 0;
362
    if (unicode != (uint32_t) -1) {
363
	len = _cairo_ucs4_to_utf8 (unicode, buf);
364
	if (len > 0) {
365
	    sub_font_glyph->utf8 = malloc (len + 1);
366
	    if (unlikely (sub_font_glyph->utf8 == NULL))
367
		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
368
 
369
	    memcpy (sub_font_glyph->utf8, buf, len);
370
	    sub_font_glyph->utf8[len] = 0;
371
	    sub_font_glyph->utf8_len = len;
372
	}
373
    }
374
 
375
    return CAIRO_STATUS_SUCCESS;
376
}
377
 
378
static cairo_status_t
379
_cairo_sub_font_glyph_map_to_unicode (cairo_sub_font_glyph_t *sub_font_glyph,
380
				      const char	     *utf8,
381
				      int		      utf8_len,
382
				      cairo_bool_t	     *is_mapped)
383
{
384
    *is_mapped = FALSE;
385
 
386
    if (utf8_len < 0)
387
	return CAIRO_STATUS_SUCCESS;
388
 
389
    if (utf8 != NULL && utf8_len != 0 && utf8[utf8_len - 1] == '\0')
390
	utf8_len--;
391
 
392
    if (utf8 != NULL && utf8_len != 0) {
393
	if (sub_font_glyph->utf8 != NULL) {
394
	    if (utf8_len == sub_font_glyph->utf8_len &&
395
		memcmp (utf8, sub_font_glyph->utf8, utf8_len) == 0)
396
	    {
397
		/* Requested utf8 mapping matches the existing mapping */
398
		*is_mapped = TRUE;
399
	    }
400
	} else {
401
	    /* No existing mapping. Use the requested mapping */
402
	    sub_font_glyph->utf8 = malloc (utf8_len + 1);
403
	    if (unlikely (sub_font_glyph->utf8 == NULL))
404
		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
405
 
406
	    memcpy (sub_font_glyph->utf8, utf8, utf8_len);
407
	    sub_font_glyph->utf8[utf8_len] = 0;
408
	    sub_font_glyph->utf8_len = utf8_len;
409
	    *is_mapped = TRUE;
410
	}
411
    }
412
 
413
    return CAIRO_STATUS_SUCCESS;
414
}
415
 
416
static cairo_int_status_t
417
_cairo_sub_font_lookup_glyph (cairo_sub_font_t	                *sub_font,
418
                              unsigned long	                 scaled_font_glyph_index,
419
			      const char			*utf8,
420
			      int				 utf8_len,
421
                              cairo_scaled_font_subsets_glyph_t *subset_glyph)
422
{
423
    cairo_sub_font_glyph_t key, *sub_font_glyph;
424
    cairo_int_status_t status;
425
 
426
    _cairo_sub_font_glyph_init_key (&key, scaled_font_glyph_index);
427
    sub_font_glyph = _cairo_hash_table_lookup (sub_font->sub_font_glyphs,
428
					      &key.base);
429
    if (sub_font_glyph != NULL) {
430
        subset_glyph->font_id = sub_font->font_id;
431
        subset_glyph->subset_id = sub_font_glyph->subset_id;
432
        subset_glyph->subset_glyph_index = sub_font_glyph->subset_glyph_index;
433
        subset_glyph->is_scaled = sub_font->is_scaled;
434
        subset_glyph->is_composite = sub_font->is_composite;
435
        subset_glyph->x_advance = sub_font_glyph->x_advance;
436
        subset_glyph->y_advance = sub_font_glyph->y_advance;
437
	status = _cairo_sub_font_glyph_map_to_unicode (sub_font_glyph,
438
						       utf8, utf8_len,
439
						       &subset_glyph->utf8_is_mapped);
440
	subset_glyph->unicode = sub_font_glyph->unicode;
441
 
442
	return status;
443
    }
444
 
445
    return CAIRO_INT_STATUS_UNSUPPORTED;
446
}
447
 
448
static cairo_status_t
449
_cairo_sub_font_map_glyph (cairo_sub_font_t	*sub_font,
450
			   unsigned long	 scaled_font_glyph_index,
451
			   const char		*utf8,
452
			   int			 utf8_len,
453
                           cairo_scaled_font_subsets_glyph_t *subset_glyph)
454
{
455
    cairo_sub_font_glyph_t key, *sub_font_glyph;
456
    cairo_status_t status;
457
 
458
    _cairo_sub_font_glyph_init_key (&key, scaled_font_glyph_index);
459
    sub_font_glyph = _cairo_hash_table_lookup (sub_font->sub_font_glyphs,
460
					       &key.base);
461
    if (sub_font_glyph == NULL) {
462
	cairo_scaled_glyph_t *scaled_glyph;
463
 
464
	if (sub_font->num_glyphs_in_current_subset == sub_font->max_glyphs_per_subset)
465
	{
466
	    cairo_scaled_font_subsets_glyph_t tmp_subset_glyph;
467
 
468
	    sub_font->current_subset++;
469
	    sub_font->num_glyphs_in_current_subset = 0;
470
 
471
	    /* Reserve first glyph in subset for the .notdef glyph
472
	     * except for Type 3 fonts */
473
	    if (! _cairo_font_face_is_user (sub_font->scaled_font->font_face)) {
474
		status = _cairo_sub_font_map_glyph (sub_font, 0, NULL, -1, &tmp_subset_glyph);
475
		if (unlikely (status))
476
		    return status;
477
	    }
478
	}
479
 
480
	_cairo_scaled_font_freeze_cache (sub_font->scaled_font);
481
        status = _cairo_scaled_glyph_lookup (sub_font->scaled_font,
482
                                             scaled_font_glyph_index,
483
                                             CAIRO_SCALED_GLYPH_INFO_METRICS,
484
                                             &scaled_glyph);
485
	assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
486
	if (unlikely (status)) {
487
	    _cairo_scaled_font_thaw_cache (sub_font->scaled_font);
488
	    return status;
489
	}
490
 
491
        sub_font_glyph = _cairo_sub_font_glyph_create (scaled_font_glyph_index,
492
						       sub_font->current_subset,
493
						       sub_font->num_glyphs_in_current_subset,
494
                                                       scaled_glyph->metrics.x_advance,
495
                                                       scaled_glyph->metrics.y_advance);
496
	_cairo_scaled_font_thaw_cache (sub_font->scaled_font);
497
 
498
	if (unlikely (sub_font_glyph == NULL))
499
	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
500
 
501
	status = _cairo_sub_font_glyph_lookup_unicode (sub_font_glyph,
502
						       sub_font->scaled_font,
503
						       scaled_font_glyph_index);
504
	if (unlikely (status)) {
505
	    _cairo_sub_font_glyph_destroy (sub_font_glyph);
506
	    return status;
507
	}
508
 
509
	status = _cairo_hash_table_insert (sub_font->sub_font_glyphs, &sub_font_glyph->base);
510
	if (unlikely (status)) {
511
	    _cairo_sub_font_glyph_destroy (sub_font_glyph);
512
	    return status;
513
	}
514
 
515
	sub_font->num_glyphs_in_current_subset++;
516
 
517
        if (sub_font->is_scaled) {
518
            if (sub_font->num_glyphs_in_current_subset > sub_font->parent->max_glyphs_per_scaled_subset_used)
519
                sub_font->parent->max_glyphs_per_scaled_subset_used = sub_font->num_glyphs_in_current_subset;
520
        } else {
521
            if (sub_font->num_glyphs_in_current_subset > sub_font->parent->max_glyphs_per_unscaled_subset_used)
522
                sub_font->parent->max_glyphs_per_unscaled_subset_used = sub_font->num_glyphs_in_current_subset;
523
        }
524
    }
525
 
526
    subset_glyph->font_id = sub_font->font_id;
527
    subset_glyph->subset_id = sub_font_glyph->subset_id;
528
    subset_glyph->subset_glyph_index = sub_font_glyph->subset_glyph_index;
529
    subset_glyph->is_scaled = sub_font->is_scaled;
530
    subset_glyph->is_composite = sub_font->is_composite;
531
    subset_glyph->x_advance = sub_font_glyph->x_advance;
532
    subset_glyph->y_advance = sub_font_glyph->y_advance;
533
    status = _cairo_sub_font_glyph_map_to_unicode (sub_font_glyph,
534
						   utf8, utf8_len,
535
						   &subset_glyph->utf8_is_mapped);
536
    subset_glyph->unicode = sub_font_glyph->unicode;
537
 
538
    return status;
539
}
540
 
541
static void
542
_cairo_sub_font_collect (void *entry, void *closure)
543
{
544
    cairo_sub_font_t *sub_font = entry;
545
    cairo_sub_font_collection_t *collection = closure;
546
    cairo_scaled_font_subset_t subset;
547
    int i;
548
    unsigned int j;
549
 
550
    if (collection->status)
551
	return;
552
 
553
    collection->status = sub_font->scaled_font->status;
554
    if (collection->status)
555
	return;
556
 
557
    for (i = 0; i <= sub_font->current_subset; i++) {
558
	collection->subset_id = i;
559
	collection->num_glyphs = 0;
560
	collection->max_glyph = 0;
561
 
562
	_cairo_hash_table_foreach (sub_font->sub_font_glyphs,
563
				   _cairo_sub_font_glyph_collect, collection);
564
	if (collection->status)
565
	    break;
566
	if (collection->num_glyphs == 0)
567
	    continue;
568
 
569
        /* Ensure the resulting array has no uninitialized holes */
570
	assert (collection->num_glyphs == collection->max_glyph + 1);
571
 
572
	subset.scaled_font = sub_font->scaled_font;
573
	subset.is_composite = sub_font->is_composite;
574
	subset.is_scaled = sub_font->is_scaled;
575
	subset.font_id = sub_font->font_id;
576
	subset.subset_id = i;
577
	subset.glyphs = collection->glyphs;
578
	subset.utf8 = collection->utf8;
579
	subset.num_glyphs = collection->num_glyphs;
580
        subset.glyph_names = NULL;
581
        /* No need to check for out of memory here. If to_unicode is NULL, the PDF
582
         * surface does not emit an ToUnicode stream */
583
        subset.to_unicode = _cairo_malloc_ab (collection->num_glyphs, sizeof (unsigned long));
584
        if (subset.to_unicode) {
585
            for (j = 0; j < collection->num_glyphs; j++) {
586
                /* default unicode character required when mapping fails */
587
                subset.to_unicode[j] = 0xfffd;
588
            }
589
        }
590
        collection->status = (collection->font_subset_callback) (&subset,
591
					    collection->font_subset_callback_closure);
592
 
593
        if (subset.to_unicode != NULL)
594
            free (subset.to_unicode);
595
 
596
	if (subset.glyph_names != NULL) {
597
            for (j = 0; j < collection->num_glyphs; j++)
598
		free (subset.glyph_names[j]);
599
	    free (subset.glyph_names);
600
	}
601
 
602
	if (collection->status)
603
	    break;
604
    }
605
}
606
 
607
static cairo_scaled_font_subsets_t *
608
_cairo_scaled_font_subsets_create_internal (cairo_subsets_type_t type)
609
{
610
    cairo_scaled_font_subsets_t *subsets;
611
 
612
    subsets = malloc (sizeof (cairo_scaled_font_subsets_t));
613
    if (unlikely (subsets == NULL)) {
614
	_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
615
	return NULL;
616
    }
617
 
618
    subsets->type = type;
619
    subsets->max_glyphs_per_unscaled_subset_used = 0;
620
    subsets->max_glyphs_per_scaled_subset_used = 0;
621
    subsets->num_sub_fonts = 0;
622
 
623
    subsets->unscaled_sub_fonts = _cairo_hash_table_create (_cairo_sub_fonts_equal);
624
    if (! subsets->unscaled_sub_fonts) {
625
	free (subsets);
626
	return NULL;
627
    }
628
    subsets->unscaled_sub_fonts_list = NULL;
629
    subsets->unscaled_sub_fonts_list_end = NULL;
630
 
631
    subsets->scaled_sub_fonts = _cairo_hash_table_create (_cairo_sub_fonts_equal);
632
    if (! subsets->scaled_sub_fonts) {
633
	_cairo_hash_table_destroy (subsets->unscaled_sub_fonts);
634
	free (subsets);
635
	return NULL;
636
    }
637
    subsets->scaled_sub_fonts_list = NULL;
638
    subsets->scaled_sub_fonts_list_end = NULL;
639
 
640
    return subsets;
641
}
642
 
643
cairo_scaled_font_subsets_t *
644
_cairo_scaled_font_subsets_create_scaled (void)
645
{
646
    return _cairo_scaled_font_subsets_create_internal (CAIRO_SUBSETS_SCALED);
647
}
648
 
649
cairo_scaled_font_subsets_t *
650
_cairo_scaled_font_subsets_create_simple (void)
651
{
652
    return _cairo_scaled_font_subsets_create_internal (CAIRO_SUBSETS_SIMPLE);
653
}
654
 
655
cairo_scaled_font_subsets_t *
656
_cairo_scaled_font_subsets_create_composite (void)
657
{
658
    return _cairo_scaled_font_subsets_create_internal (CAIRO_SUBSETS_COMPOSITE);
659
}
660
 
661
void
662
_cairo_scaled_font_subsets_destroy (cairo_scaled_font_subsets_t *subsets)
663
{
664
    _cairo_hash_table_foreach (subsets->scaled_sub_fonts, _cairo_sub_font_pluck, subsets->scaled_sub_fonts);
665
    _cairo_hash_table_destroy (subsets->scaled_sub_fonts);
666
 
667
    _cairo_hash_table_foreach (subsets->unscaled_sub_fonts, _cairo_sub_font_pluck, subsets->unscaled_sub_fonts);
668
    _cairo_hash_table_destroy (subsets->unscaled_sub_fonts);
669
 
670
    free (subsets);
671
}
672
 
673
cairo_status_t
674
_cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t	*subsets,
675
				      cairo_scaled_font_t		*scaled_font,
676
				      unsigned long			 scaled_font_glyph_index,
677
				      const char *			 utf8,
678
				      int				 utf8_len,
679
                                      cairo_scaled_font_subsets_glyph_t *subset_glyph)
680
{
681
    cairo_sub_font_t key, *sub_font;
682
    cairo_scaled_glyph_t *scaled_glyph;
683
    cairo_font_face_t *font_face;
684
    cairo_matrix_t identity;
685
    cairo_font_options_t font_options;
686
    cairo_scaled_font_t	*unscaled_font;
687
    cairo_status_t status;
688
    int max_glyphs;
689
    cairo_bool_t type1_font;
690
 
691
    /* Lookup glyph in unscaled subsets */
692
    if (subsets->type != CAIRO_SUBSETS_SCALED) {
693
        key.is_scaled = FALSE;
694
        _cairo_sub_font_init_key (&key, scaled_font);
695
	sub_font = _cairo_hash_table_lookup (subsets->unscaled_sub_fonts,
696
					     &key.base);
697
        if (sub_font != NULL) {
698
            status = _cairo_sub_font_lookup_glyph (sub_font,
699
						   scaled_font_glyph_index,
700
						   utf8, utf8_len,
701
						   subset_glyph);
702
	    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
703
                return status;
704
        }
705
    }
706
 
707
    /* Lookup glyph in scaled subsets */
708
    key.is_scaled = TRUE;
709
    _cairo_sub_font_init_key (&key, scaled_font);
710
    sub_font = _cairo_hash_table_lookup (subsets->scaled_sub_fonts,
711
					 &key.base);
712
    if (sub_font != NULL) {
713
	status = _cairo_sub_font_lookup_glyph (sub_font,
714
					       scaled_font_glyph_index,
715
					       utf8, utf8_len,
716
					       subset_glyph);
717
	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
718
	    return status;
719
    }
720
 
721
    /* Glyph not found. Determine whether the glyph is outline or
722
     * bitmap and add to the appropriate subset.
723
     *
724
     * glyph_index 0 (the .notdef glyph) is a special case. Some fonts
725
     * will return CAIRO_INT_STATUS_UNSUPPORTED when doing a
726
     * _scaled_glyph_lookup(_GLYPH_INFO_PATH). Type1-fallback creates
727
     * empty glyphs in this case so we can put the glyph in a unscaled
728
     * subset. */
729
    if (scaled_font_glyph_index == 0 ||
730
	_cairo_font_face_is_user (scaled_font->font_face)) {
731
	status = CAIRO_STATUS_SUCCESS;
732
    } else {
733
	_cairo_scaled_font_freeze_cache (scaled_font);
734
	status = _cairo_scaled_glyph_lookup (scaled_font,
735
					     scaled_font_glyph_index,
736
					     CAIRO_SCALED_GLYPH_INFO_PATH,
737
					     &scaled_glyph);
738
	_cairo_scaled_font_thaw_cache (scaled_font);
739
    }
740
    if (_cairo_status_is_error (status))
741
        return status;
742
 
743
    if (status == CAIRO_STATUS_SUCCESS &&
744
	subsets->type != CAIRO_SUBSETS_SCALED &&
745
	! _cairo_font_face_is_user (scaled_font->font_face))
746
    {
747
        /* Path available. Add to unscaled subset. */
748
        key.is_scaled = FALSE;
749
        _cairo_sub_font_init_key (&key, scaled_font);
750
	sub_font = _cairo_hash_table_lookup (subsets->unscaled_sub_fonts,
751
					     &key.base);
752
        if (sub_font == NULL) {
753
            font_face = cairo_scaled_font_get_font_face (scaled_font);
754
            cairo_matrix_init_identity (&identity);
755
            _cairo_font_options_init_default (&font_options);
756
            cairo_font_options_set_hint_style (&font_options, CAIRO_HINT_STYLE_NONE);
757
            cairo_font_options_set_hint_metrics (&font_options, CAIRO_HINT_METRICS_OFF);
758
            unscaled_font = cairo_scaled_font_create (font_face,
759
                                                      &identity,
760
                                                      &identity,
761
                                                      &font_options);
762
	    if (unlikely (unscaled_font->status))
763
		return unscaled_font->status;
764
 
765
            subset_glyph->is_scaled = FALSE;
766
            type1_font = FALSE;
767
#if CAIRO_HAS_FT_FONT
768
            type1_font = _cairo_type1_scaled_font_is_type1 (unscaled_font);
769
#endif
770
            if (subsets->type == CAIRO_SUBSETS_COMPOSITE && !type1_font) {
771
                max_glyphs = MAX_GLYPHS_PER_COMPOSITE_FONT;
772
                subset_glyph->is_composite = TRUE;
773
            } else {
774
                max_glyphs = MAX_GLYPHS_PER_SIMPLE_FONT;
775
                subset_glyph->is_composite = FALSE;
776
            }
777
 
778
            status = _cairo_sub_font_create (subsets,
779
					     unscaled_font,
780
					     subsets->num_sub_fonts,
781
					     max_glyphs,
782
					     subset_glyph->is_scaled,
783
					     subset_glyph->is_composite,
784
					     &sub_font);
785
 
786
            if (unlikely (status)) {
787
		cairo_scaled_font_destroy (unscaled_font);
788
                return status;
789
	    }
790
 
791
            status = _cairo_hash_table_insert (subsets->unscaled_sub_fonts,
792
                                               &sub_font->base);
793
 
794
            if (unlikely (status)) {
795
		_cairo_sub_font_destroy (sub_font);
796
                return status;
797
	    }
798
	    if (!subsets->unscaled_sub_fonts_list)
799
		subsets->unscaled_sub_fonts_list = sub_font;
800
	    else
801
		subsets->unscaled_sub_fonts_list_end->next = sub_font;
802
	    subsets->unscaled_sub_fonts_list_end = sub_font;
803
	    subsets->num_sub_fonts++;
804
        }
805
    } else {
806
        /* No path available. Add to scaled subset. */
807
        key.is_scaled = TRUE;
808
        _cairo_sub_font_init_key (&key, scaled_font);
809
	sub_font = _cairo_hash_table_lookup (subsets->scaled_sub_fonts,
810
					     &key.base);
811
        if (sub_font == NULL) {
812
            subset_glyph->is_scaled = TRUE;
813
            subset_glyph->is_composite = FALSE;
814
            if (subsets->type == CAIRO_SUBSETS_SCALED)
815
                max_glyphs = INT_MAX;
816
            else
817
                max_glyphs = MAX_GLYPHS_PER_SIMPLE_FONT;
818
 
819
            status = _cairo_sub_font_create (subsets,
820
					     cairo_scaled_font_reference (scaled_font),
821
					     subsets->num_sub_fonts,
822
					     max_glyphs,
823
					     subset_glyph->is_scaled,
824
					     subset_glyph->is_composite,
825
					     &sub_font);
826
            if (unlikely (status)) {
827
		cairo_scaled_font_destroy (scaled_font);
828
                return status;
829
	    }
830
 
831
            status = _cairo_hash_table_insert (subsets->scaled_sub_fonts,
832
                                               &sub_font->base);
833
            if (unlikely (status)) {
834
		_cairo_sub_font_destroy (sub_font);
835
                return status;
836
	    }
837
	    if (!subsets->scaled_sub_fonts_list)
838
		subsets->scaled_sub_fonts_list = sub_font;
839
	    else
840
		subsets->scaled_sub_fonts_list_end->next = sub_font;
841
	    subsets->scaled_sub_fonts_list_end = sub_font;
842
	    subsets->num_sub_fonts++;
843
        }
844
    }
845
 
846
    return _cairo_sub_font_map_glyph (sub_font,
847
				      scaled_font_glyph_index,
848
				      utf8, utf8_len,
849
				      subset_glyph);
850
}
851
 
852
static cairo_status_t
853
_cairo_scaled_font_subsets_foreach_internal (cairo_scaled_font_subsets_t              *font_subsets,
854
                                             cairo_scaled_font_subset_callback_func_t  font_subset_callback,
855
                                             void				      *closure,
856
					     cairo_subsets_foreach_type_t	       type)
857
{
858
    cairo_sub_font_collection_t collection;
859
    cairo_sub_font_t *sub_font;
860
    cairo_bool_t is_scaled, is_user;
861
 
862
    is_scaled = FALSE;
863
    is_user = FALSE;
864
 
865
    if (type == CAIRO_SUBSETS_FOREACH_USER)
866
	is_user = TRUE;
867
 
868
    if (type == CAIRO_SUBSETS_FOREACH_SCALED ||
869
	type == CAIRO_SUBSETS_FOREACH_USER)
870
    {
871
	is_scaled = TRUE;
872
    }
873
 
874
    if (is_scaled)
875
        collection.glyphs_size = font_subsets->max_glyphs_per_scaled_subset_used;
876
    else
877
        collection.glyphs_size = font_subsets->max_glyphs_per_unscaled_subset_used;
878
 
879
    if (! collection.glyphs_size)
880
	return CAIRO_STATUS_SUCCESS;
881
 
882
    collection.glyphs = _cairo_malloc_ab (collection.glyphs_size, sizeof(unsigned long));
883
    collection.utf8 = _cairo_malloc_ab (collection.glyphs_size, sizeof(char *));
884
    if (unlikely (collection.glyphs == NULL || collection.utf8 == NULL)) {
885
	if (collection.glyphs != NULL)
886
	    free (collection.glyphs);
887
	if (collection.utf8 != NULL)
888
	    free (collection.utf8);
889
 
890
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
891
    }
892
 
893
    collection.font_subset_callback = font_subset_callback;
894
    collection.font_subset_callback_closure = closure;
895
    collection.status = CAIRO_STATUS_SUCCESS;
896
 
897
    if (is_scaled)
898
	sub_font = font_subsets->scaled_sub_fonts_list;
899
    else
900
	sub_font = font_subsets->unscaled_sub_fonts_list;
901
 
902
    while (sub_font) {
903
	if (sub_font->is_user == is_user)
904
	    _cairo_sub_font_collect (sub_font, &collection);
905
 
906
	sub_font = sub_font->next;
907
    }
908
    free (collection.utf8);
909
    free (collection.glyphs);
910
 
911
    return collection.status;
912
}
913
 
914
cairo_status_t
915
_cairo_scaled_font_subsets_foreach_scaled (cairo_scaled_font_subsets_t		    *font_subsets,
916
                                           cairo_scaled_font_subset_callback_func_t  font_subset_callback,
917
                                           void					    *closure)
918
{
919
    return _cairo_scaled_font_subsets_foreach_internal (font_subsets,
920
                                                        font_subset_callback,
921
                                                        closure,
922
							CAIRO_SUBSETS_FOREACH_SCALED);
923
}
924
 
925
cairo_status_t
926
_cairo_scaled_font_subsets_foreach_unscaled (cairo_scaled_font_subsets_t	    *font_subsets,
927
                                           cairo_scaled_font_subset_callback_func_t  font_subset_callback,
928
                                           void					    *closure)
929
{
930
    return _cairo_scaled_font_subsets_foreach_internal (font_subsets,
931
                                                        font_subset_callback,
932
                                                        closure,
933
							CAIRO_SUBSETS_FOREACH_UNSCALED);
934
}
935
 
936
cairo_status_t
937
_cairo_scaled_font_subsets_foreach_user (cairo_scaled_font_subsets_t		  *font_subsets,
938
					 cairo_scaled_font_subset_callback_func_t  font_subset_callback,
939
					 void					  *closure)
940
{
941
    return _cairo_scaled_font_subsets_foreach_internal (font_subsets,
942
                                                        font_subset_callback,
943
                                                        closure,
944
							CAIRO_SUBSETS_FOREACH_USER);
945
}
946
 
947
static cairo_bool_t
948
_cairo_string_equal (const void *key_a, const void *key_b)
949
{
950
    const cairo_string_entry_t *a = key_a;
951
    const cairo_string_entry_t *b = key_b;
952
 
953
    if (strcmp (a->string, b->string) == 0)
954
	return TRUE;
955
    else
956
	return FALSE;
957
}
958
 
959
static void
960
_cairo_string_init_key (cairo_string_entry_t *key, char *s)
961
{
962
    unsigned long sum = 0;
963
    unsigned int i;
964
 
965
    for (i = 0; i < strlen(s); i++)
966
        sum += s[i];
967
    key->base.hash = sum;
968
    key->string = s;
969
}
970
 
971
static cairo_status_t
972
create_string_entry (char *s, cairo_string_entry_t **entry)
973
{
974
    *entry = malloc (sizeof (cairo_string_entry_t));
975
    if (unlikely (*entry == NULL))
976
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
977
 
978
    _cairo_string_init_key (*entry, s);
979
 
980
    return CAIRO_STATUS_SUCCESS;
981
}
982
 
983
static void
984
_pluck_entry (void *entry, void *closure)
985
{
986
    _cairo_hash_table_remove (closure, entry);
987
    free (entry);
988
}
989
 
990
cairo_int_status_t
991
_cairo_scaled_font_subset_create_glyph_names (cairo_scaled_font_subset_t *subset)
992
{
993
    unsigned int i;
994
    cairo_hash_table_t *names;
995
    cairo_string_entry_t key, *entry;
996
    char buf[30];
997
    char *utf8;
998
    uint16_t *utf16;
999
    int utf16_len;
1000
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
1001
 
1002
    names = _cairo_hash_table_create (_cairo_string_equal);
1003
    if (unlikely (names == NULL))
1004
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1005
 
1006
    subset->glyph_names = calloc (subset->num_glyphs, sizeof (char *));
1007
    if (unlikely (subset->glyph_names == NULL)) {
1008
	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1009
	goto CLEANUP_HASH;
1010
    }
1011
 
1012
    i = 0;
1013
    if (! subset->is_scaled) {
1014
	subset->glyph_names[0] = strdup (".notdef");
1015
	if (unlikely (subset->glyph_names[0] == NULL)) {
1016
	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1017
	    goto CLEANUP_HASH;
1018
	}
1019
 
1020
	status = create_string_entry (subset->glyph_names[0], &entry);
1021
	if (unlikely (status))
1022
	    goto CLEANUP_HASH;
1023
 
1024
	status = _cairo_hash_table_insert (names, &entry->base);
1025
	if (unlikely (status)) {
1026
	    free (entry);
1027
	    goto CLEANUP_HASH;
1028
	}
1029
	i++;
1030
    }
1031
 
1032
    for (; i < subset->num_glyphs; i++) {
1033
	utf8 = subset->utf8[i];
1034
	utf16 = NULL;
1035
	utf16_len = 0;
1036
	if (utf8 && *utf8) {
1037
	    status = _cairo_utf8_to_utf16 (utf8, -1, &utf16, &utf16_len);
1038
	    if (unlikely (status))
1039
		goto CLEANUP_HASH;
1040
	}
1041
 
1042
	if (utf16_len == 1) {
1043
	    snprintf (buf, sizeof (buf), "uni%04X", (int) utf16[0]);
1044
	    _cairo_string_init_key (&key, buf);
1045
	    entry = _cairo_hash_table_lookup (names, &key.base);
1046
	    if (entry != NULL)
1047
		snprintf (buf, sizeof (buf), "g%d", i);
1048
	} else {
1049
	    snprintf (buf, sizeof (buf), "g%d", i);
1050
	}
1051
	if (utf16)
1052
	    free (utf16);
1053
 
1054
	subset->glyph_names[i] = strdup (buf);
1055
	if (unlikely (subset->glyph_names[i] == NULL)) {
1056
	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1057
	    goto CLEANUP_HASH;
1058
	}
1059
 
1060
	status = create_string_entry (subset->glyph_names[i], &entry);
1061
	if (unlikely (status))
1062
	    goto CLEANUP_HASH;
1063
 
1064
	status = _cairo_hash_table_insert (names, &entry->base);
1065
	if (unlikely (status)) {
1066
	    free (entry);
1067
	    goto CLEANUP_HASH;
1068
	}
1069
    }
1070
 
1071
CLEANUP_HASH:
1072
    _cairo_hash_table_foreach (names, _pluck_entry, names);
1073
    _cairo_hash_table_destroy (names);
1074
 
1075
    if (likely (status == CAIRO_STATUS_SUCCESS))
1076
	return CAIRO_STATUS_SUCCESS;
1077
 
1078
    if (subset->glyph_names != NULL) {
1079
	for (i = 0; i < subset->num_glyphs; i++) {
1080
	    if (subset->glyph_names[i] != NULL)
1081
		free (subset->glyph_names[i]);
1082
	}
1083
 
1084
	free (subset->glyph_names);
1085
	subset->glyph_names = NULL;
1086
    }
1087
 
1088
    return status;
1089
}
1090
 
1091
#endif /* CAIRO_HAS_FONT_SUBSET */