Coverage Report

Created: 2026-03-31 07:41

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