Coverage Report

Created: 2026-10-17 07:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/harfbuzz/src/hb-ot-cmap-table.hh
Line
Count
Source
1
/*
2
 * Copyright © 2014  Google, Inc.
3
 *
4
 *  This is part of HarfBuzz, a text shaping library.
5
 *
6
 * Permission is hereby granted, without written agreement and without
7
 * license or royalty fees, to use, copy, modify, and distribute this
8
 * software and its documentation for any purpose, provided that the
9
 * above copyright notice and the following two paragraphs appear in
10
 * all copies of this software.
11
 *
12
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15
 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16
 * DAMAGE.
17
 *
18
 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20
 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
21
 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23
 *
24
 * Google Author(s): Behdad Esfahbod
25
 */
26
27
#ifndef HB_OT_CMAP_TABLE_HH
28
#define HB_OT_CMAP_TABLE_HH
29
30
#include "hb-ot-os2-table.hh"
31
#include "hb-ot-shaper-arabic-pua.hh"
32
#include "hb-open-type.hh"
33
#include "hb-ot-dual.hh"
34
#include "hb-set.hh"
35
#include "hb-cache.hh"
36
37
/*
38
 * cmap -- Character to Glyph Index Mapping
39
 * https://docs.microsoft.com/en-us/typography/opentype/spec/cmap
40
 */
41
#define HB_OT_TAG_cmap HB_TAG('c','m','a','p')
42
0
#define HB_OT_TAG_DMAP HB_TAG('D','M','A','P')
43
44
namespace OT {
45
46
static inline uint8_t unicode_to_macroman (hb_codepoint_t u)
47
0
{
48
0
  static const struct unicode_to_macroman_t
49
0
  {
50
0
    uint16_t unicode;
51
0
    uint8_t macroman;
52
0
  }
53
0
  mapping[] =
54
0
  {
55
0
    { 0x00A0, 0xCA },
56
0
    { 0x00A1, 0xC1 },
57
0
    { 0x00A2, 0xA2 },
58
0
    { 0x00A3, 0xA3 },
59
0
    { 0x00A5, 0xB4 },
60
0
    { 0x00A7, 0xA4 },
61
0
    { 0x00A8, 0xAC },
62
0
    { 0x00A9, 0xA9 },
63
0
    { 0x00AA, 0xBB },
64
0
    { 0x00AB, 0xC7 },
65
0
    { 0x00AC, 0xC2 },
66
0
    { 0x00AE, 0xA8 },
67
0
    { 0x00AF, 0xF8 },
68
0
    { 0x00B0, 0xA1 },
69
0
    { 0x00B1, 0xB1 },
70
0
    { 0x00B4, 0xAB },
71
0
    { 0x00B5, 0xB5 },
72
0
    { 0x00B6, 0xA6 },
73
0
    { 0x00B7, 0xE1 },
74
0
    { 0x00B8, 0xFC },
75
0
    { 0x00BA, 0xBC },
76
0
    { 0x00BB, 0xC8 },
77
0
    { 0x00BF, 0xC0 },
78
0
    { 0x00C0, 0xCB },
79
0
    { 0x00C1, 0xE7 },
80
0
    { 0x00C2, 0xE5 },
81
0
    { 0x00C3, 0xCC },
82
0
    { 0x00C4, 0x80 },
83
0
    { 0x00C5, 0x81 },
84
0
    { 0x00C6, 0xAE },
85
0
    { 0x00C7, 0x82 },
86
0
    { 0x00C8, 0xE9 },
87
0
    { 0x00C9, 0x83 },
88
0
    { 0x00CA, 0xE6 },
89
0
    { 0x00CB, 0xE8 },
90
0
    { 0x00CC, 0xED },
91
0
    { 0x00CD, 0xEA },
92
0
    { 0x00CE, 0xEB },
93
0
    { 0x00CF, 0xEC },
94
0
    { 0x00D1, 0x84 },
95
0
    { 0x00D2, 0xF1 },
96
0
    { 0x00D3, 0xEE },
97
0
    { 0x00D4, 0xEF },
98
0
    { 0x00D5, 0xCD },
99
0
    { 0x00D6, 0x85 },
100
0
    { 0x00D8, 0xAF },
101
0
    { 0x00D9, 0xF4 },
102
0
    { 0x00DA, 0xF2 },
103
0
    { 0x00DB, 0xF3 },
104
0
    { 0x00DC, 0x86 },
105
0
    { 0x00DF, 0xA7 },
106
0
    { 0x00E0, 0x88 },
107
0
    { 0x00E1, 0x87 },
108
0
    { 0x00E2, 0x89 },
109
0
    { 0x00E3, 0x8B },
110
0
    { 0x00E4, 0x8A },
111
0
    { 0x00E5, 0x8C },
112
0
    { 0x00E6, 0xBE },
113
0
    { 0x00E7, 0x8D },
114
0
    { 0x00E8, 0x8F },
115
0
    { 0x00E9, 0x8E },
116
0
    { 0x00EA, 0x90 },
117
0
    { 0x00EB, 0x91 },
118
0
    { 0x00EC, 0x93 },
119
0
    { 0x00ED, 0x92 },
120
0
    { 0x00EE, 0x94 },
121
0
    { 0x00EF, 0x95 },
122
0
    { 0x00F1, 0x96 },
123
0
    { 0x00F2, 0x98 },
124
0
    { 0x00F3, 0x97 },
125
0
    { 0x00F4, 0x99 },
126
0
    { 0x00F5, 0x9B },
127
0
    { 0x00F6, 0x9A },
128
0
    { 0x00F7, 0xD6 },
129
0
    { 0x00F8, 0xBF },
130
0
    { 0x00F9, 0x9D },
131
0
    { 0x00FA, 0x9C },
132
0
    { 0x00FB, 0x9E },
133
0
    { 0x00FC, 0x9F },
134
0
    { 0x00FF, 0xD8 },
135
0
    { 0x0131, 0xF5 },
136
0
    { 0x0152, 0xCE },
137
0
    { 0x0153, 0xCF },
138
0
    { 0x0178, 0xD9 },
139
0
    { 0x0192, 0xC4 },
140
0
    { 0x02C6, 0xF6 },
141
0
    { 0x02C7, 0xFF },
142
0
    { 0x02D8, 0xF9 },
143
0
    { 0x02D9, 0xFA },
144
0
    { 0x02DA, 0xFB },
145
0
    { 0x02DB, 0xFE },
146
0
    { 0x02DC, 0xF7 },
147
0
    { 0x02DD, 0xFD },
148
0
    { 0x03A9, 0xBD },
149
0
    { 0x03C0, 0xB9 },
150
0
    { 0x2013, 0xD0 },
151
0
    { 0x2014, 0xD1 },
152
0
    { 0x2018, 0xD4 },
153
0
    { 0x2019, 0xD5 },
154
0
    { 0x201A, 0xE2 },
155
0
    { 0x201C, 0xD2 },
156
0
    { 0x201D, 0xD3 },
157
0
    { 0x201E, 0xE3 },
158
0
    { 0x2020, 0xA0 },
159
0
    { 0x2021, 0xE0 },
160
0
    { 0x2022, 0xA5 },
161
0
    { 0x2026, 0xC9 },
162
0
    { 0x2030, 0xE4 },
163
0
    { 0x2039, 0xDC },
164
0
    { 0x203A, 0xDD },
165
0
    { 0x2044, 0xDA },
166
0
    { 0x20AC, 0xDB },
167
0
    { 0x2122, 0xAA },
168
0
    { 0x2202, 0xB6 },
169
0
    { 0x2206, 0xC6 },
170
0
    { 0x220F, 0xB8 },
171
0
    { 0x2211, 0xB7 },
172
0
    { 0x221A, 0xC3 },
173
0
    { 0x221E, 0xB0 },
174
0
    { 0x222B, 0xBA },
175
0
    { 0x2248, 0xC5 },
176
0
    { 0x2260, 0xAD },
177
0
    { 0x2264, 0xB2 },
178
0
    { 0x2265, 0xB3 },
179
0
    { 0x25CA, 0xD7 },
180
0
    { 0xF8FF, 0xF0 },
181
0
    { 0xFB01, 0xDE },
182
0
    { 0xFB02, 0xDF },
183
0
  };
184
0
  auto *c = hb_bsearch (u, mapping, ARRAY_LENGTH (mapping), sizeof (mapping[0]),
185
0
      _hb_cmp_operator<uint16_t, uint16_t>);
186
0
  return c ? c->macroman : 0;
187
0
}
Unexecuted instantiation: hb-face.cc:OT::unicode_to_macroman(unsigned int)
Unexecuted instantiation: hb-ot-face.cc:OT::unicode_to_macroman(unsigned int)
Unexecuted instantiation: hb-ot-font.cc:OT::unicode_to_macroman(unsigned int)
Unexecuted instantiation: hb-static.cc:OT::unicode_to_macroman(unsigned int)
188
189
struct CmapSubtableFormat0
190
{
191
  bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
192
0
  {
193
0
    hb_codepoint_t gid = codepoint < 256 ? glyphIdArray[codepoint] : 0;
194
0
    if (unlikely (!gid))
195
0
      return false;
196
0
    *glyph = gid;
197
0
    return true;
198
0
  }
199
200
  unsigned get_language () const
201
0
  {
202
0
    return language;
203
0
  }
204
205
  void collect_unicodes (hb_set_t *out) const
206
0
  {
207
0
    for (unsigned int i = 0; i < 256; i++)
208
0
      if (glyphIdArray[i])
209
0
  out->add (i);
210
0
  }
211
212
  void collect_mapping (hb_set_t *unicodes, /* OUT */
213
      hb_map_t *mapping /* OUT */) const
214
0
  {
215
0
    for (unsigned i = 0; i < 256; i++)
216
0
      if (glyphIdArray[i])
217
0
      {
218
0
  hb_codepoint_t glyph = glyphIdArray[i];
219
0
  unicodes->add (i);
220
0
  mapping->set (i, glyph);
221
0
      }
222
0
  }
223
224
  bool sanitize (hb_sanitize_context_t *c) const
225
0
  {
226
0
    TRACE_SANITIZE (this);
227
0
    return_trace (c->check_struct (this));
228
0
  }
229
230
  protected:
231
  HBUINT16  format;   /* Format number is set to 0. */
232
  HBUINT16  length;   /* Byte length of this subtable. */
233
  HBUINT16  language; /* Ignore. */
234
  HBUINT8 glyphIdArray[256];/* An array that maps character
235
         * code to glyph index values. */
236
  public:
237
  DEFINE_SIZE_STATIC (6 + 256);
238
};
239
240
struct CmapSubtableFormat4
241
{
242
  template<typename Iterator,
243
      typename Writer,
244
     hb_requires (hb_is_iterator (Iterator))>
245
  void to_ranges (Iterator it, Writer& range_writer)
246
0
  {
247
0
    hb_codepoint_t start_cp = 0, prev_run_start_cp = 0, run_start_cp = 0, end_cp = 0, last_gid = 0;
248
0
    int run_length = 0 , delta = 0, prev_delta = 0;
249
0
250
0
    enum {
251
0
      FIRST_SUB_RANGE,
252
0
      FOLLOWING_SUB_RANGE,
253
0
    } mode;
254
0
255
0
    while (it) {
256
0
      // Start a new range
257
0
      {
258
0
        const auto& pair = *it;
259
0
        start_cp = pair.first;
260
0
        prev_run_start_cp = start_cp;
261
0
        run_start_cp = start_cp;
262
0
        end_cp = start_cp;
263
0
        last_gid = pair.second;
264
0
        run_length = 1;
265
0
        prev_delta = 0;
266
0
      }
267
0
268
0
      delta = last_gid - start_cp;
269
0
      mode = FIRST_SUB_RANGE;
270
0
      it++;
271
0
272
0
      while (it) {
273
0
        // Process range
274
0
        const auto& pair = *it;
275
0
        hb_codepoint_t next_cp = pair.first;
276
0
        hb_codepoint_t next_gid = pair.second;
277
0
        if (next_cp != end_cp + 1) {
278
0
          // Current range is over, stop processing.
279
0
          break;
280
0
        }
281
0
282
0
        if (next_gid == last_gid + 1) {
283
0
          // The current run continues.
284
0
          end_cp = next_cp;
285
0
          run_length++;
286
0
          last_gid = next_gid;
287
0
          it++;
288
0
          continue;
289
0
        }
290
0
291
0
        // A new run is starting, decide if we want to commit the current run.
292
0
        int split_cost = (mode == FIRST_SUB_RANGE) ? 8 : 16;
293
0
        int run_cost = run_length * 2;
294
0
        if (run_cost >= split_cost) {
295
0
          commit_current_range(start_cp,
296
0
                               prev_run_start_cp,
297
0
                               run_start_cp,
298
0
                               end_cp,
299
0
                               delta,
300
0
                               prev_delta,
301
0
                               split_cost,
302
0
                               range_writer);
303
0
          start_cp = next_cp;
304
0
        }
305
0
306
0
        // Start the new run
307
0
        mode = FOLLOWING_SUB_RANGE;
308
0
        prev_run_start_cp = run_start_cp;
309
0
        run_start_cp = next_cp;
310
0
        end_cp = next_cp;
311
0
        prev_delta = delta;
312
0
        delta = next_gid - run_start_cp;
313
0
        run_length = 1;
314
0
        last_gid = next_gid;
315
0
        it++;
316
0
      }
317
0
318
0
      // Finalize range
319
0
      commit_current_range (start_cp,
320
0
                            prev_run_start_cp,
321
0
                            run_start_cp,
322
0
                            end_cp,
323
0
                            delta,
324
0
                            prev_delta,
325
0
                            8,
326
0
                            range_writer);
327
0
    }
328
0
329
0
    if (likely (end_cp != 0xFFFF)) {
330
0
      range_writer (0xFFFF, 0xFFFF, 1);
331
0
    }
332
0
  }
Unexecuted instantiation: _ZN2OT19CmapSubtableFormat49to_rangesI10hb_array_tIK9hb_pair_tIjjEEZNS0_23serialize_find_segcountIS6_TnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NS9_6item_tEEE5valueEvE4typeELPv0EEEjS9_E7CounterTnSD_LSE_0EEEvS9_RT0_
Unexecuted instantiation: _ZN2OT19CmapSubtableFormat49to_rangesI10hb_array_tIK9hb_pair_tIjjEEZNS0_32serialize_start_end_delta_arraysIS6_TnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NS9_6item_tEEE5valueEvE4typeELPv0EEEbP22hb_serialize_context_tS9_iE6WriterTnSD_LSE_0EEEvS9_RT0_
333
334
  /*
335
   * Writes the current range as either one or two ranges depending on what is most efficient.
336
   */
337
  template<typename Writer>
338
  void commit_current_range (hb_codepoint_t start,
339
                             hb_codepoint_t prev_run_start,
340
                             hb_codepoint_t run_start,
341
                             hb_codepoint_t end,
342
                             int run_delta,
343
                             int previous_run_delta,
344
                             int split_cost,
345
0
                             Writer& range_writer) {
346
0
    bool should_split = false;
347
0
    if (start < run_start && run_start < end) {
348
0
      int run_cost = (end - run_start + 1) * 2;
349
0
      if (run_cost >= split_cost) {
350
0
        should_split = true;
351
0
      }
352
0
    }
353
0
354
0
    // A zero delta is also the marker for ranges that need a
355
0
    // glyphIdArray; serialize_rangeoffset_glyid() tells the two cases
356
0
    // apart by re-checking the mapping.
357
0
    if (should_split) {
358
0
      if (start == prev_run_start)
359
0
        range_writer (start, run_start - 1, previous_run_delta);
360
0
      else
361
0
        range_writer (start, run_start - 1, 0);
362
0
      range_writer (run_start, end, run_delta);
363
0
      return;
364
0
    }
365
0
366
0
367
0
    if (start == run_start) {
368
0
      // Range is only a run
369
0
      range_writer (start, end, run_delta);
370
0
      return;
371
0
    }
372
0
373
0
    // Write only a single non-run range.
374
0
    range_writer (start, end, 0);
375
0
  }
Unexecuted instantiation: _ZN2OT19CmapSubtableFormat420commit_current_rangeIZNS0_23serialize_find_segcountI10hb_array_tIK9hb_pair_tIjjEETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NS9_6item_tEEE5valueEvE4typeELPv0EEEjS9_E7CounterEEvjjjjiiiRS9_
Unexecuted instantiation: _ZN2OT19CmapSubtableFormat420commit_current_rangeIZNS0_32serialize_start_end_delta_arraysI10hb_array_tIK9hb_pair_tIjjEETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NS9_6item_tEEE5valueEvE4typeELPv0EEEbP22hb_serialize_context_tS9_iE6WriterEEvjjjjiiiRS9_
376
377
  template<typename Iterator,
378
     hb_requires (hb_is_iterator (Iterator))>
379
0
  unsigned serialize_find_segcount (Iterator it) {
380
0
    struct Counter {
381
0
      unsigned segcount = 0;
382
0
383
0
      void operator() (hb_codepoint_t start,
384
0
                       hb_codepoint_t end,
385
0
                       int delta) {
386
0
        segcount++;
387
0
      }
388
0
    } counter;
389
0
390
0
    to_ranges (+it, counter);
391
0
    return counter.segcount;
392
0
  }
393
394
395
  template<typename Iterator,
396
     hb_requires (hb_is_iterator (Iterator))>
397
  bool serialize_start_end_delta_arrays (hb_serialize_context_t *c,
398
                                         Iterator it,
399
                                         int segcount)
400
0
  {
401
0
    struct Writer {
402
0
      hb_serialize_context_t *serializer_;
403
0
      HBUINT16* end_code_;
404
0
      HBUINT16* start_code_;
405
0
      HBINT16* id_delta_;
406
0
      int index_;
407
0
408
0
      Writer(hb_serialize_context_t *serializer)
409
0
          : serializer_(serializer),
410
0
            end_code_(nullptr),
411
0
            start_code_(nullptr),
412
0
            id_delta_(nullptr),
413
0
            index_ (0) {}
414
0
      void operator() (hb_codepoint_t start,
415
0
                       hb_codepoint_t end,
416
0
                       int delta) {
417
0
        start_code_[index_] = start;
418
0
        end_code_[index_] = end;
419
0
        id_delta_[index_] = delta;
420
0
        index_++;
421
0
      }
422
0
    } writer(c);
423
0
424
0
    writer.end_code_ = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount, false);
425
0
    (void) c->allocate_size<HBUINT16> (2); // padding
426
0
    writer.start_code_ = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount, false);
427
0
    writer.id_delta_ = c->allocate_size<HBINT16> (HBINT16::static_size * segcount, false);
428
0
429
0
    if (unlikely (!writer.end_code_ || !writer.start_code_ || !writer.id_delta_)) return false;
430
0
431
0
    to_ranges (+it, writer);
432
0
    return true;
433
0
  }
