Coverage Report

Created: 2025-11-16 09:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/workdir/UnpackedTarball/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
0
#define MAX_GLYPHS_PER_SIMPLE_FONT 256
54
0
#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
0
{
153
0
    sub_font_glyph->base.hash = scaled_font_glyph_index;
154
0
}
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
0
{
167
0
    cairo_sub_font_glyph_t *sub_font_glyph;
168
169
0
    sub_font_glyph = _cairo_calloc (sizeof (cairo_sub_font_glyph_t));
170
0
    if (unlikely (sub_font_glyph == NULL)) {
171
0
  _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
172
0
  return NULL;
173
0
    }
174
175
0
    _cairo_sub_font_glyph_init_key (sub_font_glyph, scaled_font_glyph_index);
176
0
    sub_font_glyph->subset_id = subset_id;
177
0
    sub_font_glyph->subset_glyph_index = subset_glyph_index;
178
0
    sub_font_glyph->x_advance = x_advance;
179
0
    sub_font_glyph->y_advance = y_advance;
180
0
    sub_font_glyph->is_latin = (latin_character >= 0);
181
0
    sub_font_glyph->latin_character = latin_character;
182
0
    sub_font_glyph->is_mapped = FALSE;
183
0
    sub_font_glyph->unicode = unicode;
184
0
    sub_font_glyph->utf8 = utf8;
185
0
    sub_font_glyph->utf8_len = utf8_len;
186
187
0
    return sub_font_glyph;
188
0
}
189
190
static void
191
_cairo_sub_font_glyph_destroy (cairo_sub_font_glyph_t *sub_font_glyph)
192
0
{
193
0
    free (sub_font_glyph->utf8);
194
195
0
    free (sub_font_glyph);
196
0
}
197
198
static void
199
_cairo_sub_font_glyph_pluck (void *entry, void *closure)
200
0
{
201
0
    cairo_sub_font_glyph_t *sub_font_glyph = entry;
202
0
    cairo_hash_table_t *sub_font_glyphs = closure;
203
204
0
    _cairo_hash_table_remove (sub_font_glyphs, &sub_font_glyph->base);
205
0
    _cairo_sub_font_glyph_destroy (sub_font_glyph);
206
0
}
207
208
static void
209
_cairo_sub_font_glyph_collect (void *entry, void *closure)
210
0
{
211
0
    cairo_sub_font_glyph_t *sub_font_glyph = entry;
212
0
    cairo_sub_font_collection_t *collection = closure;
213
0
    unsigned long scaled_font_glyph_index;
214
0
    unsigned int subset_glyph_index;
215
216
0
    if (sub_font_glyph->subset_id != collection->subset_id)
217
0
  return;
218
219
0
    scaled_font_glyph_index = sub_font_glyph->base.hash;
220
0
    subset_glyph_index = sub_font_glyph->subset_glyph_index;
221
222
    /* Ensure we don't exceed the allocated bounds. */
223
0
    assert (subset_glyph_index < collection->glyphs_size);
224
225
0
    collection->glyphs[subset_glyph_index] = scaled_font_glyph_index;
226
0
    collection->utf8[subset_glyph_index] = sub_font_glyph->utf8;
227
0
    collection->to_latin_char[subset_glyph_index] = sub_font_glyph->latin_character;
228
0
    if (sub_font_glyph->is_latin)
229
0
  collection->latin_to_subset_glyph_index[sub_font_glyph->latin_character] = subset_glyph_index;
230
231
0
    if (subset_glyph_index > collection->max_glyph)
232
0
  collection->max_glyph = subset_glyph_index;
233
234
0
    collection->num_glyphs++;
235
0
}
236
237
static cairo_bool_t
238
_cairo_sub_fonts_equal (const void *key_a, const void *key_b)
239
0
{
240
0
    const cairo_sub_font_t *sub_font_a = key_a;
241
0
    const cairo_sub_font_t *sub_font_b = key_b;
242
0
    cairo_scaled_font_t *a = sub_font_a->scaled_font;
243
0
    cairo_scaled_font_t *b = sub_font_b->scaled_font;
244
245
0
    if (sub_font_a->is_scaled)
246
0
        return a == b;
247
0
    else
248
0
  return a->font_face == b->font_face || a->original_font_face == b->original_font_face;
249
0
}
250
251
static void
252
_cairo_sub_font_init_key (cairo_sub_font_t  *sub_font,
253
        cairo_scaled_font_t *scaled_font)
