Coverage Report

Created: 2025-07-07 10:01

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