434
435
  template<typename Iterator,
436
          hb_requires (hb_is_iterator (Iterator))>
437
  HBUINT16* serialize_rangeoffset_glyid (hb_serialize_context_t *c,
438
                                         Iterator it,
439
           HBUINT16 *endCode,
440
           HBUINT16 *startCode,
441
           HBINT16 *idDelta,
442
           unsigned segcount)
443
0
  {
444
0
    hb_map_t cp_to_gid { it };
445
0
446
0
    HBUINT16 *idRangeOffset = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount);
447
0
    if (unlikely (!c->check_success (idRangeOffset))) return nullptr;
448
0
    if (unlikely ((char *)idRangeOffset - (char *)idDelta != (int) segcount * (int) HBINT16::static_size)) return nullptr;
449
0
450
0
    for (unsigned i : hb_range (segcount))
451
0
    {
452
0
      /* A non-zero delta is always a real run. A zero delta is
453
0
       * ambiguous: identity mapping, or the marker for a range that
454
0
       * needs a glyphIdArray. Only zero deltas need a check. */
455
0
      int delta = idDelta[i];
456
0
      if (delta)
457
0
  continue;
458
0
      bool use_delta = true;
459
0
      for (hb_codepoint_t cp = startCode[i]; cp <= endCode[i]; cp++)
460
0
      {
461
0
  hb_codepoint_t gid = cp_to_gid.get (cp);
462
0
  if (gid == HB_MAP_VALUE_INVALID)
463
0
    gid = 0;
464
0
  if (gid != cp)
465
0
  {
466
0
    use_delta = false;
467
0
    break;
468
0
  }
469
0
      }
470
0
      if (use_delta)
471
0
  continue;
472
0
473
0
      idRangeOffset[i] = 2 * (c->start_embed<HBUINT16> () - idRangeOffset - i);
474
0
      for (hb_codepoint_t cp = startCode[i]; cp <= endCode[i]; cp++)
475
0
      {
476
0
        HBUINT16 gid;
477
0
        gid = cp_to_gid[cp];
478
0
        c->copy<HBUINT16> (gid);
479
0
      }
480
0
    }
481
0
482
0
    return idRangeOffset;
483
0
  }
484
485
  template<typename Iterator,
486
     hb_requires (hb_is_iterator (Iterator))>
487
  void serialize (hb_serialize_context_t *c,
488
      Iterator it)
489
0
  {
490
0
    auto format4_iter =
491
0
    + it
492
0
    | hb_filter ([&] (const hb_codepoint_pair_t _)
493
0
     { return _.first <= 0xFFFF; })
494
0
    ;
495
0
496
0
    if (!format4_iter) return;
497
0
498
0
    unsigned table_initpos = c->length ();
499
0
    if (unlikely (!c->extend_min (this))) return;
500
0
    this->format = 4;
501
0
502
0
    hb_vector_t<hb_codepoint_pair_t> cp_to_gid {
503
0
      format4_iter
504
0
    };
505
0
506
0
    //serialize endCode[], startCode[], idDelta[]
507
0
    HBUINT16* endCode = c->start_embed<HBUINT16> ();
508
0
    unsigned segcount = serialize_find_segcount (cp_to_gid.iter());
509
0
    if (unlikely (!serialize_start_end_delta_arrays (c, cp_to_gid.iter(), segcount)))
510
0
      return;
511
0
512
0
    HBUINT16 *startCode = endCode + segcount + 1;
513
0
    HBINT16 *idDelta = ((HBINT16*)startCode) + segcount;
514
0
515
0
    HBUINT16 *idRangeOffset = serialize_rangeoffset_glyid (c,
516
0
                                                           cp_to_gid.iter (),
517
0
                                                           endCode,
518
0
                                                           startCode,
519
0
                                                           idDelta,
520
0
                                                           segcount);
521
0
    if (unlikely (!c->check_success (idRangeOffset))) return;
522
0
523
0
    this->length = c->length () - table_initpos;
524
0
    if ((long long) this->length != (long long) c->length () - table_initpos)
525
0
    {
526
0
      c->err (HB_SERIALIZE_ERROR_INT_OVERFLOW);
527
0
      return;
528
0
    }
529
0
530
0
    this->segCountX2 = segcount * 2;
531
0
    this->entrySelector = hb_max (1u, hb_bit_storage (segcount)) - 1;
532
0
    this->searchRange = 2 * (1u << this->entrySelector);
533
0
    this->rangeShift = segcount * 2 > this->searchRange
534
0
           ? 2 * segcount - this->searchRange
535
0
           : 0;
536
0
  }
Unexecuted instantiation: hb-face.cc:_ZN2OT19CmapSubtableFormat49serializeI16hb_filter_iter_tIS2_I17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS_4cmap6subsetEP19hb_subset_context_tbEUlS5_E_RK4$_17LPv0EERK8hb_set_tRK3$_7LSF_0EETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NSP_6item_tEEE5valueEvE4typeELSF_0EEEvP22hb_serialize_context_tSP_
Unexecuted instantiation: hb-face.cc:_ZN2OT19CmapSubtableFormat49serializeI16hb_filter_iter_tI17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS_4cmap6subsetEP19hb_subset_context_tbEUlS5_E_RK4$_17LPv0EETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NSI_6item_tEEE5valueEvE4typeELSF_0EEEvP22hb_serialize_context_tSI_
Unexecuted instantiation: hb-ot-face.cc:_ZN2OT19CmapSubtableFormat49serializeI16hb_filter_iter_tIS2_I17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS_4cmap6subsetEP19hb_subset_context_tbEUlS5_E_RK4$_17LPv0EERK8hb_set_tRK3$_7LSF_0EETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NSP_6item_tEEE5valueEvE4typeELSF_0EEEvP22hb_serialize_context_tSP_
Unexecuted instantiation: hb-ot-face.cc:_ZN2OT19CmapSubtableFormat49serializeI16hb_filter_iter_tI17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS_4cmap6subsetEP19hb_subset_context_tbEUlS5_E_RK4$_17LPv0EETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NSI_6item_tEEE5valueEvE4typeELSF_0EEEvP22hb_serialize_context_tSI_
Unexecuted instantiation: hb-ot-font.cc:_ZN2OT19CmapSubtableFormat49serializeI16hb_filter_iter_tIS2_I17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS_4cmap6subsetEP19hb_subset_context_tbEUlS5_E_RK4$_17LPv0EERK8hb_set_tRK3$_7LSF_0EETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NSP_6item_tEEE5valueEvE4typeELSF_0EEEvP22hb_serialize_context_tSP_
Unexecuted instantiation: hb-ot-font.cc:_ZN2OT19CmapSubtableFormat49serializeI16hb_filter_iter_tI17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS_4cmap6subsetEP19hb_subset_context_tbEUlS5_E_RK4$_17LPv0EETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NSI_6item_tEEE5valueEvE4typeELSF_0EEEvP22hb_serialize_context_tSI_
Unexecuted instantiation: hb-static.cc:_ZN2OT19CmapSubtableFormat49serializeI16hb_filter_iter_tIS2_I17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS_4cmap6subsetEP19hb_subset_context_tbEUlS5_E_RK4$_17LPv0EERK8hb_set_tRK3$_7LSF_0EETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NSP_6item_tEEE5valueEvE4typeELSF_0EEEvP22hb_serialize_context_tSP_
Unexecuted instantiation: hb-static.cc:_ZN2OT19CmapSubtableFormat49serializeI16hb_filter_iter_tI17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS_4cmap6subsetEP19hb_subset_context_tbEUlS5_E_RK4$_17LPv0EETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NSI_6item_tEEE5valueEvE4typeELSF_0EEEvP22hb_serialize_context_tSI_
537
538
  unsigned get_language () const
539
0
  {
540
0
    return language;
541
0
  }
542
543
  struct accelerator_t
544
  {
545
0
    accelerator_t () {}
546
    accelerator_t (const CmapSubtableFormat4 *subtable) = delete;
547
548
    void init (const CmapSubtableFormat4 *subtable,
549
         unsigned int              subtable_data_size)
550
0
    {
551
0
      segCount = subtable->segCountX2 / 2;
552
0
      endCount = subtable->values.arrayZ;
553
0
      startCount = endCount + segCount + 1;
554
0
      idDelta = startCount + segCount;
555
0
      idRangeOffset = idDelta + segCount;
556
0
      glyphIdArray = idRangeOffset + segCount;
557
558
0
      unsigned int values_offset = 16 + 8 * segCount;
559
0
      glyphIdArrayLength = subtable_data_size > values_offset
560
0
         ? (subtable_data_size - values_offset) / 2
561
0
         : 0;
562
0
    }
563
564
    bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
565
0
    {
566
0
      struct CustomRange
567
0
      {
568
0
  int cmp (hb_codepoint_t k,
569
0
     unsigned distance) const
570
0
  {
571
0
    if (k > last) return +1;
572
0
    if (k < (&last)[distance]/*first*/) return -1;
573
0
    return 0;
574
0
  }
575
0
  HBUINT16 last;
576
0
      };
577
578
0
      const HBUINT16 *found = hb_bsearch (codepoint,
579
0
            this->endCount,
580
0
            this->segCount,
581
0
            sizeof (CustomRange),
582
0
            _hb_cmp_method<hb_codepoint_t, CustomRange, unsigned>,
583
0
            this->segCount + 1);
584
0
      if (unlikely (!found))
585
0
  return false;
586
0
      unsigned int i = found - endCount;
587
588
0
      hb_codepoint_t gid;
589
0
      unsigned int rangeOffset = this->idRangeOffset[i];
590
0
      if (rangeOffset == 0)
591
0
  gid = codepoint + this->idDelta[i];
592
0
      else
593
0
      {
594
  /* Somebody has been smoking... */
595
0
  unsigned int index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount;
596
0
  if (unlikely (index >= this->glyphIdArrayLength))
597
0
    return false;
598
0
  gid = this->glyphIdArray[index];
599
0
  if (unlikely (!gid))
600
0
    return false;
601
0
  gid += this->idDelta[i];
602
0
      }
603
0
      gid &= 0xFFFFu;
604
0
      if (unlikely (!gid))
605
0
  return false;
606
0
      *glyph = gid;
607
0
      return true;
608
0
    }
609
610
    HB_INTERNAL static bool get_glyph_func (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph)
611
0
    { return ((const accelerator_t *) obj)->get_glyph (codepoint, glyph); }
612
613
    void collect_unicodes (hb_set_t *out) const
614
0
    {
615
0
      unsigned int count = this->segCount;
616
0
      if (count && this->startCount[count - 1] == 0xFFFFu)
617
0
  count--; /* Skip sentinel segment. */
618
0
      for (unsigned int i = 0; i < count; i++)
619
0
      {
620
0
  hb_codepoint_t start = this->startCount[i];
621
0
  hb_codepoint_t end = this->endCount[i];
622
0
  unsigned int rangeOffset = this->idRangeOffset[i];
623
0
        out->add_range(start, end);
624
0
  if (rangeOffset == 0)
625
0
  {
626
0
    for (hb_codepoint_t codepoint = start; codepoint <= end; codepoint++)
627
0
    {
628
0
      hb_codepoint_t gid = (codepoint + this->idDelta[i]) & 0xFFFFu;
629
0
      if (unlikely (!gid))
630
0
              out->del(codepoint);
631
0
    }
632
0
  }
633
0
  else
634
0
  {
635
0
    for (hb_codepoint_t codepoint = start; codepoint <= end; codepoint++)
636
0
    {
637
0
      unsigned int index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount;
638
0
      if (unlikely (index >= this->glyphIdArrayLength))
639
0
            {
640
0
              out->del_range (codepoint, end);
641
0
        break;
642
0
            }
643
0
      hb_codepoint_t gid = this->glyphIdArray[index];
644
0
      if (unlikely (!gid))
645
0
              out->del(codepoint);
646
0
    }
647
0
  }
648
0
      }
649
0
    }
650
651
    void collect_mapping (hb_set_t *unicodes, /* OUT */
652
        hb_map_t *mapping /* OUT */) const
653
0
    {
654
      // TODO(grieger): optimize similar to collect_unicodes
655
      // (ie. use add_range())
656
0
      unsigned count = this->segCount;
657
0
      if (count && this->startCount[count - 1] == 0xFFFFu)
658
0
  count--; /* Skip sentinel segment. */
659
0
      for (unsigned i = 0; i < count; i++)
660
0
      {
661
0
  hb_codepoint_t start = this->startCount[i];
662
0
  hb_codepoint_t end = this->endCount[i];
663
0
  unsigned rangeOffset = this->idRangeOffset[i];
664
0
  if (rangeOffset == 0)
665
0
  {
666
0
    for (hb_codepoint_t codepoint = start; codepoint <= end; codepoint++)
667
0
    {
668
0
      hb_codepoint_t gid = (codepoint + this->idDelta[i]) & 0xFFFFu;
669
0
      if (unlikely (!gid))
670
0
        continue;
671
0
      unicodes->add (codepoint);
672
0
      mapping->set (codepoint, gid);
673
0
    }
674
0
  }
675
0
  else
676
0
  {
677
0
    for (hb_codepoint_t codepoint = start; codepoint <= end; codepoint++)
678
0
    {
679
0
      unsigned index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount;
680
0
      if (unlikely (index >= this->glyphIdArrayLength))
681
0
        break;
682
0
      hb_codepoint_t gid = this->glyphIdArray[index];
683
0
      if (unlikely (!gid))
684
0
        continue;
685
0
            gid = (gid + this->idDelta[i]) & 0xFFFFu;
686
0
      unicodes->add (codepoint);
687
0
      mapping->set (codepoint, gid);
688
0
    }
689
0
  }
690
0
      }
691
0
    }
692
693
    const HBUINT16 *endCount;
694
    const HBUINT16 *startCount;
695
    const HBUINT16 *idDelta;
696
    const HBUINT16 *idRangeOffset;
697
    const HBUINT16 *glyphIdArray;
698
    unsigned int segCount;
699
    unsigned int glyphIdArrayLength;
700
  };
701
702
  bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph,
703
      unsigned int subtable_data_size) const
704
0
  {
705
0
    accelerator_t accel;
706
0
    accel.init (this, subtable_data_size);
707
0
    return accel.get_glyph_func (&accel, codepoint, glyph);
708
0
  }
709
  bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
710
0
  { return false; }
711
712
  void collect_unicodes (hb_set_t *out, unsigned int subtable_data_size) const
713
0
  {
714
0
    accelerator_t accel;
715
0
    accel.init (this, subtable_data_size);
716
0
    accel.collect_unicodes (out);
717
0
  }
718
  void collect_unicodes (hb_set_t *out) const
719
0
  { collect_unicodes (out, length); }
720
721
  void collect_mapping (hb_set_t *unicodes, /* OUT */
722
      hb_map_t *mapping, /* OUT */
723
      unsigned int subtable_data_size) const
724
0
  {
725
0
    accelerator_t accel;
726
0
    accel.init (this, subtable_data_size);
727
0
    accel.collect_mapping (unicodes, mapping);
728
0
  }
729
  void collect_mapping (hb_set_t *unicodes, /* OUT */
730
      hb_map_t *mapping /* OUT */) const
731
0
  { collect_mapping (unicodes, mapping, length); }
732
733
  bool sanitize (hb_sanitize_context_t *c) const
734
0
  {
735
0
    TRACE_SANITIZE (this);
736
0
    if (unlikely (!c->check_struct (this)))
737
0
      return_trace (false);
738
0
    hb_barrier ();
739
740
0
    return_trace (c->check_range (values, 2 + 4 * segCountX2));
741
0
  }
742
743
  protected:
744
  HBUINT16  format;   /* Format number is set to 4. */
745
  HBUINT16  length;   /* This is the length in bytes of the
746
         * subtable. */
747
  HBUINT16  language; /* Ignore. */
748
  HBUINT16  segCountX2; /* 2 x segCount. */
749
  HBUINT16  searchRange;  /* 2 * (2**floor(log2(segCount))) */
750
  HBUINT16  entrySelector;  /* log2(searchRange/2) */
751
  HBUINT16  rangeShift; /* 2 x segCount - searchRange */
752
753
  UnsizedArrayOf<HBUINT16>
754
    values;
755
#if 0
756
  HBUINT16  endCount[segCount]; /* End characterCode for each segment,
757
           * last=0xFFFFu. */
758
  HBUINT16  reservedPad;    /* Set to 0. */
759
  HBUINT16  startCount[segCount]; /* Start character code for each segment. */
760
  HBINT16   idDelta[segCount];  /* Delta for all character codes in segment. */
761
  HBUINT16  idRangeOffset[segCount];/* Offsets into glyphIdArray or 0 */
762
  UnsizedArrayOf<HBUINT16>
763
    glyphIdArray; /* Glyph index array (arbitrary length) */