254
0
{
255
0
    if (sub_font->is_scaled)
256
0
    {
257
0
        sub_font->base.hash = (uintptr_t) scaled_font;
258
0
        sub_font->scaled_font = scaled_font;
259
0
    }
260
0
    else
261
0
    {
262
0
        sub_font->base.hash = (uintptr_t) scaled_font->font_face;
263
0
        sub_font->scaled_font = scaled_font;
264
0
    }
265
0
}
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
0
{
276
0
    cairo_sub_font_t *sub_font;
277
0
    int i;
278
279
0
    sub_font = _cairo_calloc (sizeof (cairo_sub_font_t));
280
0
    if (unlikely (sub_font == NULL))
281
0
  return _cairo_error (CAIRO_STATUS_NO_MEMORY);
282
283
0
    sub_font->is_scaled = is_scaled;
284
0
    sub_font->is_composite = is_composite;
285
0
    sub_font->reserve_notdef = !sub_font->is_scaled;
286
0
    _cairo_sub_font_init_key (sub_font, scaled_font);
287
288
0
    sub_font->parent = parent;
289
0
    sub_font->scaled_font = scaled_font;
290
0
    sub_font->font_id = font_id;
291
292
0
    sub_font->use_latin_subset = parent->use_latin_subset;
293
294
    /* latin subsets of Type 3 and CID CFF fonts are not supported */
295
0
    if (sub_font->is_scaled ||
296
0
  _cairo_cff_scaled_font_is_cid_cff (scaled_font) )
297
0
    {
298
0
  sub_font->use_latin_subset = FALSE;
299
0
    }
300
301
0
    if (sub_font->use_latin_subset)
302
0
  sub_font->current_subset = 1; /* reserve subset 0 for latin glyphs */
303
0
    else
304
0
  sub_font->current_subset = 0;
305
306
0
    sub_font->num_glyphs_in_current_subset = 0;
307
0
    sub_font->num_glyphs_in_latin_subset = 0;
308
0
    sub_font->max_glyphs_per_subset = max_glyphs_per_subset;
309
0
    for (i = 0; i < 256; i++)
310
0
  sub_font->latin_char_map[i] = FALSE;
311
312
0
    sub_font->sub_font_glyphs = _cairo_hash_table_create (NULL);
313
0
    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
0
    sub_font->next = NULL;
318
0
    *sub_font_out = sub_font;
319
0
    return CAIRO_STATUS_SUCCESS;
320
0
}
321
322
static void
323
_cairo_sub_font_destroy (cairo_sub_font_t *sub_font)
324
0
{
325
0
    _cairo_hash_table_foreach (sub_font->sub_font_glyphs,
326
0
             _cairo_sub_font_glyph_pluck,
327
0
             sub_font->sub_font_glyphs);
328
0
    _cairo_hash_table_destroy (sub_font->sub_font_glyphs);
329
0
    cairo_scaled_font_destroy (sub_font->scaled_font);
330
0
    free (sub_font);
331
0
}
332
333
static void
334
_cairo_sub_font_pluck (void *entry, void *closure)
335
0
{
336
0
    cairo_sub_font_t *sub_font = entry;
337
0
    cairo_hash_table_t *sub_fonts = closure;
338
339
0
    _cairo_hash_table_remove (sub_fonts, &sub_font->base);
340
0
    _cairo_sub_font_destroy (sub_font);
341
0
}
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
0
{
355
0
    int i;
356
357
    /* exclude the extra "hyphen" at 0xad to avoid duplicate glyphnames */
358
0
    if ((uni >= 0x20 && uni <= 0x7e) ||
359
0
  (uni >= 0xa1 && uni <= 0xff && uni != 0xad) ||
360
0
  uni == 0)
361
0
        return uni;
362
363
0
    for (i = 0; i < 32; i++)
364
0
  if (_winansi_0x80_to_0x9f[i] == uni)
365
0
      return i + 0x80;
366
367
0
    return -1;
368
0
}
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
0
{
377
0
    uint32_t unicode;
378
0
    char buf[8];
379
0
    int len;
380
0
    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
0
    unicode = -1;
385
0
    status = _cairo_truetype_index_to_ucs4 (scaled_font,
386
0
              scaled_font_glyph_index,
387
0
              &unicode);
388
0
    if (_cairo_status_is_error (status))
389
0
  return status;
390
391
0
    if (unicode == (uint32_t)-1 && scaled_font->backend->index_to_ucs4) {
392
0
  status = scaled_font->backend->index_to_ucs4 (scaled_font,
393
0
                  scaled_font_glyph_index,
394
0
                  &unicode);
395
0
  if (unlikely (status))
396
0
      return status;
397
0
    }
398
399
0
    *unicode_out = unicode;
400
0
    *utf8_out = NULL;
401
0
    *utf8_len_out = 0;
402
0
    if (unicode != (uint32_t) -1) {
403
0
  len = _cairo_ucs4_to_utf8 (unicode, buf);
404
0
  if (len > 0) {
405
0
            *utf8_out = _cairo_strndup (buf, len);
406
0
            if (unlikely (*utf8_out == NULL))
407
0
                return _cairo_error (CAIRO_STATUS_NO_MEMORY);
408
409
0
      *utf8_len_out = len;
410
0
  }
411
0
    }
412
413
0
    return CAIRO_STATUS_SUCCESS;
414
0
}
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
0
{
422
0
    *is_mapped = FALSE;
423
424
0
    if (utf8_len < 0)
425
0
  return CAIRO_STATUS_SUCCESS;
426
427
0
    if (utf8 != NULL && utf8_len != 0 && utf8[utf8_len - 1] == '\0')
428
0
  utf8_len--;
429
430
0
    if (utf8 != NULL && utf8_len != 0) {
431
0
  if (sub_font_glyph->utf8 != NULL) {
432
0
      if (utf8_len == sub_font_glyph->utf8_len &&
433
0
    strncmp (utf8, sub_font_glyph->utf8, utf8_len) == 0)
434
0
      {
435
    /* Requested utf8 mapping matches the existing mapping */
436
0
    *is_mapped = TRUE;
437
0
      }
438
0
  } else {
439
      /* No existing mapping. Use the requested mapping */
440
0
            sub_font_glyph->utf8 = _cairo_strndup (utf8, utf8_len);
441
0
            if (unlikely (sub_font_glyph->utf8 == NULL))
442
0
                return _cairo_error (CAIRO_STATUS_NO_MEMORY);
443
444
0
      sub_font_glyph->utf8_len = utf8_len;
445
0
      *is_mapped = TRUE;
446
0
  }
447
0
    }
448
449
0
    return CAIRO_STATUS_SUCCESS;
450
0
}
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
0
{
459
0
    cairo_sub_font_glyph_t key, *sub_font_glyph;
460
0
    cairo_int_status_t status;
461
462
0
    _cairo_sub_font_glyph_init_key (&key, scaled_font_glyph_index);
463
0
    sub_font_glyph = _cairo_hash_table_lookup (sub_font->sub_font_glyphs,
464
0
                &key.base);
465
0
    if (sub_font_glyph != NULL) {
466
0
        subset_glyph->font_id = sub_font->font_id;
467
0
        subset_glyph->subset_id = sub_font_glyph->subset_id;
468
0
  if (sub_font_glyph->is_latin)
469
0
      subset_glyph->subset_glyph_index = sub_font_glyph->latin_character;
470
0
  else
471
0
      subset_glyph->subset_glyph_index = sub_font_glyph->subset_glyph_index;
472
473
0
        subset_glyph->is_scaled = sub_font->is_scaled;
474
0
        subset_glyph->is_composite = sub_font->is_composite;
475
0
  subset_glyph->is_latin = sub_font_glyph->is_latin;
476
0
        subset_glyph->x_advance = sub_font_glyph->x_advance;
477
0
        subset_glyph->y_advance = sub_font_glyph->y_advance;
478
0
  status = _cairo_sub_font_glyph_map_to_unicode (sub_font_glyph,
479
0
                   utf8, utf8_len,
480
0
                   &subset_glyph->utf8_is_mapped);
481
0
  subset_glyph->unicode = sub_font_glyph->unicode;
482
483
0
  return status;
484
0
    }
485
486
0
    return CAIRO_INT_STATUS_UNSUPPORTED;
487
0
}
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
0
{
499
0
    cairo_scaled_glyph_t *scaled_glyph;
500
0
    cairo_sub_font_glyph_t *sub_font_glyph;
501
0
    int *num_glyphs_in_subset_ptr;
502
0
    double x_advance;
503
0
    double y_advance;
504
0
    cairo_int_status_t status;
505
506
0
    _cairo_scaled_font_freeze_cache (sub_font->scaled_font);
507
0
    status = _cairo_scaled_glyph_lookup (sub_font->scaled_font,
508
0
           scaled_font_glyph_index,
509
0
           CAIRO_SCALED_GLYPH_INFO_METRICS,
510
0
           NULL, /* foreground color */
511
0
           &scaled_glyph);
512
0
    assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
513
0
    if (unlikely (status)) {
514
0
  _cairo_scaled_font_thaw_cache (sub_font->scaled_font);
515
0
  return status;
516
0
    }
517
518
0
    x_advance = scaled_glyph->metrics.x_advance;
519
0
    y_advance = scaled_glyph->metrics.y_advance;
520
0
    _cairo_scaled_font_thaw_cache (sub_font->scaled_font);
521
522
0
    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
0
    if (is_latin)
529
0
  num_glyphs_in_subset_ptr = &sub_font->num_glyphs_in_latin_subset;
530
0
    else
531
0
  num_glyphs_in_subset_ptr = &sub_font->num_glyphs_in_current_subset;
532
533
0
    if ((*num_glyphs_in_subset_ptr == 0) && sub_font->reserve_notdef)
534
0
  (*num_glyphs_in_subset_ptr)++;
535
536
0
    sub_font_glyph = _cairo_sub_font_glyph_create (scaled_font_glyph_index,
537
0
               is_latin ? 0 : sub_font->current_subset,
538
0
               *num_glyphs_in_subset_ptr,
539
0
               x_advance,
540
0
               y_advance,
541
0
               is_latin ? latin_character : -1,
542
0
               unicode,
543
0
               utf8,
544
0
               utf8_len);
545
546
0
    if (unlikely (sub_font_glyph == NULL))
547
0
  return _cairo_error (CAIRO_STATUS_NO_MEMORY);
548
549
0
    status = _cairo_hash_table_insert (sub_font->sub_font_glyphs, &sub_font_glyph->base);
550
0
    if (unlikely (status)) {
551
0
  _cairo_sub_font_glyph_destroy (sub_font_glyph);
552
0
  return status;
553
0
    }
554
555
0
    (*num_glyphs_in_subset_ptr)++;
556
0
    if (sub_font->is_scaled) {
557
0
  if (*num_glyphs_in_subset_ptr > sub_font->parent->max_glyphs_per_scaled_subset_used)
558
0
      sub_font->parent->max_glyphs_per_scaled_subset_used = *num_glyphs_in_subset_ptr;
559
0
    } else {
560
0
  if (*num_glyphs_in_subset_ptr > sub_font->parent->max_glyphs_per_unscaled_subset_used)
561
0
      sub_font->parent->max_glyphs_per_unscaled_subset_used = *num_glyphs_in_subset_ptr;
562
0
    }
563
564
0
    *sub_font_glyph_out = sub_font_glyph;
565
566
0
    return CAIRO_STATUS_SUCCESS;
567
0
}
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
0
{
576
0
    cairo_sub_font_glyph_t key, *sub_font_glyph;
577
0
    cairo_status_t status;
578
579
0
    _cairo_sub_font_glyph_init_key (&key, scaled_font_glyph_index);
580
0
    sub_font_glyph = _cairo_hash_table_lookup (sub_font->sub_font_glyphs,
581
0
                 &key.base);
582
0
    if (sub_font_glyph == NULL) {
583
0
  uint32_t font_unicode;
584
0
  char *font_utf8;
585
0
  int font_utf8_len;
586
0
  cairo_bool_t is_latin;
587
0
  int latin_character;
588
589
0
  status = _cairo_sub_font_glyph_lookup_unicode (sub_font->scaled_font,
590
0
                 scaled_font_glyph_index,
591
0
                 &font_unicode,
592
0
                 &font_utf8,
593
0
                 &font_utf8_len);
594
0
  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
0
  if (text_utf8 != NULL && text_utf8_len > 0) {
600
0
      uint32_t  *ucs4;
601
0
      int ucs4_len;
602
603
0
      status = _cairo_utf8_to_ucs4 (text_utf8, text_utf8_len,
604
0
            &ucs4, &ucs4_len);
605
0
      if (status == CAIRO_STATUS_SUCCESS) {
606
0
    if (ucs4_len == 1) {
607
0
        font_unicode = ucs4[0];
608
0
        free (font_utf8);
609
0
                    font_utf8 = _cairo_strndup (text_utf8, text_utf8_len);
610
0
                    if (font_utf8 == NULL) {
611
0
                        free (ucs4);
612
0
                        return _cairo_error (CAIRO_STATUS_NO_MEMORY);
613
0
        }
614
0
        font_utf8_len = text_utf8_len;
615
0
    }
616
0
    free (ucs4);
617
0
      }
618
0
  }
619
620
  /* If glyph is in the winansi encoding and font is not a scaled
621
   * font, put glyph in the latin subset. */
622
0
  is_latin = FALSE;
623
0
  latin_character = -1;
624
0
  if (sub_font->use_latin_subset && !sub_font->is_scaled)
625
0
  {
626
0
      latin_character = _cairo_unicode_to_winansi (font_unicode);
627
0
      if (latin_character > 0)
628
0
      {
629
0
    if (!sub_font->latin_char_map[latin_character]) {
630
0
        sub_font->latin_char_map[latin_character] = TRUE;
631
0
        is_latin = TRUE;
632
0
    }
633
0
      }
634
0
  }
635
636
0
  status = _cairo_sub_font_add_glyph (sub_font,
637
0
              scaled_font_glyph_index,
638
0
              is_latin,
639
0
              latin_character,
640
0
              font_unicode,
641
0
              font_utf8,
642
0
              font_utf8_len,
643
0
              &sub_font_glyph);
644
0
  if (unlikely(status))
645
0
      return status;
646
0
    }
647
648
0
    subset_glyph->font_id = sub_font->font_id;
649
0
    subset_glyph->subset_id = sub_font_glyph->subset_id;
650
0
    if (sub_font_glyph->is_latin)
651
0
  subset_glyph->subset_glyph_index = sub_font_glyph->latin_character;
652
0
    else
653
0
  subset_glyph->subset_glyph_index = sub_font_glyph->subset_glyph_index;
654
655
0
    subset_glyph->is_scaled = sub_font->is_scaled;
656
0
    subset_glyph->is_composite = sub_font->is_composite;
657
0
    subset_glyph->is_latin = sub_font_glyph->is_latin;
658
0
    subset_glyph->x_advance = sub_font_glyph->x_advance;
659
0
    subset_glyph->y_advance = sub_font_glyph->y_advance;
660
0
    status = _cairo_sub_font_glyph_map_to_unicode (sub_font_glyph,
661
0
               text_utf8, text_utf8_len,
662
0
               &subset_glyph->utf8_is_mapped);
663
0
    subset_glyph->unicode = sub_font_glyph->unicode;
664
665
0
    return status;
666
0
}
667
668
static void
669
_cairo_sub_font_collect (void *entry, void *closure)
670
0
{
671
0
    cairo_sub_font_t *sub_font = entry;
672
0
    cairo_sub_font_collection_t *collection = closure;
673
0
    cairo_scaled_font_subset_t subset;
674
0
    int i;
675
0
    unsigned int j;
676
677
0
    if (collection->status)
678
0
  return;
679
680
0
    collection->status = sub_font->scaled_font->status;
681
0
    if (collection->status)
682
0
  return;
683
684
0
    for (i = 0; i <= sub_font->current_subset; i++) {
685
0
  collection->subset_id = i;
686
0
  collection->num_glyphs = 0;
687
0
  collection->max_glyph = 0;
688
0
  memset (collection->latin_to_subset_glyph_index, 0, 256*sizeof(unsigned long));
689
690
0
  if (sub_font->reserve_notdef) {
691
      // add .notdef
692
0
      collection->glyphs[0] = 0;
693
0
      collection->utf8[0] = 0;
694
0
      collection->to_latin_char[0] = 0;
695
0
      collection->latin_to_subset_glyph_index[0] = 0;
696
0
      collection->num_glyphs++;
697
0
  }
698
699
0
  _cairo_hash_table_foreach (sub_font->sub_font_glyphs,
700
0
           _cairo_sub_font_glyph_collect, collection);
701
0
  if (collection->status)
702
0
      break;
703
704
0
  if (collection->num_glyphs == 0)
705
0
      continue;
706
707
0
  if (sub_font->reserve_notdef && collection->num_glyphs == 1)
708
0
      continue;
709
710
        /* Ensure the resulting array has no uninitialized holes */
711
0
  assert (collection->num_glyphs == collection->max_glyph + 1);
712
713
0
  subset.scaled_font = sub_font->scaled_font;
714
0
  subset.is_composite = sub_font->is_composite;
715
0
  subset.is_scaled = sub_font->is_scaled;
716
0
  subset.font_id = sub_font->font_id;
717
0
  subset.subset_id = i;
718
0
  subset.glyphs = collection->glyphs;
719
0
  subset.utf8 = collection->utf8;
720
0
  subset.num_glyphs = collection->num_glyphs;
721
0
        subset.glyph_names = NULL;
722
723
0
  subset.is_latin = FALSE;
724
0
  if (sub_font->use_latin_subset && i == 0) {
725
0
      subset.is_latin = TRUE;
726
0
      subset.to_latin_char = collection->to_latin_char;
727
0
      subset.latin_to_subset_glyph_index = collection->latin_to_subset_glyph_index;
728
0
  } else {
729
0
      subset.to_latin_char = NULL;
730
0
      subset.latin_to_subset_glyph_index = NULL;
731
0
  }
732
733
0
        collection->status = (collection->font_subset_callback) (&subset,
734
0
              collection->font_subset_callback_closure);
735
736
0
  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
0
  if (collection->status)
743
0
      break;
744
0
    }
745
0
}
746
747
static cairo_scaled_font_subsets_t *
748
_cairo_scaled_font_subsets_create_internal (cairo_subsets_type_t type)
749
2
{
750
2
    cairo_scaled_font_subsets_t *subsets;
751
752
2
    subsets = _cairo_calloc (sizeof (cairo_scaled_font_subsets_t));
753
2
    if (unlikely (subsets == NULL)) {
754
0
  _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
755
0
  return NULL;
756
0
    }
757
758
2
    subsets->type = type;
759
2
    subsets->use_latin_subset = FALSE;
760
2
    subsets->max_glyphs_per_unscaled_subset_used = 0;
761
2
    subsets->max_glyphs_per_scaled_subset_used = 0;
762
2
    subsets->num_sub_fonts = 0;
763
764
2
    subsets->unscaled_sub_fonts = _cairo_hash_table_create (_cairo_sub_fonts_equal);
765
2
    if (! subsets->unscaled_sub_fonts) {
766
0
  free (subsets);
767
0
  return NULL;
768
0
    }
769
2
    subsets->unscaled_sub_fonts_list = NULL;
770
2
    subsets->unscaled_sub_fonts_list_end = NULL;
771
772
2
    subsets->scaled_sub_fonts = _cairo_hash_table_create (_cairo_sub_fonts_equal);
773
2
    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
2
    subsets->scaled_sub_fonts_list = NULL;
779
2
    subsets->scaled_sub_fonts_list_end = NULL;
780
781
2
    return subsets;
782
2
}
783
784
cairo_scaled_font_subsets_t *
785
_cairo_scaled_font_subsets_create_scaled (void)
786
2
{
787
2
    return _cairo_scaled_font_subsets_create_internal (CAIRO_SUBSETS_SCALED);
788
2
}
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
0
{
799
0
    return _cairo_scaled_font_subsets_create_internal (CAIRO_SUBSETS_COMPOSITE);
800
0
}
801
802
void
803
_cairo_scaled_font_subsets_destroy (cairo_scaled_font_subsets_t *subsets)
804
2
{
805
2
    _cairo_hash_table_foreach (subsets->scaled_sub_fonts, _cairo_sub_font_pluck, subsets->scaled_sub_fonts);
806
2
    _cairo_hash_table_destroy (subsets->scaled_sub_fonts);
807
808
2
    _cairo_hash_table_foreach (subsets->unscaled_sub_fonts, _cairo_sub_font_pluck, subsets->unscaled_sub_fonts);
809
2
    _cairo_hash_table_destroy (subsets->unscaled_sub_fonts);
810
811
2
    free (subsets);
812
2
}
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
0
{
818
0
    font_subsets->use_latin_subset = use_latin;
819
0
}
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
0
{
829
0
    cairo_sub_font_t key, *sub_font;
830
0
    cairo_scaled_glyph_t *scaled_glyph;
831
0
    cairo_font_face_t *font_face;
832
0
    cairo_matrix_t identity;
833
0
    cairo_font_options_t font_options;
834
0
    cairo_scaled_font_t *unscaled_font;
835
0
    cairo_int_status_t status;
836
0
    int max_glyphs;
837
0
    cairo_bool_t type1_font;
838
0
    cairo_bool_t has_path;
839
0
    cairo_bool_t has_color;
840
0
    cairo_bool_t is_user;
841
842
    /* Lookup glyph in unscaled subsets */
843
0
    if (subsets->type != CAIRO_SUBSETS_SCALED) {
844
0
        key.is_scaled = FALSE;
845
0
        _cairo_sub_font_init_key (&key, scaled_font);
846
0
  sub_font = _cairo_hash_table_lookup (subsets->unscaled_sub_fonts,
847
0
               &key.base);
848
0
        if (sub_font != NULL) {
849
0
            status = _cairo_sub_font_lookup_glyph (sub_font,
850
0
               scaled_font_glyph_index,
851
0
               utf8, utf8_len,
852
0
               subset_glyph);
853
0
      if (status != CAIRO_INT_STATUS_UNSUPPORTED)
854
0
                return status;
855
0
        }
856
0
    }
857
858
    /* Lookup glyph in scaled subsets */
859
0
    key.is_scaled = TRUE;
860
0
    _cairo_sub_font_init_key (&key, scaled_font);
861
0
    sub_font = _cairo_hash_table_lookup (subsets->scaled_sub_fonts,
862
0
           &key.base);
863
0
    if (sub_font != NULL) {
864
0
  status = _cairo_sub_font_lookup_glyph (sub_font,
865
0
                 scaled_font_glyph_index,
866
0
                 utf8, utf8_len,
867
0
                 subset_glyph);
868
0
  if (status != CAIRO_INT_STATUS_UNSUPPORTED)
869
0
      return status;
870
0
    }
871
872
    /* Glyph not found. Determine whether the glyph is outline or
873
     * bitmap and add to the appropriate subset.
874
     */
875
0
    is_user = _cairo_font_face_is_user (scaled_font->font_face);
876
0
    _cairo_scaled_font_freeze_cache (scaled_font);
877
    /* Check if glyph is color */
878
0
    status = _cairo_scaled_glyph_lookup (scaled_font,
879
0
           scaled_font_glyph_index,
880
0
           CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE,
881
0
           NULL, /* foreground color */
882
0
           &scaled_glyph);
883
0
    has_color = (status == CAIRO_INT_STATUS_SUCCESS);
884
885
    /* Check if glyph has a path */
886
0
    status = _cairo_scaled_glyph_lookup (scaled_font,
887
0
           scaled_font_glyph_index,
888
0
           CAIRO_SCALED_GLYPH_INFO_PATH,
889
0
           NULL, /* foreground color */
890
0
           &scaled_glyph);
891
0
    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
0
    if (scaled_font_glyph_index == 0 && !is_user)
900
0
        has_path = TRUE;
901
902
    /* If this fails there is nothing we can do with this glyph. */
903
0
    status = _cairo_scaled_glyph_lookup (scaled_font,
904
0
           scaled_font_glyph_index,
905
0
           CAIRO_SCALED_GLYPH_INFO_SURFACE,
906
0
                                             NULL, /* foreground color */
907
0
           &scaled_glyph);
908
0
    _cairo_scaled_font_thaw_cache (scaled_font);
909
0
    if (_cairo_int_status_is_error (status))
910
0
        return status;
911
912
    /* Type 3 glyphs (is_user and has_color) must be added to scaled subset */
913
0
    if (subsets->type != CAIRO_SUBSETS_SCALED &&
914
0
  has_path && !has_color && !is_user)
915
0
    {
916
        /* Path available. Add to unscaled subset. */
917
0
        key.is_scaled = FALSE;
918
0
        _cairo_sub_font_init_key (&key, scaled_font);
919
0
  sub_font = _cairo_hash_table_lookup (subsets->unscaled_sub_fonts,
920
0
               &key.base);
921
0
        if (sub_font == NULL) {
922
0
            font_face = cairo_scaled_font_get_font_face (scaled_font);
923
0
            cairo_matrix_init_identity (&identity);
924
0
            _cairo_font_options_init_default (&font_options);
925
0
            cairo_scaled_font_get_font_options (scaled_font, &font_options);
926
0
            cairo_font_options_set_hint_style (&font_options, CAIRO_HINT_STYLE_NONE);
927
0
            cairo_font_options_set_hint_metrics (&font_options, CAIRO_HINT_METRICS_OFF);
928
0
            unscaled_font = cairo_scaled_font_create (font_face,
929
0
                                                      &identity,
930
0
                                                      &identity,
931
0
                                                      &font_options);
932
0
      if (unlikely (unscaled_font->status))
933
0
    return unscaled_font->status;
934
935
0
            subset_glyph->is_scaled = FALSE;
936
0
            type1_font = _cairo_type1_scaled_font_is_type1 (unscaled_font);
937
0
            if (subsets->type == CAIRO_SUBSETS_COMPOSITE && !type1_font) {
938
0
                max_glyphs = MAX_GLYPHS_PER_COMPOSITE_FONT;
939
0
                subset_glyph->is_composite = TRUE;
940
0
            } else {
941
0
                max_glyphs = MAX_GLYPHS_PER_SIMPLE_FONT;
942
0
                subset_glyph->is_composite = FALSE;
943
0
            }
944
945
0
            status = _cairo_sub_font_create (subsets,
946
0
               unscaled_font,
947
0
               subsets->num_sub_fonts,
948
0
               max_glyphs,
949
0
               subset_glyph->is_scaled,
950
0
               subset_glyph->is_composite,
951
0
               &sub_font);
952
953
0
            if (unlikely (status)) {
954
0
    cairo_scaled_font_destroy (unscaled_font);
955
0
                return status;
956
0
      }
957
958
0
            status = _cairo_hash_table_insert (subsets->unscaled_sub_fonts,
959
0
                                               &sub_font->base);
960
961
0
            if (unlikely (status)) {
962
0
    _cairo_sub_font_destroy (sub_font);
963
0
                return status;
964
0
      }
965
0
      if (!subsets->unscaled_sub_fonts_list)
966
0
    subsets->unscaled_sub_fonts_list = sub_font;
967
0
      else
968
0
    subsets->unscaled_sub_fonts_list_end->next = sub_font;
969
0
      subsets->unscaled_sub_fonts_list_end = sub_font;
970
0
      subsets->num_sub_fonts++;
971
0
        }
972
0
    } else {
973
        /* No path available. Add to scaled subset. */
974
0
        key.is_scaled = TRUE;
975
0
        _cairo_sub_font_init_key (&key, scaled_font);
976
0
  sub_font = _cairo_hash_table_lookup (subsets->scaled_sub_fonts,
977
0
               &key.base);
978
0
        if (sub_font == NULL) {
979
0
            subset_glyph->is_scaled = TRUE;
980
0
            subset_glyph->is_composite = FALSE;
981
0
            if (subsets->type == CAIRO_SUBSETS_SCALED)
982
0
                max_glyphs = INT_MAX;
983
0
            else
984
0
                max_glyphs = MAX_GLYPHS_PER_SIMPLE_FONT;
985
986
0
            status = _cairo_sub_font_create (subsets,
987
0
               cairo_scaled_font_reference (scaled_font),
988
0
               subsets->num_sub_fonts,
989
0
               max_glyphs,
990
0
               subset_glyph->is_scaled,
991
0
               subset_glyph->is_composite,
992
0
               &sub_font);
993
0
            if (unlikely (status)) {
994
0
    cairo_scaled_font_destroy (scaled_font);
995
0
                return status;
996
0
      }
997
998
0
            status = _cairo_hash_table_insert (subsets->scaled_sub_fonts,
999
0
                                               &sub_font->base);
1000
0
            if (unlikely (status)) {
1001
0
    _cairo_sub_font_destroy (sub_font);
1002
0
                return status;
1003
0
      }
1004
0
      if (!subsets->scaled_sub_fonts_list)
1005
0
    subsets->scaled_sub_fonts_list = sub_font;
1006
0
      else
1007
0
    subsets->scaled_sub_fonts_list_end->next = sub_font;
1008
0
      subsets->scaled_sub_fonts_list_end = sub_font;
1009
0
      subsets->num_sub_fonts++;
1010
0
        }
1011
0
    }
1012
1013
0
    return _cairo_sub_font_map_glyph (sub_font,
1014
0
              scaled_font_glyph_index,
1015
0
              utf8, utf8_len,
1016
0
              subset_glyph);
1017
0
}
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
2
{
1025
2
    cairo_sub_font_collection_t collection;
1026
2
    cairo_sub_font_t *sub_font;
1027
2
    cairo_bool_t is_scaled;
1028
1029
2
    is_scaled = FALSE;
1030
1031
2
    if (type == CAIRO_SUBSETS_FOREACH_SCALED)
1032
2
  is_scaled = TRUE;
1033
1034
2
    if (is_scaled)
1035
2
        collection.glyphs_size = font_subsets->max_glyphs_per_scaled_subset_used;
1036
0
    else
1037
0
        collection.glyphs_size = font_subsets->max_glyphs_per_unscaled_subset_used;
1038
1039
2
    if (! collection.glyphs_size)
1040
2
  return CAIRO_STATUS_SUCCESS;
1041
1042
0
    collection.glyphs = _cairo_malloc_ab (collection.glyphs_size, sizeof(unsigned long));
1043
0
    collection.utf8 = _cairo_malloc_ab (collection.glyphs_size, sizeof(char *));
1044
0
    collection.to_latin_char = _cairo_malloc_ab (collection.glyphs_size, sizeof(int));
1045
0
    collection.latin_to_subset_glyph_index = _cairo_malloc_ab (256, sizeof(unsigned long));
1046
0
    if (unlikely (collection.glyphs == NULL ||
1047
0
      collection.utf8 == NULL ||
1048
0
      collection.to_latin_char == NULL ||
1049
0
      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
0
    collection.font_subset_callback = font_subset_callback;
1059
0
    collection.font_subset_callback_closure = closure;
1060
0
    collection.status = CAIRO_STATUS_SUCCESS;
1061
1062
0
    if (is_scaled)
1063
0
  sub_font = font_subsets->scaled_sub_fonts_list;
1064
0
    else
1065
0
  sub_font = font_subsets->unscaled_sub_fonts_list;
1066
1067
0
    while (sub_font) {
1068
0
  _cairo_sub_font_collect (sub_font, &collection);
1069
0
  sub_font = sub_font->next;
1070
0
    }
1071
0
    free (collection.utf8);
1072
0
    free (collection.glyphs);
1073
0
    free (collection.to_latin_char);
1074
0
    free (collection.latin_to_subset_glyph_index);
1075
1076
0
    return collection.status;
1077
0
}
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
2
{
1084
2
    return _cairo_scaled_font_subsets_foreach_internal (font_subsets,
1085
2
                                                        font_subset_callback,
1086
2
                                                        closure,
1087
2
              CAIRO_SUBSETS_FOREACH_SCALED);
1088
2
}
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
0
{
1095
0
    return _cairo_scaled_font_subsets_foreach_internal (font_subsets,
1096
0
                                                        font_subset_callback,
1097
0
                                                        closure,
1098
0
              CAIRO_SUBSETS_FOREACH_UNSCALED);
1099
0
}
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
0
{
1338
0
    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
0
    if (*ps_name) {
1346
0
  static const char *reserved = "()<>[]{}/%#\\";
1347
0
  char buf[128]; /* max name length is 127 bytes */
1348
0
  char *src = *ps_name;
1349
0
  char *dst = buf;
1350
1351
0
  while (*src && dst < buf + 127) {
1352
0
      unsigned char c = *src;
1353
0
      if (c < 0x21 || c > 0x7e || strchr (reserved, c)) {
1354
0
    if (dst + 4 > buf + 127)
1355
0
        break;
1356
1357
0
    snprintf (dst, 4, "#%02X", c);
1358
0
    src++;
1359
0
    dst += 3;
1360
0
      } else {
1361
0
    *dst++ = *src++;
1362
0
      }
1363
0
  }
1364
0
  *dst = 0;
1365
0
  free (*ps_name);
1366
0
  *ps_name = strdup (buf);
1367
0
  if (*ps_name == NULL) {
1368
0
      status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1369
0
  }
1370
0
    }
1371
1372
0
    return status;
1373
0
}
1374
1375
#endif /* CAIRO_HAS_FONT_SUBSET */