Subversion Repositories Scribus

Rev

Rev 14952 | Details | Compare with Previous | Last modification | View Log | RSS feed

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