764
#endif
765
766
  public:
767
  DEFINE_SIZE_ARRAY (14, values);
768
};
769
770
struct CmapSubtableLongGroup
771
{
772
  friend struct CmapSubtableFormat12;
773
  friend struct CmapSubtableFormat13;
774
  template<typename U>
775
  friend struct CmapSubtableLongSegmented;
776
  friend struct cmap;
777
778
  int cmp (hb_codepoint_t codepoint) const
779
0
  {
780
0
    if (codepoint < startCharCode) return -1;
781
0
    if (codepoint > endCharCode)   return +1;
782
0
    return 0;
783
0
  }
784
785
  bool sanitize (hb_sanitize_context_t *c) const
786
0
  {
787
0
    TRACE_SANITIZE (this);
788
0
    return_trace (c->check_struct (this));
789
0
  }
790
791
  private:
792
  HBUINT32    startCharCode;  /* First character code in this group. */
793
  HBUINT32    endCharCode;  /* Last character code in this group. */
794
  HBUINT32    glyphID;  /* Glyph index; interpretation depends on
795
           * subtable format. */
796
  public:
797
  DEFINE_SIZE_STATIC (12);
798
};
799
DECLARE_NULL_NAMESPACE_BYTES (OT, CmapSubtableLongGroup);
800
801
template <typename UINT>
802
struct CmapSubtableTrimmed
803
{
804
  bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
805
0
  {
806
    /* Rely on our implicit array bound-checking. */
807
0
    hb_codepoint_t gid = glyphIdArray[codepoint - startCharCode];
808
0
    if (unlikely (!gid))
809
0
      return false;
810
0
    *glyph = gid;
811
0
    return true;
812
0
  }
Unexecuted instantiation: OT::CmapSubtableTrimmed<OT::NumType<true, unsigned short, 2u> >::get_glyph(unsigned int, unsigned int*) const
Unexecuted instantiation: OT::CmapSubtableTrimmed<OT::NumType<true, unsigned int, 4u> >::get_glyph(unsigned int, unsigned int*) const
813
814
  unsigned get_language () const
815
0
  {
816
0
    return language;
817
0
  }
Unexecuted instantiation: OT::CmapSubtableTrimmed<OT::NumType<true, unsigned short, 2u> >::get_language() const
Unexecuted instantiation: OT::CmapSubtableTrimmed<OT::NumType<true, unsigned int, 4u> >::get_language() const
818
819
  void collect_unicodes (hb_set_t *out) const
820
0
  {
821
0
    hb_codepoint_t start = startCharCode;
822
0
    unsigned int count = glyphIdArray.len;
823
0
    for (unsigned int i = 0; i < count; i++)
824
0
      if (glyphIdArray[i])
825
0
  out->add (start + i);
826
0
  }
Unexecuted instantiation: OT::CmapSubtableTrimmed<OT::NumType<true, unsigned short, 2u> >::collect_unicodes(hb_set_t*) const
Unexecuted instantiation: OT::CmapSubtableTrimmed<OT::NumType<true, unsigned int, 4u> >::collect_unicodes(hb_set_t*) const
827
828
  void collect_mapping (hb_set_t *unicodes, /* OUT */
829
      hb_map_t *mapping /* OUT */) const
830
0
  {
831
0
    hb_codepoint_t start_cp = startCharCode;
832
0
    unsigned count = glyphIdArray.len;
833
0
    for (unsigned i = 0; i < count; i++)
834
0
      if (glyphIdArray[i])
835
0
      {
836
0
  hb_codepoint_t unicode = start_cp + i;
837
0
  hb_codepoint_t glyphid = glyphIdArray[i];
838
0
  unicodes->add (unicode);
839
0
  mapping->set (unicode, glyphid);
840
0
      }
841
0
  }
Unexecuted instantiation: OT::CmapSubtableTrimmed<OT::NumType<true, unsigned short, 2u> >::collect_mapping(hb_set_t*, hb_map_t*) const
Unexecuted instantiation: OT::CmapSubtableTrimmed<OT::NumType<true, unsigned int, 4u> >::collect_mapping(hb_set_t*, hb_map_t*) const
842
843
  bool sanitize (hb_sanitize_context_t *c) const
844
0
  {
845
0
    TRACE_SANITIZE (this);
846
0
    return_trace (c->check_struct (this) && glyphIdArray.sanitize (c));
847
0
  }
Unexecuted instantiation: OT::CmapSubtableTrimmed<OT::NumType<true, unsigned short, 2u> >::sanitize(hb_sanitize_context_t*) const
Unexecuted instantiation: OT::CmapSubtableTrimmed<OT::NumType<true, unsigned int, 4u> >::sanitize(hb_sanitize_context_t*) const
848
849
  protected:
850
  UINT    formatReserved; /* Subtable format and (maybe) padding. */
851
  UINT    length;   /* Byte length of this subtable. */
852
  UINT    language; /* Ignore. */
853
  UINT    startCharCode;  /* First character code covered. */
854
  ArrayOf<HBGlyphID16, UINT>
855
    glyphIdArray; /* Array of glyph index values for character
856
         * codes in the range. */
857
  public:
858
  DEFINE_SIZE_ARRAY (5 * sizeof (UINT), glyphIdArray);
859
};
860
861
struct CmapSubtableFormat6  : CmapSubtableTrimmed<HBUINT16> {};
862
struct CmapSubtableFormat10 : CmapSubtableTrimmed<HBUINT32> {};
863
864
template <typename T>
865
struct CmapSubtableLongSegmented
866
{
867
  friend struct cmap;
868
869
  bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
870
0
  {
871
0
    hb_codepoint_t gid = T::group_get_glyph (groups.bsearch (codepoint), codepoint);
872
0
    if (unlikely (!gid))
873
0
      return false;
874
0
    *glyph = gid;
875
0
    return true;
876
0
  }
Unexecuted instantiation: OT::CmapSubtableLongSegmented<OT::CmapSubtableFormat12>::get_glyph(unsigned int, unsigned int*) const
Unexecuted instantiation: OT::CmapSubtableLongSegmented<OT::CmapSubtableFormat13>::get_glyph(unsigned int, unsigned int*) const
877
878
  unsigned get_language () const
879
0
  {
880
0
    return language;
881
0
  }
Unexecuted instantiation: OT::CmapSubtableLongSegmented<OT::CmapSubtableFormat12>::get_language() const
Unexecuted instantiation: OT::CmapSubtableLongSegmented<OT::CmapSubtableFormat13>::get_language() const
882
883
  void collect_unicodes (hb_set_t *out, unsigned int num_glyphs) const
884
0
  {
885
0
    for (unsigned int i = 0; i < this->groups.len; i++)
886
0
    {
887
0
      hb_codepoint_t start = this->groups[i].startCharCode;
888
0
      hb_codepoint_t end = hb_min ((hb_codepoint_t) this->groups[i].endCharCode,
889
0
           (hb_codepoint_t) HB_UNICODE_MAX);
890
0
      hb_codepoint_t gid = this->groups[i].glyphID;
891
0
      if (!gid)
892
0
      {
893
  /* Intention is: if (hb_is_same (T, CmapSubtableFormat13)) continue; */
894
0
  if (! T::group_get_glyph (this->groups[i], end)) continue;
895
0
  start++;
896
0
  gid++;
897
0
      }
898
0
      if (unlikely ((unsigned int) gid >= num_glyphs)) continue;
899
0
      if (unlikely ((unsigned int) (gid + end - start) >= num_glyphs))
900
0
  end = start + (hb_codepoint_t) num_glyphs - gid;
901
902
0
      out->add_range (start, hb_min (end, 0x10FFFFu));
903
0
    }
904
0
  }
Unexecuted instantiation: OT::CmapSubtableLongSegmented<OT::CmapSubtableFormat12>::collect_unicodes(hb_set_t*, unsigned int) const
Unexecuted instantiation: OT::CmapSubtableLongSegmented<OT::CmapSubtableFormat13>::collect_unicodes(hb_set_t*, unsigned int) const
905
906
  void collect_mapping (hb_set_t *unicodes, /* OUT */
907
      hb_map_t *mapping, /* OUT */
908
      unsigned num_glyphs) const
909
0
  {
910
0
    hb_codepoint_t last_end = 0;
911
0
    unsigned count = this->groups.len;
912
0
    for (unsigned i = 0; i < count; i++)
913
0
    {
914
0
      hb_codepoint_t start = this->groups.arrayZ[i].startCharCode;
915
0
      hb_codepoint_t end = hb_min ((hb_codepoint_t) this->groups.arrayZ[i].endCharCode,
916
0
           (hb_codepoint_t) HB_UNICODE_MAX);
917
0
      if (unlikely (start > end || start < last_end)) {
918
        // Range is not in order and is invalid, skip it.
919
0
        continue;
920
0
      }
921
0
      last_end = end;
922
923
924
0
      hb_codepoint_t gid = this->groups.arrayZ[i].glyphID;
925
0
      if (!gid)
926
0
      {
927
0
        if (T::formatNumber == 13) continue;
928
0
  start++;
929
0
  gid++;
930
0
      }
931
0
      if (unlikely ((unsigned int) gid >= num_glyphs)) continue;
932
0
      if (unlikely ((unsigned int) (gid + end - start) >= num_glyphs))
933
0
  end = start + (hb_codepoint_t) num_glyphs - gid;
934
935
0
      mapping->alloc (mapping->get_population () + end - start + 1);
936
937
0
      unicodes->add_range (start, end);
938
0
      for (unsigned cp = start; cp <= end; cp++)
939
0
      {
940
0
  mapping->set (cp, gid);
941
0
        gid += T::increment;
942
0
      }
943
0
    }
944
0
  }
Unexecuted instantiation: OT::CmapSubtableLongSegmented<OT::CmapSubtableFormat12>::collect_mapping(hb_set_t*, hb_map_t*, unsigned int) const
Unexecuted instantiation: OT::CmapSubtableLongSegmented<OT::CmapSubtableFormat13>::collect_mapping(hb_set_t*, hb_map_t*, unsigned int) const
945
946
  bool sanitize (hb_sanitize_context_t *c) const
947
0
  {
948
0
    TRACE_SANITIZE (this);
949
0
    return_trace (c->check_struct (this) && groups.sanitize (c));
950
0
  }
Unexecuted instantiation: OT::CmapSubtableLongSegmented<OT::CmapSubtableFormat12>::sanitize(hb_sanitize_context_t*) const
Unexecuted instantiation: OT::CmapSubtableLongSegmented<OT::CmapSubtableFormat13>::sanitize(hb_sanitize_context_t*) const
951
952
  protected:
953
  HBUINT16  format;   /* Subtable format; set to 12. */
954
  HBUINT16  reserved; /* Reserved; set to 0. */
955
  HBUINT32  length;   /* Byte length of this subtable. */
956
  HBUINT32  language; /* Ignore. */
957
  SortedArray32Of<CmapSubtableLongGroup>
958
    groups;   /* Groupings. */
959
  public:
960
  DEFINE_SIZE_ARRAY (16, groups);
961
};
962
963
struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
964
{
965
  static constexpr int increment = 1;
966
  static constexpr int formatNumber = 12;
967
968
  static hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
969
           hb_codepoint_t u)
970
0
  { return likely (group.startCharCode <= group.endCharCode) ?
971
0
     group.glyphID + (u - group.startCharCode) : 0; }
972
973
974
  template<typename Iterator,
975
     hb_requires (hb_is_iterator (Iterator))>
976
  void serialize (hb_serialize_context_t *c,
977
      Iterator it)
978
0
  {
979
0
    if (!it) return;
980
0
    unsigned table_initpos = c->length ();
981
0
    if (unlikely (!c->extend_min (this))) return;
982
0
983
0
    hb_codepoint_t startCharCode = (hb_codepoint_t) -1, endCharCode = (hb_codepoint_t) -1;
984
0
    hb_codepoint_t glyphID = 0;
985
0
986
0
    for (const auto& _ : +it)
987
0
    {
988
0
      if (startCharCode == (hb_codepoint_t) -1)
989
0
      {
990
0
  startCharCode = _.first;
991
0
  endCharCode = _.first;
992
0
  glyphID = _.second;
993
0
      }
994
0
      else if (!_is_gid_consecutive (endCharCode, startCharCode, glyphID, _.first, _.second))
995
0
      {
996
0
  CmapSubtableLongGroup  grouprecord;
997
0
  grouprecord.startCharCode = startCharCode;
998
0
  grouprecord.endCharCode = endCharCode;
999
0
  grouprecord.glyphID = glyphID;
1000
0
  c->copy<CmapSubtableLongGroup> (grouprecord);
1001
0
1002
0
  startCharCode = _.first;
1003
0
  endCharCode = _.first;
1004
0
  glyphID = _.second;
1005
0
      }
1006
0
      else
1007
0
  endCharCode = _.first;
1008
0
    }
1009
0
1010
0
    CmapSubtableLongGroup record;
1011
0
    record.startCharCode = startCharCode;
1012
0
    record.endCharCode = endCharCode;
1013
0
    record.glyphID = glyphID;
1014
0
    c->copy<CmapSubtableLongGroup> (record);
1015
0
1016
0
    this->format = 12;
1017
0
    this->reserved = 0;
1018
0
    this->length = c->length () - table_initpos;
1019
0
    this->groups.len = (this->length - min_size) / CmapSubtableLongGroup::static_size;
1020
0
  }
Unexecuted instantiation: hb-face.cc:_ZN2OT20CmapSubtableFormat129serializeI16hb_filter_iter_tIS2_I17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS_4cmap6subsetEP19hb_subset_context_tbEUlS5_E_RK4$_17LPv0EERK8hb_set_tRK3$_7LSF_0EETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NSP_6item_tEEE5valueEvE4typeELSF_0EEEvP22hb_serialize_context_tSP_
Unexecuted instantiation: hb-face.cc:_ZN2OT20CmapSubtableFormat129serializeI16hb_filter_iter_tI17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS_4cmap6subsetEP19hb_subset_context_tbEUlS5_E_RK4$_17LPv0EETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NSI_6item_tEEE5valueEvE4typeELSF_0EEEvP22hb_serialize_context_tSI_
Unexecuted instantiation: hb-ot-face.cc:_ZN2OT20CmapSubtableFormat129serializeI16hb_filter_iter_tIS2_I17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS_4cmap6subsetEP19hb_subset_context_tbEUlS5_E_RK4$_17LPv0EERK8hb_set_tRK3$_7LSF_0EETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NSP_6item_tEEE5valueEvE4typeELSF_0EEEvP22hb_serialize_context_tSP_
Unexecuted instantiation: hb-ot-face.cc:_ZN2OT20CmapSubtableFormat129serializeI16hb_filter_iter_tI17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS_4cmap6subsetEP19hb_subset_context_tbEUlS5_E_RK4$_17LPv0EETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NSI_6item_tEEE5valueEvE4typeELSF_0EEEvP22hb_serialize_context_tSI_
Unexecuted instantiation: hb-ot-font.cc:_ZN2OT20CmapSubtableFormat129serializeI16hb_filter_iter_tIS2_I17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS_4cmap6subsetEP19hb_subset_context_tbEUlS5_E_RK4$_17LPv0EERK8hb_set_tRK3$_7LSF_0EETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NSP_6item_tEEE5valueEvE4typeELSF_0EEEvP22hb_serialize_context_tSP_
Unexecuted instantiation: hb-ot-font.cc:_ZN2OT20CmapSubtableFormat129serializeI16hb_filter_iter_tI17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS_4cmap6subsetEP19hb_subset_context_tbEUlS5_E_RK4$_17LPv0EETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NSI_6item_tEEE5valueEvE4typeELSF_0EEEvP22hb_serialize_context_tSI_
Unexecuted instantiation: hb-static.cc:_ZN2OT20CmapSubtableFormat129serializeI16hb_filter_iter_tIS2_I17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS_4cmap6subsetEP19hb_subset_context_tbEUlS5_E_RK4$_17LPv0EERK8hb_set_tRK3$_7LSF_0EETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NSP_6item_tEEE5valueEvE4typeELSF_0EEEvP22hb_serialize_context_tSP_
Unexecuted instantiation: hb-static.cc:_ZN2OT20CmapSubtableFormat129serializeI16hb_filter_iter_tI17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS_4cmap6subsetEP19hb_subset_context_tbEUlS5_E_RK4$_17LPv0EETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NSI_6item_tEEE5valueEvE4typeELSF_0EEEvP22hb_serialize_context_tSI_
1021
1022
  static size_t get_sub_table_size (const hb_sorted_vector_t<CmapSubtableLongGroup> &groups_data)
1023
0
  { return 16 + 12 * groups_data.length; }
1024
1025
  private:
1026
  static bool _is_gid_consecutive (hb_codepoint_t endCharCode,
1027
           hb_codepoint_t startCharCode,
1028
           hb_codepoint_t glyphID,
1029
           hb_codepoint_t cp,
1030
           hb_codepoint_t new_gid)
1031
0
  {
1032
0
    return (cp - 1 == endCharCode) &&
1033
0
  new_gid == glyphID + (cp - startCharCode);
1034
0
  }
1035
1036
};
1037
1038
struct CmapSubtableFormat13 : CmapSubtableLongSegmented<CmapSubtableFormat13>
1039
{
1040
  static constexpr int increment = 0;
1041
  static constexpr int formatNumber = 13;
1042
1043
  static hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
1044
           hb_codepoint_t u HB_UNUSED)
1045
0
  { return group.glyphID; }
1046
};
1047
1048
typedef enum
1049
{
1050
  GLYPH_VARIANT_NOT_FOUND = 0,
1051
  GLYPH_VARIANT_FOUND = 1,
1052
  GLYPH_VARIANT_USE_DEFAULT = 2
1053
} glyph_variant_t;
1054
1055
struct UnicodeValueRange
1056
{
1057
  int cmp (const hb_codepoint_t &codepoint) const
1058
0
  {
1059
0
    if (codepoint < startUnicodeValue) return -1;
1060
0
    if (codepoint > startUnicodeValue + additionalCount) return +1;
1061
0
    return 0;
1062
0
  }
1063
1064
  bool sanitize (hb_sanitize_context_t *c) const
1065
0
  {
1066
0
    TRACE_SANITIZE (this);
1067
0
    return_trace (c->check_struct (this));
1068
0
  }
1069
1070
  HBUINT24  startUnicodeValue;  /* First value in this range. */
1071
  HBUINT8 additionalCount;  /* Number of additional values in this
1072
           * range. */
1073
  public:
1074
  DEFINE_SIZE_STATIC (4);
1075
};
1076
1077
struct DefaultUVS : SortedArray32Of<UnicodeValueRange>
1078
{
1079
  void collect_unicodes (hb_set_t *out) const
1080
0
  {
1081
0
    unsigned int count = len;
1082
0
    for (unsigned int i = 0; i < count; i++)
1083
0
    {
1084
0
      hb_codepoint_t first = arrayZ[i].startUnicodeValue;
1085
0
      hb_codepoint_t last = hb_min ((hb_codepoint_t) (first + arrayZ[i].additionalCount),
1086
0
            (hb_codepoint_t) HB_UNICODE_MAX);
1087
0
      out->add_range (first, last);
1088
0
    }
1089
0
  }
1090
1091
  DefaultUVS* copy (hb_serialize_context_t *c,
1092
        const hb_set_t *unicodes) const
1093
0
  {
1094
0
    auto *out = c->start_embed<DefaultUVS> ();
1095
0
    auto snap = c->snapshot ();
1096
0
1097
0
    HBUINT32 len;
1098
0
    len = 0;
1099
0
    if (unlikely (!c->copy<HBUINT32> (len))) return nullptr;
1100
0
    unsigned init_len = c->length ();
1101
0
1102
0
    if (this->len > unicodes->get_population () * hb_bit_storage ((unsigned) this->len))
1103
0
    {
1104
0
      hb_codepoint_t start = HB_SET_VALUE_INVALID;
1105
0
      hb_codepoint_t end = HB_SET_VALUE_INVALID;
1106
0
1107
0
      for (auto u : *unicodes)
1108
0
      {
1109
0
        if (!as_array ().bsearch (u))
1110
0
    continue;
1111
0
  if (start == HB_SET_VALUE_INVALID)
1112
0
  {
1113
0
    start = u;
1114
0
    end = start - 1;
1115
0
  }
1116
0
  if (end + 1 != u || end - start == 255)
1117
0
        {
1118
0
    UnicodeValueRange rec;
1119
0
    rec.startUnicodeValue = start;
1120
0
    rec.additionalCount = end - start;
1121
0
    c->copy<UnicodeValueRange> (rec);
1122
0
    start = u;
1123
0
  }
1124
0
  end = u;
1125
0
      }
1126
0
      if (start != HB_SET_VALUE_INVALID)
1127
0
      {
1128
0
  UnicodeValueRange rec;
1129
0
  rec.startUnicodeValue = start;
1130
0
  rec.additionalCount = end - start;
1131
0
  c->copy<UnicodeValueRange> (rec);
1132
0
      }
1133
0
1134
0
    }
1135
0
    else
1136
0
    {
1137
0
      hb_codepoint_t lastCode = HB_SET_VALUE_INVALID;
1138
0
      int count = -1;
1139
0
1140
0
      for (const UnicodeValueRange& _ : *this)
1141
0
      {
1142
0
  hb_codepoint_t curEntry = (hb_codepoint_t) (_.startUnicodeValue - 1);
1143
0
  hb_codepoint_t end = curEntry + _.additionalCount + 2;
1144
0
1145
0
  for (; unicodes->next (&curEntry) && curEntry < end;)
1146
0
  {
1147
0
    count += 1;
1148
0
    if (lastCode == HB_SET_VALUE_INVALID)
1149
0
      lastCode = curEntry;
1150
0
    else if (lastCode + count != curEntry || count > 255)
1151
0
    {
1152
0
      UnicodeValueRange rec;
1153
0
      rec.startUnicodeValue = lastCode;
1154
0
      rec.additionalCount = count - 1;
1155
0
      c->copy<UnicodeValueRange> (rec);
1156
0
1157
0
      lastCode = curEntry;
1158
0
      count = 0;
1159
0
    }
1160
0
  }
1161
0
      }
1162
0
1163
0
      if (lastCode != HB_MAP_VALUE_INVALID)
1164
0
      {
1165
0
  UnicodeValueRange rec;
1166
0
  rec.startUnicodeValue = lastCode;
1167
0
  rec.additionalCount = count;
1168
0
  c->copy<UnicodeValueRange> (rec);
1169
0
      }
1170
0
    }
1171
0
1172
0
    if (c->length () - init_len == 0)
1173
0
    {
1174
0
      c->revert (snap);
1175
0
      return nullptr;
1176
0
    }
1177
0
    else
1178
0
    {
1179
0
      if (unlikely (!c->check_assign (out->len,
1180
0
                                      (c->length () - init_len) / UnicodeValueRange::static_size,
1181
0
                                      HB_SERIALIZE_ERROR_INT_OVERFLOW))) return nullptr;
1182
0
      return out;
1183
0
    }
1184
0
  }
1185
1186
  public:
1187
  DEFINE_SIZE_ARRAY (4, *this);
1188
};
1189
1190
template <typename Types>
1191
struct UVSMapping
1192
{
1193
  using GlyphID = typename Types::HBGlyphID;
1194
1195
  int cmp (const hb_codepoint_t &codepoint) const
1196
0
  { return unicodeValue.cmp (codepoint); }
1197
1198
  bool sanitize (hb_sanitize_context_t *c) const
1199
0
  {
1200
0
    TRACE_SANITIZE (this);
1201
0
    return_trace (c->check_struct (this));
1202
0
  }
1203
1204
  HBUINT24  unicodeValue; /* Base Unicode value of the UVS */
1205
  GlyphID
1206
    glyphID;  /* Glyph ID of the UVS. */
1207
  public:
1208
  DEFINE_SIZE_STATIC (3 + GlyphID::static_size);
1209
};
1210
1211
template <typename Types>
1212
struct NonDefaultUVS : SortedArray32Of<UVSMapping<Types>>
1213
{
1214
  using Mapping = UVSMapping<Types>;
1215
1216
  void collect_unicodes (hb_set_t *out) const
1217
0
  {
1218
0
    for (const auto& a : this->as_array ())
1219
0
      out->add (a.unicodeValue);
1220
0
  }
1221
1222
  void collect_mapping (hb_set_t *unicodes, /* OUT */
1223
      hb_map_t *mapping /* OUT */) const
1224
  {
1225
    for (const auto& a : this->as_array ())
1226
    {
1227
      hb_codepoint_t unicode = a.unicodeValue;
1228
      hb_codepoint_t glyphid = a.glyphID;
1229
      unicodes->add (unicode);
1230
      mapping->set (unicode, glyphid);
1231
    }
1232
  }
1233
1234
  void closure_glyphs (const hb_set_t      *unicodes,
1235
           hb_set_t            *glyphset) const
1236
0
  {
1237
0
    + this->as_array ()
1238
0
    | hb_filter (unicodes, &Mapping::unicodeValue)
1239
0
    | hb_map (&Mapping::glyphID)
1240
0
    | hb_sink (glyphset)
1241
0
    ;
1242
0
  }
1243
1244
  NonDefaultUVS* copy (hb_serialize_context_t *c,
1245
           const hb_set_t *unicodes,
1246
           const hb_set_t *glyphs_requested,
1247
           const hb_map_t *glyph_map) const
1248
0
  {
1249
0
    auto *out = c->start_embed<NonDefaultUVS> ();
1250
0
    auto it =
1251
0
    + this->as_array ()
1252
0
    | hb_filter ([&] (const Mapping& _)
1253
0
     {
1254
0
       return unicodes->has (_.unicodeValue) || glyphs_requested->has (_.glyphID);
1255
0
     })
1256
0
    ;
1257
0
1258
0
    if (!it) return nullptr;
1259
0
1260
0
    HBUINT32 len;
1261
0
    len = it.len ();
1262
0
    if (unlikely (!c->copy<HBUINT32> (len))) return nullptr;
1263
0
1264
0
    for (const Mapping& _ : it)
1265
0
    {
1266
0
      Mapping mapping;
1267
0
      mapping.unicodeValue = _.unicodeValue;
1268
0
      mapping.glyphID = glyph_map->get (_.glyphID);
1269
0
      c->copy<Mapping> (mapping);
1270
0
    }
1271
0
1272
0
    return out;
1273
0
  }
1274
1275
  public:
1276
  DEFINE_SIZE_ARRAY (4, *this);
1277
};
1278
1279
template <typename Types>
1280
struct VariationSelectorRecord
1281
{
1282
  glyph_variant_t get_glyph (hb_codepoint_t codepoint,
1283
           hb_codepoint_t *glyph,
1284
           const void *base) const
1285
0
  {
1286
0
    if ((base+defaultUVS).bfind (codepoint))
1287
0
      return GLYPH_VARIANT_USE_DEFAULT;
1288
0
    const UVSMapping<Types> &nonDefault = (base+nonDefaultUVS).bsearch (codepoint);
1289
0
    if (nonDefault.glyphID)
1290
0
    {
1291
0
      *glyph = nonDefault.glyphID;
1292
0
       return GLYPH_VARIANT_FOUND;
1293
0
    }
1294
0
    return GLYPH_VARIANT_NOT_FOUND;
1295
0
  }
1296
1297
  VariationSelectorRecord(const VariationSelectorRecord& other)
1298
  {
1299
    *this = other;
1300
  }
1301
1302
  void operator= (const VariationSelectorRecord& other)
1303
0
  {
1304
0
    varSelector = other.varSelector;
1305
0
    HBUINT32 offset = other.defaultUVS;
1306
0
    defaultUVS = offset;
1307
0
    offset = other.nonDefaultUVS;
1308
0
    nonDefaultUVS = offset;
1309
0
  }
1310
1311
  void collect_unicodes (hb_set_t *out, const void *base) const
1312
0
  {
1313
0
    (base+defaultUVS).collect_unicodes (out);
1314
0
    (base+nonDefaultUVS).collect_unicodes (out);
1315
0
  }
1316
1317
  void collect_mapping (const void *base,
1318
      hb_set_t *unicodes, /* OUT */
1319
      hb_map_t *mapping /* OUT */) const
1320
  {
1321
    (base+defaultUVS).collect_unicodes (unicodes);
1322
    (base+nonDefaultUVS).collect_mapping (unicodes, mapping);
1323
  }
1324
1325
  int cmp (const hb_codepoint_t &variation_selector) const
1326
0
  { return varSelector.cmp (variation_selector); }
1327
1328
  bool sanitize (hb_sanitize_context_t *c, const void *base) const
1329
0
  {
1330
0
    TRACE_SANITIZE (this);
1331
0
    return_trace (c->check_struct (this) &&
1332
0
      defaultUVS.sanitize (c, base) &&
1333
0
      nonDefaultUVS.sanitize (c, base));
1334
0
  }
1335
1336
  hb_pair_t<unsigned, unsigned>
1337
  copy (hb_serialize_context_t *c,
1338
  const hb_set_t *unicodes,
1339
  const hb_set_t *glyphs_requested,
1340
  const hb_map_t *glyph_map,
1341
  const void *base) const
1342
0
  {
1343
0
    auto snap = c->snapshot ();
1344
0
    auto *out = c->embed<VariationSelectorRecord> (*this);
1345
0
    if (unlikely (!out)) return hb_pair (0, 0);
1346
0
1347
0
    out->defaultUVS = 0;
1348
0
    out->nonDefaultUVS = 0;
1349
0
1350
0
    unsigned non_default_uvs_objidx = 0;
1351
0
    if (nonDefaultUVS != 0)
1352
0
    {
1353
0
      c->push ();
1354
0
      if (c->copy (base+nonDefaultUVS, unicodes, glyphs_requested, glyph_map))
1355
0
  non_default_uvs_objidx = c->pop_pack ();
1356
0
      else c->pop_discard ();
1357
0
    }
1358
0
1359
0
    unsigned default_uvs_objidx = 0;
1360
0
    if (defaultUVS != 0)
1361
0
    {
1362
0
      c->push ();
1363
0
      if (c->copy (base+defaultUVS, unicodes))
1364
0
  default_uvs_objidx = c->pop_pack ();
1365
0
      else c->pop_discard ();
1366
0
    }
1367
0
1368
0
1369
0
    if (!default_uvs_objidx && !non_default_uvs_objidx)
1370
0
      c->revert (snap);
1371
0
1372
0
    return hb_pair (default_uvs_objidx, non_default_uvs_objidx);
1373
0
  }
1374
1375
  HBUINT24  varSelector;  /* Variation selector. */
1376
  Offset32To<DefaultUVS>
1377
    defaultUVS; /* Offset to Default UVS Table.  May be 0. */
1378
  Offset32To<NonDefaultUVS<Types>>
1379
    nonDefaultUVS;  /* Offset to Non-Default UVS Table.  May be 0. */
1380
  public:
1381
  DEFINE_SIZE_STATIC (11);
1382
};
1383
1384
template <typename Types>
1385
struct CmapSubtableFormat14_15
1386
{
1387
  static constexpr unsigned format_value = Types::size == 2 ? 14 : 15;
1388
  using Record = VariationSelectorRecord<Types>;
1389
  using NonDefault = NonDefaultUVS<Types>;
1390
1391
  glyph_variant_t get_glyph_variant (hb_codepoint_t codepoint,
1392
             hb_codepoint_t variation_selector,
1393
             hb_codepoint_t *glyph) const
1394
0
  { return record.bsearch (variation_selector).get_glyph (codepoint, glyph, this); }
1395
1396
  void collect_variation_selectors (hb_set_t *out) const
1397
0
  {
1398
0
    for (const auto& a : record.as_array ())
1399
0
      out->add (a.varSelector);
1400
0
  }
1401
  void collect_variation_unicodes (hb_codepoint_t variation_selector,
1402
           hb_set_t *out) const
1403
0
  { record.bsearch (variation_selector).collect_unicodes (out, this); }
1404
1405
  void serialize (hb_serialize_context_t *c,
1406
      const hb_set_t *unicodes,
1407
      const hb_set_t *glyphs_requested,
1408
      const hb_map_t *glyph_map,
1409
      const void *base)
1410
0
  {
1411
0
    auto snap = c->snapshot ();
1412
0
    unsigned table_initpos = c->length ();
1413
0
    const char* init_tail = c->tail;
1414
0
1415
0
    if (unlikely (!c->extend_min (this))) return;
1416
0
    this->format = format_value;
1417
0
1418
0
    auto src_tbl = reinterpret_cast<const CmapSubtableFormat14_15*> (base);
1419
0
1420
0
    /*
1421
0
     * Some versions of OTS require that offsets are in order. Due to the use
1422
0
     * of push()/pop_pack() serializing the variation records in order results
1423
0
     * in the offsets being in reverse order (first record has the largest
1424
0
     * offset). While this is perfectly valid, it will cause some versions of
1425
0
     * OTS to consider this table bad.
1426
0
     *
1427
0
     * So to prevent this issue we serialize the variation records in reverse
1428
0
     * order, so that the offsets are ordered from small to large. Since
1429
0
     * variation records are supposed to be in increasing order of varSelector
1430
0
     * we then have to reverse the order of the written variation selector
1431
0
     * records after everything is finalized.
1432
0
     */
1433
0
    hb_vector_t<hb_pair_t<unsigned, unsigned>> obj_indices;
1434
0
    for (int i = src_tbl->record.len - 1; i >= 0; i--)
1435
0
    {
1436
0
      if (!unicodes->has(src_tbl->record[i].varSelector))
1437
0
        continue;
1438
0
1439
0
      hb_pair_t<unsigned, unsigned> result = src_tbl->record[i].copy (c, unicodes, glyphs_requested, glyph_map, base);
1440
0
      if (result.first || result.second)
1441
0
  obj_indices.push (result);
1442
0
    }
1443
0
1444
0
    if (c->length () - table_initpos == CmapSubtableFormat14_15::min_size)
1445
0
    {
1446
0
      c->revert (snap);
1447
0
      return;
1448
0
    }
1449
0
1450
0
    if (unlikely (!c->check_success (!obj_indices.in_error ())))
1451
0
      return;
1452
0
1453
0
    int tail_len = init_tail - c->tail;
1454
0
    c->check_assign (this->length, c->length () - table_initpos + tail_len,
1455
0
                     HB_SERIALIZE_ERROR_INT_OVERFLOW);
1456
0
    c->check_assign (this->record.len,
1457
0
         (c->length () - table_initpos - CmapSubtableFormat14_15::min_size) /
1458
0
         Record::static_size,
1459
0
                     HB_SERIALIZE_ERROR_INT_OVERFLOW);
1460
0
1461
0
    /* Correct the incorrect write order by reversing the order of the variation
1462
0
       records array. */
1463
0
    _reverse_variation_records ();
1464
0
1465
0
    /* Now that records are in the right order, we can set up the offsets. */
1466
0
    _add_links_to_variation_records (c, obj_indices);
1467
0
  }
1468
1469
  void _reverse_variation_records ()
1470
0
  {
1471
0
    record.as_array ().reverse ();
1472
0
  }
1473
1474
  void _add_links_to_variation_records (hb_serialize_context_t *c,
1475
          const hb_vector_t<hb_pair_t<unsigned, unsigned>>& obj_indices)
1476
0
  {
1477
0
    for (unsigned i = 0; i < obj_indices.length; i++)
1478
0
    {
1479
0
      /*
1480
0
       * Since the record array has been reversed (see comments in copy())
1481
0
       * but obj_indices has not been, the indices at obj_indices[i]
1482
0
       * are for the variation record at record[j].
1483
0
       */
1484
0
      int j = obj_indices.length - 1 - i;
1485
0
      c->add_link (record[j].defaultUVS, obj_indices[i].first);
1486
0
      c->add_link (record[j].nonDefaultUVS, obj_indices[i].second);
1487
0
    }
1488
0
  }
1489
1490
  void closure_glyphs (const hb_set_t      *unicodes,
1491
           hb_set_t            *glyphset) const
1492
0
  {
1493
0
    + hb_iter (record)
1494
0
    | hb_filter (hb_bool, &Record::nonDefaultUVS)
1495
0
    | hb_filter (unicodes, &Record::varSelector)
1496
0
    | hb_map (&Record::nonDefaultUVS)
1497
0
    | hb_map (hb_add (this))
1498
0
    | hb_apply ([=] (const NonDefault& _) { _.closure_glyphs (unicodes, glyphset); })
1499
0
    ;
1500
0
  }
1501
1502
  void collect_unicodes (hb_set_t *out) const
1503
  {
1504
    for (const Record& _ : record)
1505
      _.collect_unicodes (out, this);
1506
  }
1507
1508
  void collect_mapping (hb_set_t *unicodes, /* OUT */
1509
      hb_map_t *mapping /* OUT */) const
1510
  {
1511
    for (const Record& _ : record)
1512
      _.collect_mapping (this, unicodes, mapping);
1513
  }
1514
1515
  bool sanitize (hb_sanitize_context_t *c) const
1516
0
  {
1517
0
    TRACE_SANITIZE (this);
1518
0
    return_trace (c->check_struct (this) &&
1519
0
      record.sanitize (c, this));
1520
0
  }
1521
1522
  protected:
1523
  HBUINT16  format;   /* Format number is set to 14 or 15. */
1524
  HBUINT32  length;   /* Byte length of this subtable. */
1525
  SortedArray32Of<Record>
1526
    record;   /* Variation selector records; sorted
1527
         * in increasing order of `varSelector'. */
1528
  public:
1529
  DEFINE_SIZE_ARRAY (10, record);
1530
};
1531
1532
struct CmapSubtable
1533
{
1534
  /* Note: We intentionally do NOT implement subtable formats 2 and 8. */
1535
1536
  bool is_variation_selector () const
1537
0
  {
1538
0
    switch (u.format.v) {
1539
0
    case 14:
1540
0
#ifndef HB_NO_BEYOND_64K
1541
0
    case 15:
1542
0
#endif
1543
0
      return true;
1544
0
    default:
1545
0
      return false;
1546
0
    }
1547
0
  }
1548
1549
  glyph_variant_t get_glyph_variant (hb_codepoint_t codepoint,
1550
             hb_codepoint_t variation_selector,
1551
             hb_codepoint_t *glyph) const
1552
0
  {
1553
0
    switch (u.format.v) {
1554
0
    case 14: hb_barrier (); return u.format14.get_glyph_variant (codepoint, variation_selector, glyph);
1555
#ifndef HB_NO_BEYOND_64K
1556
    case 15: hb_barrier (); return u.format15.get_glyph_variant (codepoint, variation_selector, glyph);
1557
#endif
1558
0
    default: return GLYPH_VARIANT_NOT_FOUND;
1559
0
    }
1560
0
  }
1561
1562
  void collect_variation_selectors (hb_set_t *out) const
1563
0
  {
1564
0
    switch (u.format.v) {
1565
0
    case 14: hb_barrier (); u.format14.collect_variation_selectors (out); return;
1566
#ifndef HB_NO_BEYOND_64K
1567
    case 15: hb_barrier (); u.format15.collect_variation_selectors (out); return;
1568
#endif
1569
0
    default: return;
1570
0
    }
1571
0
  }
1572
1573
  void collect_variation_unicodes (hb_codepoint_t variation_selector,
1574
            hb_set_t *out) const
1575
0
  {
1576
0
    switch (u.format.v) {
1577
0
    case 14: hb_barrier (); u.format14.collect_variation_unicodes (variation_selector, out); return;
1578
#ifndef HB_NO_BEYOND_64K
1579
    case 15: hb_barrier (); u.format15.collect_variation_unicodes (variation_selector, out); return;
1580
#endif
1581
0
    default: return;
1582
0
    }
1583
0
  }
1584
1585
  void closure_glyphs (const hb_set_t *unicodes, hb_set_t *glyphset) const
1586
0
  {
1587
0
    switch (u.format.v) {
1588
0
    case 14: hb_barrier (); u.format14.closure_glyphs (unicodes, glyphset); return;
1589
0
#ifndef HB_NO_BEYOND_64K
1590
0
    case 15: hb_barrier (); u.format15.closure_glyphs (unicodes, glyphset); return;
1591
0
#endif
1592
0
    default: return;
1593
0
    }
1594
0
  }
1595
1596
  bool get_glyph (hb_codepoint_t codepoint,
1597
      hb_codepoint_t *glyph,
1598
      unsigned int subtable_data_size = 0) const
1599
0
  {
1600
0
    switch (u.format.v) {
1601
0
    case  0: hb_barrier (); return u.format0 .get_glyph (codepoint, glyph);
1602
0
    case  4: hb_barrier (); return subtable_data_size
1603
0
              ? u.format4.get_glyph (codepoint, glyph, subtable_data_size)
1604
0
              : false;
1605
0
    case  6: hb_barrier (); return u.format6 .get_glyph (codepoint, glyph);
1606
0
    case 10: hb_barrier (); return u.format10.get_glyph (codepoint, glyph);
1607
0
    case 12: hb_barrier (); return u.format12.get_glyph (codepoint, glyph);
1608
0
    case 13: hb_barrier (); return u.format13.get_glyph (codepoint, glyph);
1609
0
    case 14:
1610
0
    default: return false;
1611
0
    }
1612
0
  }
1613
  void collect_unicodes (hb_set_t *out,
1614
       unsigned int num_glyphs = UINT_MAX,
1615
       unsigned int subtable_data_size = 0) const
1616
0
  {
1617
0
    switch (u.format.v) {
1618
0
    case  0: hb_barrier (); u.format0 .collect_unicodes (out); return;
1619
0
    case  4: hb_barrier (); if (subtable_data_size)
1620
0
            u.format4.collect_unicodes (out, subtable_data_size);
1621
0
          else
1622
0
            u.format4.collect_unicodes (out);
1623
0
          return;
1624
0
    case  6: hb_barrier (); u.format6 .collect_unicodes (out); return;
1625
0
    case 10: hb_barrier (); u.format10.collect_unicodes (out); return;
1626
0
    case 12: hb_barrier (); u.format12.collect_unicodes (out, num_glyphs); return;
1627
0
    case 13: hb_barrier (); u.format13.collect_unicodes (out, num_glyphs); return;
1628
0
    case 14:
1629
0
    default: return;
1630
0
    }
1631
0
  }
1632
1633
  void collect_mapping (hb_set_t *unicodes, /* OUT */
1634
      hb_map_t *mapping, /* OUT */
1635
      unsigned num_glyphs = UINT_MAX,
1636
      unsigned int subtable_data_size = 0) const
1637
0
  {
1638
0
    switch (u.format.v) {
1639
0
    case  0: hb_barrier (); u.format0 .collect_mapping (unicodes, mapping); return;
1640
0
    case  4: hb_barrier (); if (subtable_data_size)
1641
0
            u.format4.collect_mapping (unicodes, mapping, subtable_data_size);
1642
0
          else
1643
0
            u.format4.collect_mapping (unicodes, mapping);
1644
0
          return;
1645
0
    case  6: hb_barrier (); u.format6 .collect_mapping (unicodes, mapping); return;
1646
0
    case 10: hb_barrier (); u.format10.collect_mapping (unicodes, mapping); return;
1647
0
    case 12: hb_barrier (); u.format12.collect_mapping (unicodes, mapping, num_glyphs); return;
1648
0
    case 13: hb_barrier (); u.format13.collect_mapping (unicodes, mapping, num_glyphs); return;
1649
0
    case 14:
1650
0
    default: return;
1651
0
    }
1652
0
  }
1653
1654
  unsigned get_language () const
1655
0
  {
1656
0
    switch (u.format.v) {
1657
0
    case  0: hb_barrier (); return u.format0 .get_language ();
1658
0
    case  4: hb_barrier (); return u.format4 .get_language ();
1659
0
    case  6: hb_barrier (); return u.format6 .get_language ();
1660
0
    case 10: hb_barrier (); return u.format10.get_language ();
1661
0
    case 12: hb_barrier (); return u.format12.get_language ();
1662
0
    case 13: hb_barrier (); return u.format13.get_language ();
1663
0
    case 14:
1664
0
    default: return 0;
1665
0
    }
1666
0
  }
1667
1668
  template<typename Iterator,
1669
     hb_requires (hb_is_iterator (Iterator))>
1670
  void serialize (hb_serialize_context_t *c,
1671
      Iterator it,
1672
      unsigned format,
1673
      const hb_subset_plan_t *plan,
1674
      const void *base)
1675
0
  {
1676
0
    switch (format) {
1677
0
    case  4: hb_barrier (); return u.format4.serialize (c, it);
1678
0
    case 12: hb_barrier (); return u.format12.serialize (c, it);
1679
0
    case 14: hb_barrier (); return u.format14.serialize (c, &plan->unicodes, &plan->glyphs_requested, plan->glyph_map, base);
1680
0
#ifndef HB_NO_BEYOND_64K
1681
0
    case 15: hb_barrier (); return u.format15.serialize (c, &plan->unicodes, &plan->glyphs_requested, plan->glyph_map, base);
1682
0
#endif
1683
0
    default: return;
1684
0
    }
1685
0
  }
Unexecuted instantiation: hb-face.cc:_ZN2OT12CmapSubtable9serializeI16hb_filter_iter_tIS2_I17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS_4cmap6subsetEP19hb_subset_context_tbEUlS5_E_RK4$_17LPv0EERK8hb_set_tRK3$_7LSF_0EETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NSP_6item_tEEE5valueEvE4typeELSF_0EEEvP22hb_serialize_context_tSP_jPK16hb_subset_plan_tPKv
Unexecuted instantiation: hb-face.cc:_ZN2OT12CmapSubtable9serializeI16hb_filter_iter_tI17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS_4cmap6subsetEP19hb_subset_context_tbEUlS5_E_RK4$_17LPv0EETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NSI_6item_tEEE5valueEvE4typeELSF_0EEEvP22hb_serialize_context_tSI_jPK16hb_subset_plan_tPKv
Unexecuted instantiation: hb-ot-face.cc:_ZN2OT12CmapSubtable9serializeI16hb_filter_iter_tIS2_I17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS_4cmap6subsetEP19hb_subset_context_tbEUlS5_E_RK4$_17LPv0EERK8hb_set_tRK3$_7LSF_0EETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NSP_6item_tEEE5valueEvE4typeELSF_0EEEvP22hb_serialize_context_tSP_jPK16hb_subset_plan_tPKv
Unexecuted instantiation: hb-ot-face.cc:_ZN2OT12CmapSubtable9serializeI16hb_filter_iter_tI17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS_4cmap6subsetEP19hb_subset_context_tbEUlS5_E_RK4$_17LPv0EETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NSI_6item_tEEE5valueEvE4typeELSF_0EEEvP22hb_serialize_context_tSI_jPK16hb_subset_plan_tPKv
Unexecuted instantiation: hb-ot-font.cc:_ZN2OT12CmapSubtable9serializeI16hb_filter_iter_tIS2_I17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS_4cmap6subsetEP19hb_subset_context_tbEUlS5_E_RK4$_17LPv0EERK8hb_set_tRK3$_7LSF_0EETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NSP_6item_tEEE5valueEvE4typeELSF_0EEEvP22hb_serialize_context_tSP_jPK16hb_subset_plan_tPKv
Unexecuted instantiation: hb-ot-font.cc:_ZN2OT12CmapSubtable9serializeI16hb_filter_iter_tI17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS_4cmap6subsetEP19hb_subset_context_tbEUlS5_E_RK4$_17LPv0EETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NSI_6item_tEEE5valueEvE4typeELSF_0EEEvP22hb_serialize_context_tSI_jPK16hb_subset_plan_tPKv
Unexecuted instantiation: hb-static.cc:_ZN2OT12CmapSubtable9serializeI16hb_filter_iter_tIS2_I17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS_4cmap6subsetEP19hb_subset_context_tbEUlS5_E_RK4$_17LPv0EERK8hb_set_tRK3$_7LSF_0EETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NSP_6item_tEEE5valueEvE4typeELSF_0EEEvP22hb_serialize_context_tSP_jPK16hb_subset_plan_tPKv
Unexecuted instantiation: hb-static.cc:_ZN2OT12CmapSubtable9serializeI16hb_filter_iter_tI17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS_4cmap6subsetEP19hb_subset_context_tbEUlS5_E_RK4$_17LPv0EETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NSI_6item_tEEE5valueEvE4typeELSF_0EEEvP22hb_serialize_context_tSI_jPK16hb_subset_plan_tPKv
1686
1687
  bool sanitize (hb_sanitize_context_t *c) const
1688
0
  {
1689
0
    TRACE_SANITIZE (this);
1690
0
    if (!u.format.v.sanitize (c)) return_trace (false);
1691
0
    hb_barrier ();
1692
0
    switch (u.format.v) {
1693
0
    case  0: hb_barrier (); return_trace (u.format0 .sanitize (c));
1694
0
    case  4: hb_barrier (); return_trace (u.format4 .sanitize (c));
1695
0
    case  6: hb_barrier (); return_trace (u.format6 .sanitize (c));
1696
0
    case 10: hb_barrier (); return_trace (u.format10.sanitize (c));
1697
0
    case 12: hb_barrier (); return_trace (u.format12.sanitize (c));
1698
0
    case 13: hb_barrier (); return_trace (u.format13.sanitize (c));
1699
0
    case 14: hb_barrier (); return_trace (u.format14.sanitize (c));
1700
#ifndef HB_NO_BEYOND_64K
1701
    case 15: hb_barrier (); return_trace (u.format15.sanitize (c));
1702
#endif
1703
0
    default:return_trace (true);
1704
0
    }
1705
0
  }
1706
1707
  public:
1708
  union {
1709
  struct { HBUINT16 v; }  format;   /* Format identifier */
1710
  CmapSubtableFormat0 format0;
1711
  CmapSubtableFormat4 format4;
1712
  CmapSubtableFormat6 format6;
1713
  CmapSubtableFormat10  format10;
1714
  CmapSubtableFormat12  format12;
1715
  CmapSubtableFormat13  format13;
1716
  CmapSubtableFormat14_15<Layout::SmallTypes>
1717
      format14;
1718
#ifndef HB_NO_BEYOND_64K
1719
  CmapSubtableFormat14_15<Layout::MediumTypes>
1720
      format15;
1721
#endif
1722
  } u;
1723
  public:
1724
  DEFINE_SIZE_UNION (2, format.v);
1725
};
1726
1727
1728
struct EncodingRecord
1729
{
1730
  int cmp (const EncodingRecord &other) const
1731
0
  {
1732
0
    int ret;
1733
0
    ret = platformID.cmp (other.platformID);
1734
0
    if (ret) return ret;
1735
0
    if (other.encodingID != 0xFFFF)
1736
0
    {
1737
0
      ret = encodingID.cmp (other.encodingID);
1738
0
      if (ret) return ret;
1739
0
    }
1740
0
    return 0;
1741
0
  }
1742
1743
  bool sanitize (hb_sanitize_context_t *c, const void *base) const
1744
0
  {
1745
0
    TRACE_SANITIZE (this);
1746
0
    return_trace (c->check_struct (this) &&
1747
0
      subtable.sanitize (c, base));
1748
0
  }
1749
1750
  template<typename Iterator,
1751
     hb_requires (hb_is_iterator (Iterator))>
1752
  EncodingRecord* copy (hb_serialize_context_t *c,
1753
      Iterator it,
1754
      unsigned format,
1755
      const void *base,
1756
      const hb_subset_plan_t *plan,
1757
      /* INOUT */ unsigned *objidx) const
1758
0
  {
1759
0
    TRACE_SERIALIZE (this);
1760
0
    auto snap = c->snapshot ();
1761
0
    auto *out = c->embed (this);
1762
0
    if (unlikely (!out)) return_trace (nullptr);
1763
0
    out->subtable = 0;
1764
0
1765
0
    if (*objidx == 0)
1766
0
    {
1767
0
      CmapSubtable *cmapsubtable = c->push<CmapSubtable> ();
1768
0
      unsigned origin_length = c->length ();
1769
0
      cmapsubtable->serialize (c, it, format, plan, &(base+subtable));
1770
0
      if (c->length () > origin_length && !c->in_error()) *objidx = c->pop_pack ();
1771
0
      else c->pop_discard ();
1772
0
    }
1773
0
1774
0
    if (*objidx == 0)
1775
0
    {
1776
0
      c->revert (snap);
1777
0
      return_trace (nullptr);
1778
0
    }
1779
0
1780
0
    c->add_link (out->subtable, *objidx);
1781
0
    return_trace (out);
1782
0
  }
Unexecuted instantiation: hb-face.cc:_ZNK2OT14EncodingRecord4copyI16hb_filter_iter_tIS2_I17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS_4cmap6subsetEP19hb_subset_context_tbEUlS5_E_RK4$_17LPv0EERK8hb_set_tRK3$_7LSF_0EETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NSP_6item_tEEE5valueEvE4typeELSF_0EEEPS0_P22hb_serialize_context_tSP_jPKvPK16hb_subset_plan_tPj
Unexecuted instantiation: hb-face.cc:_ZNK2OT14EncodingRecord4copyI16hb_filter_iter_tI17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS_4cmap6subsetEP19hb_subset_context_tbEUlS5_E_RK4$_17LPv0EETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NSI_6item_tEEE5valueEvE4typeELSF_0EEEPS0_P22hb_serialize_context_tSI_jPKvPK16hb_subset_plan_tPj
Unexecuted instantiation: hb-ot-face.cc:_ZNK2OT14EncodingRecord4copyI16hb_filter_iter_tIS2_I17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS_4cmap6subsetEP19hb_subset_context_tbEUlS5_E_RK4$_17LPv0EERK8hb_set_tRK3$_7LSF_0EETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NSP_6item_tEEE5valueEvE4typeELSF_0EEEPS0_P22hb_serialize_context_tSP_jPKvPK16hb_subset_plan_tPj
Unexecuted instantiation: hb-ot-face.cc:_ZNK2OT14EncodingRecord4copyI16hb_filter_iter_tI17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS_4cmap6subsetEP19hb_subset_context_tbEUlS5_E_RK4$_17LPv0EETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NSI_6item_tEEE5valueEvE4typeELSF_0EEEPS0_P22hb_serialize_context_tSI_jPKvPK16hb_subset_plan_tPj
Unexecuted instantiation: hb-ot-font.cc:_ZNK2OT14EncodingRecord4copyI16hb_filter_iter_tIS2_I17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS_4cmap6subsetEP19hb_subset_context_tbEUlS5_E_RK4$_17LPv0EERK8hb_set_tRK3$_7LSF_0EETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NSP_6item_tEEE5valueEvE4typeELSF_0EEEPS0_P22hb_serialize_context_tSP_jPKvPK16hb_subset_plan_tPj
Unexecuted instantiation: hb-ot-font.cc:_ZNK2OT14EncodingRecord4copyI16hb_filter_iter_tI17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS_4cmap6subsetEP19hb_subset_context_tbEUlS5_E_RK4$_17LPv0EETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NSI_6item_tEEE5valueEvE4typeELSF_0EEEPS0_P22hb_serialize_context_tSI_jPKvPK16hb_subset_plan_tPj
Unexecuted instantiation: hb-static.cc:_ZNK2OT14EncodingRecord4copyI16hb_filter_iter_tIS2_I17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS_4cmap6subsetEP19hb_subset_context_tbEUlS5_E_RK4$_17LPv0EERK8hb_set_tRK3$_7LSF_0EETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NSP_6item_tEEE5valueEvE4typeELSF_0EEEPS0_P22hb_serialize_context_tSP_jPKvPK16hb_subset_plan_tPj
Unexecuted instantiation: hb-static.cc:_ZNK2OT14EncodingRecord4copyI16hb_filter_iter_tI17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS_4cmap6subsetEP19hb_subset_context_tbEUlS5_E_RK4$_17LPv0EETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NSI_6item_tEEE5valueEvE4typeELSF_0EEEPS0_P22hb_serialize_context_tSI_jPKvPK16hb_subset_plan_tPj
1783
1784
  HBUINT16  platformID; /* Platform ID. */
1785
  HBUINT16  encodingID; /* Platform-specific encoding ID. */
1786
  Offset32To<CmapSubtable>
1787
    subtable; /* Byte offset from beginning of table to the subtable for this encoding. */
1788
  public:
1789
  DEFINE_SIZE_STATIC (8);
1790
};
1791
1792
struct cmap;
1793
1794
struct SubtableUnicodesCache {
1795
1796
 private:
1797
  hb_blob_ptr_t<cmap> base_blob;
1798
  const char* base;
1799
  unsigned int table_length;
1800
  hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> cached_unicodes;
1801
1802
 public:
1803
1804
  static SubtableUnicodesCache* create (hb_blob_ptr_t<cmap> source_table)
1805
0
  {
1806
0
    SubtableUnicodesCache* cache =
1807
0
        (SubtableUnicodesCache*) hb_malloc (sizeof(SubtableUnicodesCache));
1808
0
1809
0
    if (unlikely (!cache))
1810
0
      return nullptr;
1811
0
1812
0
    new (cache) SubtableUnicodesCache (source_table);
1813
0
    return cache;
1814
0
  }
1815
1816
0
  static void destroy (void* value) {
1817
0
    if (!value) return;
1818
0
1819
0
    SubtableUnicodesCache* cache = (SubtableUnicodesCache*) value;
1820
0
    cache->~SubtableUnicodesCache ();
1821
0
    hb_free (cache);
1822
0
  }
1823
1824
  SubtableUnicodesCache(const void* cmap_base,
1825
      unsigned int table_length_ = 0)
1826
      : base_blob(),
1827
        base ((const char*) cmap_base),
1828
        table_length (table_length_),
1829
        cached_unicodes ()
1830
0
  {}
1831
1832
  SubtableUnicodesCache(hb_blob_ptr_t<cmap> base_blob_)
1833
      : base_blob(base_blob_),
1834
        base ((const char *) base_blob.get()),
1835
        table_length (base_blob.get_length ()),
1836
        cached_unicodes ()
1837
0
  {}
1838
1839
  ~SubtableUnicodesCache()
1840
0
  {
1841
0
    base_blob.destroy ();
1842
0
  }
1843
1844
  bool same_base(const void* other) const
1845
0
  {
1846
0
    return other == (const void*) base;
1847
0
  }
1848
1849
  const hb_set_t* set_for (const EncodingRecord* record,
1850
                           SubtableUnicodesCache& mutable_cache) const
1851
0
  {
1852
0
    if (cached_unicodes.has ((unsigned) ((const char *) record - base)))
1853
0
      return cached_unicodes.get ((unsigned) ((const char *) record - base));
1854
0
1855
0
    return mutable_cache.set_for (record);
1856
0
  }
1857
1858
  const hb_set_t* set_for (const EncodingRecord* record)
1859
0
  {
1860
0
    if (!cached_unicodes.has ((unsigned) ((const char *) record - base)))
1861
0
    {
1862
0
      hb_set_t *s = hb_set_create ();
1863
0
      if (unlikely (s->in_error ()))
1864
0
  return hb_set_get_empty ();
1865
0
1866
0
      unsigned int subtable_data_size = record->subtable < table_length
1867
0
          ? table_length - (unsigned int) record->subtable
1868
0
          : 0;
1869
0
      (base+record->subtable).collect_unicodes (s, UINT_MAX, subtable_data_size);
1870
0
1871
0
      if (unlikely (!cached_unicodes.set ((unsigned) ((const char *) record - base), hb::unique_ptr<hb_set_t> {s})))
1872
0
        return hb_set_get_empty ();
1873
0
1874
0
      return s;
1875
0
    }
1876
0
    return cached_unicodes.get ((unsigned) ((const char *) record - base));
1877
0
  }
1878
1879
};
1880
1881
static inline uint16_t
1882
_hb_symbol_pua_map (unsigned codepoint)
1883
0
{
1884
0
  if (codepoint <= 0x00FFu)
1885
0
  {
1886
    /* For symbol-encoded OpenType fonts, we duplicate the
1887
     * U+F000..F0FF range at U+0000..U+00FF.  That's what
1888
     * Windows seems to do, and that's hinted about at:
1889
     * https://docs.microsoft.com/en-us/typography/opentype/spec/recom
1890
     * under "Non-Standard (Symbol) Fonts". */
1891
0
    return 0xF000u + codepoint;
1892
0
  }
1893
0
  return 0;
1894
0
}
Unexecuted instantiation: hb-face.cc:OT::_hb_symbol_pua_map(unsigned int)
Unexecuted instantiation: hb-ot-face.cc:OT::_hb_symbol_pua_map(unsigned int)
Unexecuted instantiation: hb-ot-font.cc:OT::_hb_symbol_pua_map(unsigned int)
Unexecuted instantiation: hb-static.cc:OT::_hb_symbol_pua_map(unsigned int)
1895
1896
struct cmap
1897
{
1898
  static constexpr hb_tag_t tableTag = HB_OT_TAG_cmap;
1899
1900
1901
0
  static SubtableUnicodesCache* create_filled_cache(hb_blob_ptr_t<cmap> source_table) {
1902
0
    const cmap* cmap = source_table.get();
1903
0
    auto it =
1904
0
    + hb_iter (cmap->encodingRecord)
1905
0
    | hb_filter ([&](const EncodingRecord& _) {
1906
0
      return cmap::filter_encoding_records_for_subset (cmap, _);
1907
0
    })
1908
0
    ;
1909
0
1910
0
    SubtableUnicodesCache* cache = SubtableUnicodesCache::create(source_table);
1911
0
1912
0
    if (unlikely (!cache))
1913
0
      return nullptr;
1914
0
1915
0
    for (const EncodingRecord& _ : it)
1916
0
      cache->set_for(&_); // populate the cache for this encoding record.
1917
0
1918
0
    return cache;
1919
0
  }
1920
1921
  template<typename Iterator, typename EncodingRecIter,
1922
     hb_requires (hb_is_iterator (EncodingRecIter))>
1923
  bool serialize (hb_serialize_context_t *c,
1924
      Iterator it,
1925
      EncodingRecIter encodingrec_iter,
1926
      const void *base,
1927
      hb_subset_plan_t *plan,
1928
                    bool drop_format_4 = false,
1929
        unsigned int source_table_length = 0)
1930
0
  {
1931
0
    if (unlikely (!c->extend_min ((*this))))  return false;
1932
0
    this->version = 0;
1933
0
1934
0
    unsigned format4objidx = 0, format12objidx = 0, format14objidx = 0;
1935
0
#ifndef HB_NO_BEYOND_64K
1936
0
    unsigned format15objidx = 0;
1937
0
#endif
1938
0
    auto snap = c->snapshot ();
1939
0
1940
0
    SubtableUnicodesCache local_unicodes_cache (base, source_table_length);
1941
0
    const SubtableUnicodesCache* unicodes_cache = &local_unicodes_cache;
1942
0
1943
0
    if (plan->accelerator &&
1944
0
        plan->accelerator->cmap_cache &&
1945
0
        plan->accelerator->cmap_cache->same_base (base))
1946
0
      unicodes_cache = plan->accelerator->cmap_cache;
1947
0
1948
0
    for (const EncodingRecord& _ : encodingrec_iter)
1949
0
    {
1950
0
      if (c->in_error ())
1951
0
        return false;
1952
0
1953
0
      unsigned format = (base+_.subtable).u.format.v;
1954
0
      if (format != 4 && format != 12 && format != 14
1955
0
#ifndef HB_NO_BEYOND_64K
1956
0
    && format != 15
1957
0
#endif
1958
0
   ) continue;
1959
0
1960
0
      const hb_set_t* unicodes_set = unicodes_cache->set_for (&_, local_unicodes_cache);
1961
0
1962
0
      if (!drop_format_4 && format == 4)
1963
0
      {
1964
0
        c->copy (_, + it | hb_filter (*unicodes_set, hb_first), 4u, base, plan, &format4objidx);
1965
0
        if (c->in_error () && c->only_overflow ())
1966
0
        {
1967
0
          // cmap4 overflowed, reset and retry serialization without format 4 subtables.
1968
0
          c->revert (snap);
1969
0
          return serialize (c, it,
1970
0
                            encodingrec_iter,
1971
0
                            base,
1972
0
                            plan,
1973
0
                            true,
1974
0
          source_table_length);
1975
0
        }
1976
0
      }
1977
0
1978
0
      else if (format == 12)
1979
0
      {
1980
0
        if (_can_drop (_,
1981
0
                       *unicodes_set,
1982
0
                       base,
1983
0
                       *unicodes_cache,
1984
0
                       local_unicodes_cache,
1985
0
                       + it | hb_map (hb_first), encodingrec_iter))
1986
0
          continue;
1987
0
        c->copy (_, + it | hb_filter (*unicodes_set, hb_first), 12u, base, plan, &format12objidx);
1988
0
      }
1989
0
      else if (format == 14) c->copy (_, it, 14u, base, plan, &format14objidx);
1990
0
#ifndef HB_NO_BEYOND_64K
1991
0
      else if (format == 15) c->copy (_, it, 15u, base, plan, &format15objidx);
1992
0
#endif
1993
0
    }
1994
0
        unsigned length = c->length ();
1995
0
        unsigned available = length > cmap::min_size ? length - cmap::min_size : 0;
1996
0
        c->check_assign(this->encodingRecord.len,
1997
0
                        available / EncodingRecord::static_size,
1998
0
                        HB_SERIALIZE_ERROR_INT_OVERFLOW);
1999
0
2000
0
    // Fail if format 4 was dropped and there is no cmap12.
2001
0
    return !drop_format_4 || format12objidx;
2002
0
  }
Unexecuted instantiation: hb-face.cc:_ZN2OT4cmap9serializeI16hb_filter_iter_tI17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS0_6subsetEP19hb_subset_context_tbEUlS5_E_RK4$_17LPv0EES2_IS3_IKNS_14EncodingRecordEEZNKS0_6subsetES9_bEUlRSH_E_SD_LSE_0EETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT0_NSN_6item_tEEE5valueEvE4typeELSE_0EEEbP22hb_serialize_context_tT_SN_PKvP16hb_subset_plan_tbj
Unexecuted instantiation: hb-ot-face.cc:_ZN2OT4cmap9serializeI16hb_filter_iter_tI17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS0_6subsetEP19hb_subset_context_tbEUlS5_E_RK4$_17LPv0EES2_IS3_IKNS_14EncodingRecordEEZNKS0_6subsetES9_bEUlRSH_E_SD_LSE_0EETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT0_NSN_6item_tEEE5valueEvE4typeELSE_0EEEbP22hb_serialize_context_tT_SN_PKvP16hb_subset_plan_tbj
Unexecuted instantiation: hb-ot-font.cc:_ZN2OT4cmap9serializeI16hb_filter_iter_tI17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS0_6subsetEP19hb_subset_context_tbEUlS5_E_RK4$_17LPv0EES2_IS3_IKNS_14EncodingRecordEEZNKS0_6subsetES9_bEUlRSH_E_SD_LSE_0EETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT0_NSN_6item_tEEE5valueEvE4typeELSE_0EEEbP22hb_serialize_context_tT_SN_PKvP16hb_subset_plan_tbj
Unexecuted instantiation: hb-static.cc:_ZN2OT4cmap9serializeI16hb_filter_iter_tI17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS0_6subsetEP19hb_subset_context_tbEUlS5_E_RK4$_17LPv0EES2_IS3_IKNS_14EncodingRecordEEZNKS0_6subsetES9_bEUlRSH_E_SD_LSE_0EETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT0_NSN_6item_tEEE5valueEvE4typeELSE_0EEEbP22hb_serialize_context_tT_SN_PKvP16hb_subset_plan_tbj
2003
2004
  template<typename Iterator, typename EncodingRecordIterator,
2005
      hb_requires (hb_is_iterator (Iterator)),
2006
      hb_requires (hb_is_iterator (EncodingRecordIterator))>
2007
  bool _can_drop (const EncodingRecord& cmap12,
2008
                  const hb_set_t& cmap12_unicodes,
2009
                  const void* base,
2010
                  const SubtableUnicodesCache& unicodes_cache,
2011
                  SubtableUnicodesCache& local_unicodes_cache,
2012
                  Iterator subset_unicodes,
2013
                  EncodingRecordIterator encoding_records)
2014
0
  {
2015
0
    for (auto cp : + subset_unicodes | hb_filter (cmap12_unicodes))
2016
0
    {
2017
0
      if (cp >= 0x10000) return false;
2018
0
    }
2019
0
2020
0
    unsigned target_platform;
2021
0
    unsigned target_encoding;
2022
0
    unsigned target_language = (base+cmap12.subtable).get_language ();
2023
0
2024
0
    if (cmap12.platformID == 0 && cmap12.encodingID == 4)
2025
0
    {
2026
0
      target_platform = 0;
2027
0
      target_encoding = 3;
2028
0
    } else if (cmap12.platformID == 3 && cmap12.encodingID == 10) {
2029
0
      target_platform = 3;
2030
0
      target_encoding = 1;
2031
0
    } else {
2032
0
      return false;
2033
0
    }
2034
0
2035
0
    for (const auto& _ : encoding_records)
2036
0
    {
2037
0
      if (_.platformID != target_platform
2038
0
          || _.encodingID != target_encoding
2039
0
          || (base+_.subtable).get_language() != target_language)
2040
0
        continue;
2041
0
2042
0
      const hb_set_t* sibling_unicodes = unicodes_cache.set_for (&_, local_unicodes_cache);
2043
0
2044
0
      auto cmap12 = + subset_unicodes | hb_filter (cmap12_unicodes);
2045
0
      auto sibling = + subset_unicodes | hb_filter (*sibling_unicodes);
2046
0
      for (; cmap12 && sibling; cmap12++, sibling++)
2047
0
      {
2048
0
        unsigned a = *cmap12;
2049
0
        unsigned b = *sibling;
2050
0
        if (a != b) return false;
2051
0
      }
2052
0
2053
0
      return !cmap12 && !sibling;
2054
0
    }
2055
0
2056
0
    return false;
2057
0
  }
Unexecuted instantiation: hb-face.cc:_ZN2OT4cmap9_can_dropI13hb_map_iter_tI16hb_filter_iter_tI17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS0_6subsetEP19hb_subset_context_tbEUlS6_E_RK4$_17LPv0EERK3$_7L24hb_function_sortedness_t0ELSF_0EES3_IS4_IKNS_14EncodingRecordEEZNKS0_6subsetESA_bEUlRSN_E_SE_LSF_0EETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NST_6item_tEEE5valueEvE4typeELSF_0ETnPNSS_IXsr17hb_is_iterator_ofIT0_NSY_6item_tEEE5valueEvE4typeELSF_0EEEbSP_RK8hb_set_tPKvRKNS_21SubtableUnicodesCacheERS18_ST_SY_
Unexecuted instantiation: hb-ot-face.cc:_ZN2OT4cmap9_can_dropI13hb_map_iter_tI16hb_filter_iter_tI17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS0_6subsetEP19hb_subset_context_tbEUlS6_E_RK4$_17LPv0EERK3$_7L24hb_function_sortedness_t0ELSF_0EES3_IS4_IKNS_14EncodingRecordEEZNKS0_6subsetESA_bEUlRSN_E_SE_LSF_0EETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NST_6item_tEEE5valueEvE4typeELSF_0ETnPNSS_IXsr17hb_is_iterator_ofIT0_NSY_6item_tEEE5valueEvE4typeELSF_0EEEbSP_RK8hb_set_tPKvRKNS_21SubtableUnicodesCacheERS18_ST_SY_
Unexecuted instantiation: hb-ot-font.cc:_ZN2OT4cmap9_can_dropI13hb_map_iter_tI16hb_filter_iter_tI17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS0_6subsetEP19hb_subset_context_tbEUlS6_E_RK4$_17LPv0EERK3$_7L24hb_function_sortedness_t0ELSF_0EES3_IS4_IKNS_14EncodingRecordEEZNKS0_6subsetESA_bEUlRSN_E_SE_LSF_0EETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NST_6item_tEEE5valueEvE4typeELSF_0ETnPNSS_IXsr17hb_is_iterator_ofIT0_NSY_6item_tEEE5valueEvE4typeELSF_0EEEbSP_RK8hb_set_tPKvRKNS_21SubtableUnicodesCacheERS18_ST_SY_
Unexecuted instantiation: hb-static.cc:_ZN2OT4cmap9_can_dropI13hb_map_iter_tI16hb_filter_iter_tI17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS0_6subsetEP19hb_subset_context_tbEUlS6_E_RK4$_17LPv0EERK3$_7L24hb_function_sortedness_t0ELSF_0EES3_IS4_IKNS_14EncodingRecordEEZNKS0_6subsetESA_bEUlRSN_E_SE_LSF_0EETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NST_6item_tEEE5valueEvE4typeELSF_0ETnPNSS_IXsr17hb_is_iterator_ofIT0_NSY_6item_tEEE5valueEvE4typeELSF_0EEEbSP_RK8hb_set_tPKvRKNS_21SubtableUnicodesCacheERS18_ST_SY_
2058
2059
  void closure_glyphs (const hb_set_t      *unicodes,
2060
           hb_set_t            *glyphset) const
2061
0
  {
2062
0
    + hb_iter (encodingRecord)
2063
0
    | hb_map (&EncodingRecord::subtable)
2064
0
    | hb_map (hb_add (this))
2065
0
    | hb_filter (&CmapSubtable::is_variation_selector)
2066
0
    | hb_apply ([=] (const CmapSubtable& _) { _.closure_glyphs (unicodes, glyphset); })
2067
0
    ;
2068
0
  }
2069
2070
  bool subset (hb_subset_context_t *c) const
2071
0
  { return subset (c, false); }
2072
2073
  bool subset (hb_subset_context_t *c, bool is_dmap) const
2074
0
  {
2075
0
    TRACE_SUBSET (this);
2076
0
2077
0
    cmap *cmap_prime = c->serializer->start_embed<cmap> ();
2078
0
2079
0
    auto encodingrec_iter =
2080
0
    + hb_iter (encodingRecord)
2081
0
    | hb_filter ([&](const EncodingRecord& _) {
2082
0
      return cmap::filter_encoding_records_for_subset (this, _);
2083
0
    })
2084
0
    ;
2085
0
2086
0
    if (unlikely (!encodingrec_iter.len ())) return_trace (false);
2087
0
2088
0
    const EncodingRecord *unicode_bmp= nullptr, *unicode_ucs4 = nullptr, *ms_bmp = nullptr, *ms_ucs4 = nullptr;
2089
0
    bool has_format12 = false;
2090
0
2091
0
    for (const EncodingRecord& _ : encodingrec_iter)
2092
0
    {
2093
0
      unsigned format = (this + _.subtable).u.format.v;
2094
0
      if (format == 12) has_format12 = true;
2095
0
2096
0
      const EncodingRecord *table = std::addressof (_);
2097
0
      if      (_.platformID == 0 && _.encodingID ==  3) unicode_bmp = table;
2098
0
      else if (_.platformID == 0 && _.encodingID ==  4) unicode_ucs4 = table;
2099
0
      else if (_.platformID == 3 && _.encodingID ==  1) ms_bmp = table;
2100
0
      else if (_.platformID == 3 && _.encodingID == 10) ms_ucs4 = table;
2101
0
    }
2102
0
2103
0
    if (unlikely (!is_dmap && !has_format12 && !unicode_bmp && !ms_bmp)) return_trace (false);
2104
0
    if (unlikely (!is_dmap && has_format12 && (!unicode_ucs4 && !ms_ucs4))) return_trace (false);
2105
0
2106
0
    auto it =
2107
0
    + c->plan->unicode_to_new_gid_list.iter ()
2108
0
    | hb_filter ([&] (const hb_codepoint_pair_t _)
2109
0
     { return (_.second != HB_MAP_VALUE_INVALID); })
2110
0
    ;
2111
0
2112
0
    return_trace (cmap_prime->serialize (c->serializer,
2113
0
                                         it,
2114
0
                                         encodingrec_iter,
2115
0
                                         this,
2116
0
                                         c->plan,
2117
0
           false,
2118
0
           c->source_blob->length));
2119
0
  }
2120
2121
  const CmapSubtable *find_best_subtable (bool *symbol = nullptr,
2122
            bool *mac = nullptr,
2123
            bool *macroman = nullptr) const
2124
0
  {
2125
0
    if (symbol) *symbol = false;
2126
0
    if (mac) *mac = false;
2127
0
    if (macroman) *macroman = false;
2128
2129
0
    const CmapSubtable *subtable;
2130
2131
    /* Symbol subtable.
2132
     * Prefer symbol if available.
2133
     * https://github.com/harfbuzz/harfbuzz/issues/1918 */
2134
0
    if ((subtable = this->find_subtable (3, 0)))
2135
0
    {
2136
0
      if (symbol) *symbol = true;
2137
0
      return subtable;
2138
0
    }
2139
2140
    /* 32-bit subtables. */
2141
0
    if ((subtable = this->find_subtable (3, 10))) return subtable;
2142
0
    if ((subtable = this->find_subtable (0, 6))) return subtable;
2143
0
    if ((subtable = this->find_subtable (0, 4))) return subtable;
2144
2145
    /* 16-bit subtables. */
2146
0
    if ((subtable = this->find_subtable (3, 1))) return subtable;
2147
0
    if ((subtable = this->find_subtable (0, 3))) return subtable;
2148
0
    if ((subtable = this->find_subtable (0, 2))) return subtable;
2149
0
    if ((subtable = this->find_subtable (0, 1))) return subtable;
2150
0
    if ((subtable = this->find_subtable (0, 0))) return subtable;
2151
2152
    /* MacRoman subtable. */
2153
0
    if ((subtable = this->find_subtable (1, 0)))
2154
0
    {
2155
0
      if (mac) *mac = true;
2156
0
      if (macroman) *macroman = true;
2157
0
      return subtable;
2158
0
    }
2159
    /* Any other Mac subtable; we just map ASCII for these. */
2160
0
    if ((subtable = this->find_subtable (1, 0xFFFF)))
2161
0
    {
2162
0
      if (mac) *mac = true;
2163
0
      return subtable;
2164
0
    }
2165
2166
    /* Meh. */
2167
0
    return &Null (CmapSubtable);
2168
0
  }
2169
2170
  struct accelerator_t
2171
  {
2172
    using cache_t = hb_cache_t<21, 19>;
2173
    static_assert (sizeof (cache_t) == 1024, "");
2174
2175
    accelerator_t (hb_face_t *face, hb_tag_t table_tag = cmap::tableTag)
2176
0
    {
2177
0
      this->table = hb_sanitize_context_t ().reference_table<cmap> (face, table_tag);
2178
0
      if (!this->table.get_length ())
2179
0
  return;
2180
2181
0
      bool symbol, mac, macroman;
2182
0
      this->subtable = table->find_best_subtable (&symbol, &mac, &macroman);
2183
0
      this->subtable_uvs = &Null (CmapSubtable);
2184
0
      {
2185
0
  const CmapSubtable *st = table->find_variation_selector_subtable ();
2186
0
  if (st)
2187
0
    subtable_uvs = st;
2188
0
      }
2189
2190
0
#ifndef HB_NO_OT_FONT_CMAP_CACHE
2191
0
      cache = (cache_t *) hb_malloc (sizeof (cache_t));
2192
0
      if (cache)
2193
0
  new (cache) cache_t ();
2194
0
      else
2195
0
        return; // Such that get_glyph_funcZ remains null.
2196
0
#endif
2197
2198
0
      this->get_glyph_data = subtable;
2199
0
#ifndef HB_NO_CMAP_LEGACY_SUBTABLES
2200
0
      bool is_format4 = subtable->u.format.v == 4;
2201
0
      auto set_format4_getter = [this] (bool (*func) (const void *,
2202
0
                  hb_codepoint_t,
2203
0
                  hb_codepoint_t *))
2204
0
      {
2205
0
  this->format4_accel.init (&this->subtable->u.format4,
2206
0
          get_subtable_data_size (this->subtable));
2207
0
  this->get_glyph_data = &this->format4_accel;
2208
0
  this->get_glyph_funcZ = func;
2209
0
      };
2210
0
      if (unlikely (symbol))
2211
0
      {
2212
0
  switch ((unsigned) face->table.OS2->get_font_page ()) {
2213
0
  case OS2::font_page_t::FONT_PAGE_NONE:
2214
0
    if (is_format4)
2215
0
      set_format4_getter (get_glyph_from_symbol<CmapSubtableFormat4::accelerator_t, _hb_symbol_pua_map>);
2216
0
    else
2217
0
      this->get_glyph_funcZ = get_glyph_from_symbol<CmapSubtable, _hb_symbol_pua_map>;
2218
0
    break;
2219
0
#ifndef HB_NO_OT_SHAPER_ARABIC_FALLBACK
2220
0
  case OS2::font_page_t::FONT_PAGE_SIMP_ARABIC:
2221
0
    if (is_format4)
2222
0
      set_format4_getter (get_glyph_from_symbol<CmapSubtableFormat4::accelerator_t, _hb_arabic_pua_simp_map>);
2223
0
    else
2224
0
      this->get_glyph_funcZ = get_glyph_from_symbol<CmapSubtable, _hb_arabic_pua_simp_map>;
2225
0
    break;
2226
0
  case OS2::font_page_t::FONT_PAGE_TRAD_ARABIC:
2227
0
    if (is_format4)
2228
0
      set_format4_getter (get_glyph_from_symbol<CmapSubtableFormat4::accelerator_t, _hb_arabic_pua_trad_map>);
2229
0
    else
2230
0
      this->get_glyph_funcZ = get_glyph_from_symbol<CmapSubtable, _hb_arabic_pua_trad_map>;
2231
0
    break;
2232
0
#endif
2233
0
  default:
2234
0
    if (is_format4)
2235
0
      set_format4_getter (get_glyph_from<CmapSubtableFormat4::accelerator_t>);
2236
0
    else
2237
0
      this->get_glyph_funcZ = get_glyph_from<CmapSubtable>;
2238
0
    break;
2239
0
  }
2240
0
      }
2241
0
      else if (unlikely (macroman))
2242
0
      {
2243
0
  if (is_format4)
2244
0
    set_format4_getter (get_glyph_from_macroman<CmapSubtableFormat4::accelerator_t>);
2245
0
  else
2246
0
    this->get_glyph_funcZ = get_glyph_from_macroman<CmapSubtable>;
2247
0
      }
2248
0
      else if (unlikely (mac))
2249
0
      {
2250
0
  if (is_format4)
2251
0
    set_format4_getter (get_glyph_from_ascii<CmapSubtableFormat4::accelerator_t>);
2252
0
  else
2253
0
    this->get_glyph_funcZ = get_glyph_from_ascii<CmapSubtable>;
2254
0
      }
2255
0
      else
2256
0
#endif
2257
0
      {
2258
0
  switch (subtable->u.format.v) {
2259
    /* Accelerate format 4 and format 12. */
2260
0
    default:
2261
0
      this->get_glyph_funcZ = get_glyph_from<CmapSubtable>;
2262
0
      break;
2263
0
    case 12:
2264
0
      this->get_glyph_funcZ = get_glyph_from<CmapSubtableFormat12>;
2265
0
      break;
2266
0
    case  4:
2267
0
    {
2268
0
      hb_barrier ();
2269
0
      this->format4_accel.init (&subtable->u.format4,
2270
0
              get_subtable_data_size (subtable));
2271
0
      this->get_glyph_data = &this->format4_accel;
2272
0
      this->get_glyph_funcZ = this->format4_accel.get_glyph_func;
2273
0
      break;
2274
0
    }
2275
0
  }
2276
0
      }
2277
0
    }
2278
    ~accelerator_t ()
2279
0
    {
2280
0
#ifndef HB_NO_OT_FONT_CMAP_CACHE
2281
0
      hb_free (cache);
2282
0
#endif
2283
0
      table.destroy ();
2284
0
    }
2285
2286
    inline bool _cached_get (hb_codepoint_t unicode,
2287
           hb_codepoint_t *glyph) const
2288
0
    {
2289
0
#ifndef HB_NO_OT_FONT_CMAP_CACHE
2290
      // cache is always non-null if we have a get_glyph_funcZ
2291
0
      unsigned v;
2292
0
      if (cache->get (unicode, &v))
2293
0
      {
2294
0
        *glyph = v;
2295
0
  return true;
2296
0
      }
2297
0
#endif
2298
0
      bool ret  = this->get_glyph_funcZ (this->get_glyph_data, unicode, glyph);
2299
2300
0
#ifndef HB_NO_OT_FONT_CMAP_CACHE
2301
0
      if (ret)
2302
0
        cache->set (unicode, *glyph);
2303
0
#endif
2304
2305
0
      return ret;
2306
0
    }
2307
2308
    bool get_nominal_glyph (hb_codepoint_t  unicode,
2309
          hb_codepoint_t *glyph) const
2310
0
    {
2311
0
      if (unlikely (!this->get_glyph_funcZ)) return false;
2312
0
      return _cached_get (unicode, glyph);
2313
0
    }
2314
2315
    unsigned int get_nominal_glyphs (unsigned int count,
2316
             const hb_codepoint_t *first_unicode,
2317
             unsigned int unicode_stride,
2318
             hb_codepoint_t *first_glyph,
2319
             unsigned int glyph_stride) const
2320
0
    {
2321
0
      if (unlikely (!this->get_glyph_funcZ)) return 0;
2322
2323
0
      unsigned int done;
2324
0
      for (done = 0;
2325
0
     done < count && _cached_get (*first_unicode, first_glyph);
2326
0
     done++)
2327
0
      {
2328
0
  first_unicode = &StructAtOffsetUnaligned<hb_codepoint_t> (first_unicode, unicode_stride);
2329
0
  first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
2330
0
      }
2331
0
      return done;
2332
0
    }
2333
2334
    bool get_variation_glyph (hb_codepoint_t  unicode,
2335
            hb_codepoint_t  variation_selector,
2336
            hb_codepoint_t *glyph) const
2337
0
    {
2338
0
      switch (get_glyph_variant (unicode, variation_selector, glyph))
2339
0
      {
2340
0
  case GLYPH_VARIANT_NOT_FOUND: return false;
2341
0
  case GLYPH_VARIANT_FOUND: return true;
2342
0
  case GLYPH_VARIANT_USE_DEFAULT: break;
2343
0
      }
2344
0
2345
0
      return get_nominal_glyph (unicode, glyph);
2346
0
    }
2347
2348
    glyph_variant_t get_glyph_variant (hb_codepoint_t  unicode,
2349
               hb_codepoint_t  variation_selector,
2350
               hb_codepoint_t *glyph) const
2351
0
    {
2352
0
      return this->subtable_uvs->get_glyph_variant (unicode,
2353
0
                variation_selector,
2354
0
                glyph);
2355
0
    }
2356
2357
0
    bool has_data () const { return table.get_length (); }
2358
2359
    void collect_unicodes (hb_set_t *out, unsigned int num_glyphs) const
2360
0
    { subtable->collect_unicodes (out, num_glyphs, get_subtable_data_size (subtable)); }
2361
    void collect_mapping (hb_set_t *unicodes, hb_map_t *mapping,
2362
        unsigned num_glyphs = UINT_MAX) const
2363
0
    { subtable->collect_mapping (unicodes, mapping, num_glyphs, get_subtable_data_size (subtable)); }
2364
    void collect_variation_selectors (hb_set_t *out) const
2365
0
    { subtable_uvs->collect_variation_selectors (out); }
2366
    void collect_variation_unicodes (hb_codepoint_t variation_selector,
2367
             hb_set_t *out) const
2368
0
    { subtable_uvs->collect_variation_unicodes (variation_selector, out); }
2369
2370
    protected:
2371
    typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj,
2372
                hb_codepoint_t codepoint,
2373
                hb_codepoint_t *glyph);
2374
    typedef uint16_t (*hb_pua_remap_func_t) (unsigned);
2375
2376
    template <typename Type>
2377
    HB_INTERNAL static bool get_glyph_from (const void *obj,
2378
              hb_codepoint_t codepoint,
2379
              hb_codepoint_t *glyph)
2380
0
    {
2381
0
      const Type *typed_obj = (const Type *) obj;
2382
0
      return typed_obj->get_glyph (codepoint, glyph);
2383
0
    }
Unexecuted instantiation: bool OT::cmap::accelerator_t::get_glyph_from<OT::CmapSubtableFormat4::accelerator_t>(void const*, unsigned int, unsigned int*)
Unexecuted instantiation: bool OT::cmap::accelerator_t::get_glyph_from<OT::CmapSubtable>(void const*, unsigned int, unsigned int*)
Unexecuted instantiation: bool OT::cmap::accelerator_t::get_glyph_from<OT::CmapSubtableFormat12>(void const*, unsigned int, unsigned int*)
2384
2385
    template <typename Type, hb_pua_remap_func_t remap>
2386
    HB_INTERNAL static bool get_glyph_from_symbol (const void *obj,
2387
               hb_codepoint_t codepoint,
2388
               hb_codepoint_t *glyph)
2389
0
    {
2390
0
      const Type *typed_obj = (const Type *) obj;
2391
0
      if (likely (typed_obj->get_glyph (codepoint, glyph)))
2392
0
  return true;
2393
2394
0
      if (hb_codepoint_t c = remap (codepoint))
2395
0
  return typed_obj->get_glyph (c, glyph);
2396
2397
0
      return false;
2398
0
    }
Unexecuted instantiation: hb-face.cc:bool OT::cmap::accelerator_t::get_glyph_from_symbol<OT::CmapSubtableFormat4::accelerator_t, &OT::_hb_symbol_pua_map>(void const*, unsigned int, unsigned int*)
Unexecuted instantiation: hb-face.cc:bool OT::cmap::accelerator_t::get_glyph_from_symbol<OT::CmapSubtable, &OT::_hb_symbol_pua_map>(void const*, unsigned int, unsigned int*)
Unexecuted instantiation: hb-face.cc:bool OT::cmap::accelerator_t::get_glyph_from_symbol<OT::CmapSubtableFormat4::accelerator_t, &(_hb_arabic_pua_simp_map(unsigned int))>(void const*, unsigned int, unsigned int*)
Unexecuted instantiation: hb-face.cc:bool OT::cmap::accelerator_t::get_glyph_from_symbol<OT::CmapSubtable, &(_hb_arabic_pua_simp_map(unsigned int))>(void const*, unsigned int, unsigned int*)
Unexecuted instantiation: hb-face.cc:bool OT::cmap::accelerator_t::get_glyph_from_symbol<OT::CmapSubtableFormat4::accelerator_t, &(_hb_arabic_pua_trad_map(unsigned int))>(void const*, unsigned int, unsigned int*)
Unexecuted instantiation: hb-face.cc:bool OT::cmap::accelerator_t::get_glyph_from_symbol<OT::CmapSubtable, &(_hb_arabic_pua_trad_map(unsigned int))>(void const*, unsigned int, unsigned int*)
Unexecuted instantiation: hb-ot-face.cc:bool OT::cmap::accelerator_t::get_glyph_from_symbol<OT::CmapSubtableFormat4::accelerator_t, &OT::_hb_symbol_pua_map>(void const*, unsigned int, unsigned int*)
Unexecuted instantiation: hb-ot-face.cc:bool OT::cmap::accelerator_t::get_glyph_from_symbol<OT::CmapSubtable, &OT::_hb_symbol_pua_map>(void const*, unsigned int, unsigned int*)
Unexecuted instantiation: hb-ot-face.cc:bool OT::cmap::accelerator_t::get_glyph_from_symbol<OT::CmapSubtableFormat4::accelerator_t, &(_hb_arabic_pua_simp_map(unsigned int))>(void const*, unsigned int, unsigned int*)
Unexecuted instantiation: hb-ot-face.cc:bool OT::cmap::accelerator_t::get_glyph_from_symbol<OT::CmapSubtable, &(_hb_arabic_pua_simp_map(unsigned int))>(void const*, unsigned int, unsigned int*)
Unexecuted instantiation: hb-ot-face.cc:bool OT::cmap::accelerator_t::get_glyph_from_symbol<OT::CmapSubtableFormat4::accelerator_t, &(_hb_arabic_pua_trad_map(unsigned int))>(void const*, unsigned int, unsigned int*)
Unexecuted instantiation: hb-ot-face.cc:bool OT::cmap::accelerator_t::get_glyph_from_symbol<OT::CmapSubtable, &(_hb_arabic_pua_trad_map(unsigned int))>(void const*, unsigned int, unsigned int*)
Unexecuted instantiation: hb-ot-font.cc:bool OT::cmap::accelerator_t::get_glyph_from_symbol<OT::CmapSubtableFormat4::accelerator_t, &OT::_hb_symbol_pua_map>(void const*, unsigned int, unsigned int*)
Unexecuted instantiation: hb-ot-font.cc:bool OT::cmap::accelerator_t::get_glyph_from_symbol<OT::CmapSubtable, &OT::_hb_symbol_pua_map>(void const*, unsigned int, unsigned int*)
Unexecuted instantiation: hb-ot-font.cc:bool OT::cmap::accelerator_t::get_glyph_from_symbol<OT::CmapSubtableFormat4::accelerator_t, &(_hb_arabic_pua_simp_map(unsigned int))>(void const*, unsigned int, unsigned int*)
Unexecuted instantiation: hb-ot-font.cc:bool OT::cmap::accelerator_t::get_glyph_from_symbol<OT::CmapSubtable, &(_hb_arabic_pua_simp_map(unsigned int))>(void const*, unsigned int, unsigned int*)
Unexecuted instantiation: hb-ot-font.cc:bool OT::cmap::accelerator_t::get_glyph_from_symbol<OT::CmapSubtableFormat4::accelerator_t, &(_hb_arabic_pua_trad_map(unsigned int))>(void const*, unsigned int, unsigned int*)
Unexecuted instantiation: hb-ot-font.cc:bool OT::cmap::accelerator_t::get_glyph_from_symbol<OT::CmapSubtable, &(_hb_arabic_pua_trad_map(unsigned int))>(void const*, unsigned int, unsigned int*)
Unexecuted instantiation: hb-static.cc:bool OT::cmap::accelerator_t::get_glyph_from_symbol<OT::CmapSubtableFormat4::accelerator_t, &OT::_hb_symbol_pua_map>(void const*, unsigned int, unsigned int*)
Unexecuted instantiation: hb-static.cc:bool OT::cmap::accelerator_t::get_glyph_from_symbol<OT::CmapSubtable, &OT::_hb_symbol_pua_map>(void const*, unsigned int, unsigned int*)
Unexecuted instantiation: hb-static.cc:bool OT::cmap::accelerator_t::get_glyph_from_symbol<OT::CmapSubtableFormat4::accelerator_t, &(_hb_arabic_pua_simp_map(unsigned int))>(void const*, unsigned int, unsigned int*)
Unexecuted instantiation: hb-static.cc:bool OT::cmap::accelerator_t::get_glyph_from_symbol<OT::CmapSubtable, &(_hb_arabic_pua_simp_map(unsigned int))>(void const*, unsigned int, unsigned int*)
Unexecuted instantiation: hb-static.cc:bool OT::cmap::accelerator_t::get_glyph_from_symbol<OT::CmapSubtableFormat4::accelerator_t, &(_hb_arabic_pua_trad_map(unsigned int))>(void const*, unsigned int, unsigned int*)
Unexecuted instantiation: hb-static.cc:bool OT::cmap::accelerator_t::get_glyph_from_symbol<OT::CmapSubtable, &(_hb_arabic_pua_trad_map(unsigned int))>(void const*, unsigned int, unsigned int*)
2399
2400
    template <typename Type>
2401
    HB_INTERNAL static bool get_glyph_from_ascii (const void *obj,
2402
              hb_codepoint_t codepoint,
2403
              hb_codepoint_t *glyph)
2404
0
    {
2405
0
      const Type *typed_obj = (const Type *) obj;
2406
0
      return codepoint < 0x80 && typed_obj->get_glyph (codepoint, glyph);
2407
0
    }
Unexecuted instantiation: bool OT::cmap::accelerator_t::get_glyph_from_ascii<OT::CmapSubtableFormat4::accelerator_t>(void const*, unsigned int, unsigned int*)
Unexecuted instantiation: bool OT::cmap::accelerator_t::get_glyph_from_ascii<OT::CmapSubtable>(void const*, unsigned int, unsigned int*)
2408
2409
    template <typename Type>
2410
    HB_INTERNAL static bool get_glyph_from_macroman (const void *obj,
2411
                 hb_codepoint_t codepoint,
2412
                 hb_codepoint_t *glyph)
2413
0
    {
2414
0
      if (get_glyph_from_ascii<Type> (obj, codepoint, glyph))
2415
0
  return true;
2416
2417
0
      const Type *typed_obj = (const Type *) obj;
2418
0
      unsigned c = unicode_to_macroman (codepoint);
2419
0
      return c && typed_obj->get_glyph (c, glyph);
2420
0
    }
Unexecuted instantiation: bool OT::cmap::accelerator_t::get_glyph_from_macroman<OT::CmapSubtableFormat4::accelerator_t>(void const*, unsigned int, unsigned int*)
Unexecuted instantiation: bool OT::cmap::accelerator_t::get_glyph_from_macroman<OT::CmapSubtable>(void const*, unsigned int, unsigned int*)
2421
2422
    unsigned int get_subtable_data_size (const CmapSubtable *subtable) const
2423
0
    {
2424
0
      unsigned int table_length = this->table.get_length ();
2425
0
      uintptr_t table_start = (uintptr_t) (const void *) this->table.get ();
2426
0
      uintptr_t subtable_addr = (uintptr_t) (const void *) subtable;
2427
0
      if (unlikely (subtable_addr < table_start))
2428
0
  return 0;
2429
2430
0
      uintptr_t subtable_offset = subtable_addr - table_start;
2431
0
      if (unlikely (subtable_offset >= table_length))
2432
0
  return 0;
2433
2434
0
      return table_length - (unsigned int) subtable_offset;
2435
0
    }
2436
2437
    private:
2438
    hb_nonnull_ptr_t<const CmapSubtable> subtable;
2439
    hb_nonnull_ptr_t<const CmapSubtable> subtable_uvs;
2440
2441
    hb_cmap_get_glyph_func_t get_glyph_funcZ = nullptr;
2442
    const void *get_glyph_data = nullptr;
2443
2444
    CmapSubtableFormat4::accelerator_t format4_accel;
2445
2446
#ifndef HB_NO_OT_FONT_CMAP_CACHE
2447
    cache_t *cache = nullptr;
2448
#endif
2449
2450
    public:
2451
    hb_blob_ptr_t<cmap> table;
2452
  };
2453
2454
  protected:
2455
2456
  const CmapSubtable *find_subtable (unsigned int platform_id,
2457
             unsigned int encoding_id) const
2458
0
  {
2459
0
    EncodingRecord key;
2460
0
    key.platformID = platform_id;
2461
0
    key.encodingID = encoding_id;
2462
2463
0
    const EncodingRecord &result = encodingRecord.bsearch (key);
2464
0
    if (!result.subtable)
2465
0
      return nullptr;
2466
2467
0
    return &(this+result.subtable);
2468
0
  }
2469
2470
  const CmapSubtable *find_variation_selector_subtable () const
2471
0
  {
2472
0
    const CmapSubtable *format14 = nullptr;
2473
0
    for (const EncodingRecord& record : encodingRecord)
2474
0
    {
2475
0
      if (record.platformID != 0 || record.encodingID != 5)
2476
0
  continue;
2477
2478
0
      const CmapSubtable *subtable = &(this+record.subtable);
2479
#ifndef HB_NO_BEYOND_64K
2480
      if (subtable->u.format.v == 15)
2481
  return subtable;
2482
#endif
2483
0
      if (subtable->u.format.v == 14)
2484
0
  format14 = subtable;
2485
0
    }
2486
0
    return format14;
2487
0
  }
2488
2489
  public:
2490
2491
  bool sanitize (hb_sanitize_context_t *c) const
2492
0
  {
2493
0
    TRACE_SANITIZE (this);
2494
0
    return_trace (c->check_struct (this) &&
2495
0
      hb_barrier () &&
2496
0
      likely (version == 0) &&
2497
0
      encodingRecord.sanitize (c, this));
2498
0
  }
2499
2500
 private:
2501
2502
  static bool filter_encoding_records_for_subset(const cmap* cmap,
2503
                                                 const EncodingRecord& _)
2504
0
  {
2505
0
    return
2506
0
        (_.platformID == 0 && _.encodingID == 3) ||
2507
0
        (_.platformID == 0 && _.encodingID == 4) ||
2508
0
        (_.platformID == 3 && _.encodingID == 1) ||
2509
0
        (_.platformID == 3 && _.encodingID == 10) ||
2510
0
        (cmap + _.subtable).is_variation_selector ();
2511
0
  }
2512
2513
  protected:
2514
  HBUINT16  version;  /* Table version number (0). */
2515
  SortedArray16Of<EncodingRecord>
2516
    encodingRecord; /* Encoding tables. */
2517
  public:
2518
  DEFINE_SIZE_ARRAY (4, encodingRecord);
2519
};
2520
2521
struct DMAP : cmap
2522
{
2523
  static constexpr hb_tag_t tableTag = HB_OT_TAG_DMAP;
2524
2525
  bool subset (hb_subset_context_t *c) const
2526
0
  { return cmap::subset (c, true); }
2527
};
2528
2529
struct cmap_accelerator_t
2530
{
2531
  cmap_accelerator_t (hb_face_t *face) :
2532
0
    dmap (face, HB_OT_TAG_DMAP),
2533
0
    base (face)
2534
0
  {}
2535
2536
  bool get_nominal_glyph (hb_codepoint_t  unicode,
2537
        hb_codepoint_t *glyph) const
2538
0
  {
2539
0
    return dmap.get_nominal_glyph (unicode, glyph) ||
2540
0
     base.get_nominal_glyph (unicode, glyph);
2541
0
  }
2542
2543
  unsigned int get_nominal_glyphs (unsigned int count,
2544
           const hb_codepoint_t *first_unicode,
2545
           unsigned int unicode_stride,
2546
           hb_codepoint_t *first_glyph,
2547
           unsigned int glyph_stride) const
2548
0
  {
2549
0
    if (likely (!dmap.has_data ()))
2550
0
      return base.get_nominal_glyphs (count,
2551
0
              first_unicode, unicode_stride,
2552
0
              first_glyph, glyph_stride);
2553
2554
0
    unsigned int done;
2555
0
    for (done = 0;
2556
0
   done < count && get_nominal_glyph (*first_unicode, first_glyph);
2557
0
   done++)
2558
0
    {
2559
0
      first_unicode = &StructAtOffsetUnaligned<hb_codepoint_t> (first_unicode, unicode_stride);
2560
0
      first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
2561
0
    }
2562
0
    return done;
2563
0
  }
2564
2565
  bool get_variation_glyph (hb_codepoint_t  unicode,
2566
          hb_codepoint_t  variation_selector,
2567
          hb_codepoint_t *glyph) const
2568
0
  {
2569
0
    glyph_variant_t result = dmap.get_glyph_variant (unicode,
2570
0
                 variation_selector,
2571
0
                 glyph);
2572
0
    if (result == GLYPH_VARIANT_NOT_FOUND)
2573
0
      result = base.get_glyph_variant (unicode, variation_selector, glyph);
2574
2575
0
    switch (result)
2576
0
    {
2577
0
      case GLYPH_VARIANT_NOT_FOUND: return false;
2578
0
      case GLYPH_VARIANT_FOUND: return true;
2579
0
      case GLYPH_VARIANT_USE_DEFAULT: break;
2580
0
    }
2581
2582
0
    return get_nominal_glyph (unicode, glyph);
2583
0
  }
2584
2585
  void collect_unicodes (hb_set_t *out, unsigned int num_glyphs) const
2586
0
  {
2587
0
    base.collect_unicodes (out, num_glyphs);
2588
0
    dmap.collect_unicodes (out, num_glyphs);
2589
0
  }
2590
2591
  void collect_mapping (hb_set_t *unicodes, hb_map_t *mapping,
2592
      unsigned num_glyphs = UINT_MAX) const
2593
0
  {
2594
0
    base.collect_mapping (unicodes, mapping, num_glyphs);
2595
0
    dmap.collect_mapping (unicodes, mapping, num_glyphs);
2596
0
  }
2597
2598
  void collect_variation_selectors (hb_set_t *out) const
2599
0
  {
2600
0
    base.collect_variation_selectors (out);
2601
0
    dmap.collect_variation_selectors (out);
2602
0
  }
2603
2604
  void collect_variation_unicodes (hb_codepoint_t variation_selector,
2605
           hb_set_t *out) const
2606
0
  {
2607
0
    base.collect_variation_unicodes (variation_selector, out);
2608
0
    dmap.collect_variation_unicodes (variation_selector, out);
2609
0
  }
2610
2611
  void closure_glyphs (const hb_set_t *unicodes,
2612
           hb_set_t       *glyphset) const
2613
0
  {
2614
0
    if (likely (!dmap.has_data ()))
2615
0
    {
2616
0
      base.table->closure_glyphs (unicodes, glyphset);
2617
0
      return;
2618
0
    }
2619
0
2620
0
    hb_set_t variation_selectors;
2621
0
    collect_variation_selectors (&variation_selectors);
2622
0
    for (hb_codepoint_t variation_selector : variation_selectors)
2623
0
    {
2624
0
      if (!unicodes->has (variation_selector))
2625
0
  continue;
2626
0
2627
0
      hb_set_t variation_unicodes;
2628
0
      collect_variation_unicodes (variation_selector, &variation_unicodes);
2629
0
      for (hb_codepoint_t unicode : variation_unicodes)
2630
0
      {
2631
0
  if (!unicodes->has (unicode))
2632
0
    continue;
2633
0
2634
0
  hb_codepoint_t glyph;
2635
0
  if (get_variation_glyph (unicode, variation_selector, &glyph))
2636
0
    glyphset->add (glyph);
2637
0
      }
2638
0
    }
2639
0
  }
2640
2641
  cmap::accelerator_t dmap;
2642
  cmap::accelerator_t base;
2643
};
2644
2645
} /* namespace OT */
2646
2647
2648
#endif /* HB_OT_CMAP_TABLE_HH */