Coverage Report

Created: 2025-12-31 07:23

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pango/subprojects/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-set.hh"
34
#include "hb-cache.hh"
35
36
/*
37
 * cmap -- Character to Glyph Index Mapping
38
 * https://docs.microsoft.com/en-us/typography/opentype/spec/cmap
39
 */
40
#define HB_OT_TAG_cmap HB_TAG('c','m','a','p')
41
42
namespace OT {
43
44
static inline uint8_t unicode_to_macroman (hb_codepoint_t u)
45
0
{
46
0
  uint16_t mapping[] = {
47
0
    0x00C4, 0x00C5, 0x00C7, 0x00C9, 0x00D1, 0x00D6, 0x00DC, 0x00E1,
48
0
    0x00E0, 0x00E2, 0x00E4, 0x00E3, 0x00E5, 0x00E7, 0x00E9, 0x00E8,
49
0
    0x00EA, 0x00EB, 0x00ED, 0x00EC, 0x00EE, 0x00EF, 0x00F1, 0x00F3,
50
0
    0x00F2, 0x00F4, 0x00F6, 0x00F5, 0x00FA, 0x00F9, 0x00FB, 0x00FC,
51
0
    0x2020, 0x00B0, 0x00A2, 0x00A3, 0x00A7, 0x2022, 0x00B6, 0x00DF,
52
0
    0x00AE, 0x00A9, 0x2122, 0x00B4, 0x00A8, 0x2260, 0x00C6, 0x00D8,
53
0
    0x221E, 0x00B1, 0x2264, 0x2265, 0x00A5, 0x00B5, 0x2202, 0x2211,
54
0
    0x220F, 0x03C0, 0x222B, 0x00AA, 0x00BA, 0x03A9, 0x00E6, 0x00F8,
55
0
    0x00BF, 0x00A1, 0x00AC, 0x221A, 0x0192, 0x2248, 0x2206, 0x00AB,
56
0
    0x00BB, 0x2026, 0x00A0, 0x00C0, 0x00C3, 0x00D5, 0x0152, 0x0153,
57
0
    0x2013, 0x2014, 0x201C, 0x201D, 0x2018, 0x2019, 0x00F7, 0x25CA,
58
0
    0x00FF, 0x0178, 0x2044, 0x20AC, 0x2039, 0x203A, 0xFB01, 0xFB02,
59
0
    0x2021, 0x00B7, 0x201A, 0x201E, 0x2030, 0x00C2, 0x00CA, 0x00C1,
60
0
    0x00CB, 0x00C8, 0x00CD, 0x00CE, 0x00CF, 0x00CC, 0x00D3, 0x00D4,
61
0
    0xF8FF, 0x00D2, 0x00DA, 0x00DB, 0x00D9, 0x0131, 0x02C6, 0x02DC,
62
0
    0x00AF, 0x02D8, 0x02D9, 0x02DA, 0x00B8, 0x02DD, 0x02DB, 0x02C7
63
0
  };
64
0
  uint16_t *c = hb_bsearch (u, mapping, ARRAY_LENGTH (mapping), sizeof (mapping[0]),
65
0
          _hb_cmp_operator<uint16_t, uint16_t>);
66
0
  return c ? (c - mapping) + 0x7F : 0;
67
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)
68
69
struct CmapSubtableFormat0
70
{
71
  bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
72
0
  {
73
0
    hb_codepoint_t gid = codepoint < 256 ? glyphIdArray[codepoint] : 0;
74
0
    if (unlikely (!gid))
75
0
      return false;
76
0
    *glyph = gid;
77
0
    return true;
78
0
  }
79
80
  unsigned get_language () const
81
0
  {
82
0
    return language;
83
0
  }
84
85
  void collect_unicodes (hb_set_t *out) const
86
0
  {
87
0
    for (unsigned int i = 0; i < 256; i++)
88
0
      if (glyphIdArray[i])
89
0
  out->add (i);
90
0
  }
91
92
  void collect_mapping (hb_set_t *unicodes, /* OUT */
93
      hb_map_t *mapping /* OUT */) const
94
0
  {
95
0
    for (unsigned i = 0; i < 256; i++)
96
0
      if (glyphIdArray[i])
97
0
      {
98
0
  hb_codepoint_t glyph = glyphIdArray[i];
99
0
  unicodes->add (i);
100
0
  mapping->set (i, glyph);
101
0
      }
102
0
  }
103
104
  bool sanitize (hb_sanitize_context_t *c) const
105
0
  {
106
0
    TRACE_SANITIZE (this);
107
0
    return_trace (c->check_struct (this));
108
0
  }
109
110
  protected:
111
  HBUINT16  format;   /* Format number is set to 0. */
112
  HBUINT16  length;   /* Byte length of this subtable. */
113
  HBUINT16  language; /* Ignore. */
114
  HBUINT8 glyphIdArray[256];/* An array that maps character
115
         * code to glyph index values. */
116
  public:
117
  DEFINE_SIZE_STATIC (6 + 256);
118
};
119
120
struct CmapSubtableFormat4
121
{
122
123
124
  template<typename Iterator,
125
      typename Writer,
126
     hb_requires (hb_is_iterator (Iterator))>
127
  void to_ranges (Iterator it, Writer& range_writer)
128
0
  {
129
0
    hb_codepoint_t start_cp = 0, prev_run_start_cp = 0, run_start_cp = 0, end_cp = 0, last_gid = 0;
130
0
    int run_length = 0 , delta = 0, prev_delta = 0;
131
0
132
0
    enum {
133
0
      FIRST_SUB_RANGE,
134
0
      FOLLOWING_SUB_RANGE,
135
0
    } mode;
136
0
137
0
    while (it) {
138
0
      // Start a new range
139
0
      {
140
0
        const auto& pair = *it;
141
0
        start_cp = pair.first;
142
0
        prev_run_start_cp = start_cp;
143
0
        run_start_cp = start_cp;
144
0
        end_cp = start_cp;
145
0
        last_gid = pair.second;
146
0
        run_length = 1;
147
0
        prev_delta = 0;
148
0
      }
149
0
150
0
      delta = last_gid - start_cp;
151
0
      mode = FIRST_SUB_RANGE;
152
0
      it++;
153
0
154
0
      while (it) {
155
0
        // Process range
156
0
        const auto& pair = *it;
157
0
        hb_codepoint_t next_cp = pair.first;
158
0
        hb_codepoint_t next_gid = pair.second;
159
0
        if (next_cp != end_cp + 1) {
160
0
          // Current range is over, stop processing.
161
0
          break;
162
0
        }
163
0
164
0
        if (next_gid == last_gid + 1) {
165
0
          // The current run continues.
166
0
          end_cp = next_cp;
167
0
          run_length++;
168
0
          last_gid = next_gid;
169
0
          it++;
170
0
          continue;
171
0
        }
172
0
173
0
        // A new run is starting, decide if we want to commit the current run.
174
0
        int split_cost = (mode == FIRST_SUB_RANGE) ? 8 : 16;
175
0
        int run_cost = run_length * 2;
176
0
        if (run_cost >= split_cost) {
177
0
          commit_current_range(start_cp,
178
0
                               prev_run_start_cp,
179
0
                               run_start_cp,
180
0
                               end_cp,
181
0
                               delta,
182
0
                               prev_delta,
183
0
                               split_cost,
184
0
                               range_writer);
185
0
          start_cp = next_cp;
186
0
        }
187
0
188
0
        // Start the new run
189
0
        mode = FOLLOWING_SUB_RANGE;
190
0
        prev_run_start_cp = run_start_cp;
191
0
        run_start_cp = next_cp;
192
0
        end_cp = next_cp;
193
0
        prev_delta = delta;
194
0
        delta = next_gid - run_start_cp;
195
0
        run_length = 1;
196
0
        last_gid = next_gid;
197
0
        it++;
198
0
      }
199
0
200
0
      // Finalize range
201
0
      commit_current_range (start_cp,
202
0
                            prev_run_start_cp,
203
0
                            run_start_cp,
204
0
                            end_cp,
205
0
                            delta,
206
0
                            prev_delta,
207
0
                            8,
208
0
                            range_writer);
209
0
    }
210
0
211
0
    if (likely (end_cp != 0xFFFF)) {
212
0
      range_writer (0xFFFF, 0xFFFF, 1);
213
0
    }
214
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_
215
216
  /*
217
   * Writes the current range as either one or two ranges depending on what is most efficient.
218
   */
219
  template<typename Writer>
220
  void commit_current_range (hb_codepoint_t start,
221
                             hb_codepoint_t prev_run_start,
222
                             hb_codepoint_t run_start,
223
                             hb_codepoint_t end,
224
                             int run_delta,
225
                             int previous_run_delta,
226
                             int split_cost,
227
0
                             Writer& range_writer) {
228
0
    bool should_split = false;
229
0
    if (start < run_start && run_start < end) {
230
0
      int run_cost = (end - run_start + 1) * 2;
231
0
      if (run_cost >= split_cost) {
232
0
        should_split = true;
233
0
      }
234
0
    }
235
0
236
0
    // TODO(grieger): handle case where delta is legitimately 0, mark range offset array instead?
237
0
    if (should_split) {
238
0
      if (start == prev_run_start)
239
0
        range_writer (start, run_start - 1, previous_run_delta);
240
0
      else
241
0
        range_writer (start, run_start - 1, 0);
242
0
      range_writer (run_start, end, run_delta);
243
0
      return;
244
0
    }
245
0
246
0
247
0
    if (start == run_start) {
248
0
      // Range is only a run
249
0
      range_writer (start, end, run_delta);
250
0
      return;
251
0
    }
252
0
253
0
    // Write only a single non-run range.
254
0
    range_writer (start, end, 0);
255
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_
256
257
  template<typename Iterator,
258
     hb_requires (hb_is_iterator (Iterator))>
259
0
  unsigned serialize_find_segcount (Iterator it) {
260
0
    struct Counter {
261
0
      unsigned segcount = 0;
262
0
263
0
      void operator() (hb_codepoint_t start,
264
0
                       hb_codepoint_t end,
265
0
                       int delta) {
266
0
        segcount++;
267
0
      }
268
0
    } counter;
269
0
270
0
    to_ranges (+it, counter);
271
0
    return counter.segcount;
272
0
  }
273
274
275
  template<typename Iterator,
276
     hb_requires (hb_is_iterator (Iterator))>
277
  bool serialize_start_end_delta_arrays (hb_serialize_context_t *c,
278
                                         Iterator it,
279
                                         int segcount)
280
0
  {
281
0
    struct Writer {
282
0
      hb_serialize_context_t *serializer_;
283
0
      HBUINT16* end_code_;
284
0
      HBUINT16* start_code_;
285
0
      HBINT16* id_delta_;
286
0
      int index_;
287
0
288
0
      Writer(hb_serialize_context_t *serializer)
289
0
          : serializer_(serializer),
290
0
            end_code_(nullptr),
291
0
            start_code_(nullptr),
292
0
            id_delta_(nullptr),
293
0
            index_ (0) {}
294
0
      void operator() (hb_codepoint_t start,
295
0
                       hb_codepoint_t end,
296
0
                       int delta) {
297
0
        start_code_[index_] = start;
298
0
        end_code_[index_] = end;
299
0
        id_delta_[index_] = delta;
300
0
        index_++;
301
0
      }
302
0
    } writer(c);
303
0
304
0
    writer.end_code_ = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount, false);
305
0
    (void) c->allocate_size<HBUINT16> (2); // padding
306
0
    writer.start_code_ = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount, false);
307
0
    writer.id_delta_ = c->allocate_size<HBINT16> (HBINT16::static_size * segcount, false);
308
0
309
0
    if (unlikely (!writer.end_code_ || !writer.start_code_ || !writer.id_delta_)) return false;
310
0
311
0
    to_ranges (+it, writer);
312
0
    return true;
313
0
  }
314
315
  template<typename Iterator,
316
          hb_requires (hb_is_iterator (Iterator))>
317
  HBUINT16* serialize_rangeoffset_glyid (hb_serialize_context_t *c,
318
                                         Iterator it,
319
           HBUINT16 *endCode,
320
           HBUINT16 *startCode,
321
           HBINT16 *idDelta,
322
           unsigned segcount)
323
0
  {
324
0
    hb_map_t cp_to_gid { it };
325
0
326
0
    HBUINT16 *idRangeOffset = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount);
327
0
    if (unlikely (!c->check_success (idRangeOffset))) return nullptr;
328
0
    if (unlikely ((char *)idRangeOffset - (char *)idDelta != (int) segcount * (int) HBINT16::static_size)) return nullptr;
329
0
330
0
    for (unsigned i : + hb_range (segcount)
331
0
          | hb_filter ([&] (const unsigned _) { return idDelta[_] == 0; }))
332
0
    {
333
0
      idRangeOffset[i] = 2 * (c->start_embed<HBUINT16> () - idRangeOffset - i);
334
0
      for (hb_codepoint_t cp = startCode[i]; cp <= endCode[i]; cp++)
335
0
      {
336
0
        HBUINT16 gid;
337
0
        gid = cp_to_gid[cp];
338
0
        c->copy<HBUINT16> (gid);
339
0
      }
340
0
    }
341
0
342
0
    return idRangeOffset;
343
0
  }
344
345
  template<typename Iterator,
346
     hb_requires (hb_is_iterator (Iterator))>
347
  void serialize (hb_serialize_context_t *c,
348
      Iterator it)
349
0
  {
350
0
    auto format4_iter =
351
0
    + it
352
0
    | hb_filter ([&] (const hb_codepoint_pair_t _)
353
0
     { return _.first <= 0xFFFF; })
354
0
    ;
355
0
356
0
    if (!format4_iter) return;
357
0
358
0
    unsigned table_initpos = c->length ();
359
0
    if (unlikely (!c->extend_min (this))) return;
360
0
    this->format = 4;
361
0
362
0
    hb_vector_t<hb_codepoint_pair_t> cp_to_gid {
363
0
      format4_iter
364
0
    };
365
0
366
0
    //serialize endCode[], startCode[], idDelta[]
367
0
    HBUINT16* endCode = c->start_embed<HBUINT16> ();
368
0
    unsigned segcount = serialize_find_segcount (cp_to_gid.iter());
369
0
    if (unlikely (!serialize_start_end_delta_arrays (c, cp_to_gid.iter(), segcount)))
370
0
      return;
371
0
372
0
    HBUINT16 *startCode = endCode + segcount + 1;
373
0
    HBINT16 *idDelta = ((HBINT16*)startCode) + segcount;
374
0
375
0
    HBUINT16 *idRangeOffset = serialize_rangeoffset_glyid (c,
376
0
                                                           cp_to_gid.iter (),
377
0
                                                           endCode,
378
0
                                                           startCode,
379
0
                                                           idDelta,
380
0
                                                           segcount);
381
0
    if (unlikely (!c->check_success (idRangeOffset))) return;
382
0
383
0
    this->length = c->length () - table_initpos;
384
0
    if ((long long) this->length != (long long) c->length () - table_initpos)
385
0
    {
386
0
      // Length overflowed. Discard the current object before setting the error condition, otherwise
387
0
      // discard is a noop which prevents the higher level code from reverting the serializer to the
388
0
      // pre-error state in cmap4 overflow handling code.
389
0
      c->pop_discard ();
390
0
      c->err (HB_SERIALIZE_ERROR_INT_OVERFLOW);
391
0
      return;
392
0
    }
393
0
394
0
    this->segCountX2 = segcount * 2;
395
0
    this->entrySelector = hb_max (1u, hb_bit_storage (segcount)) - 1;
396
0
    this->searchRange = 2 * (1u << this->entrySelector);
397
0
    this->rangeShift = segcount * 2 > this->searchRange
398
0
           ? 2 * segcount - this->searchRange
399
0
           : 0;
400
0
  }
Unexecuted instantiation: hb-face.cc:_ZN2OT19CmapSubtableFormat49serializeI16hb_filter_iter_tIS2_I17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS_4cmap6subsetEP19hb_subset_context_tEUlS5_E_RK4$_10LPv0EERK8hb_set_tRK3$_5LSF_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_tEUlS5_E_RK4$_10LPv0EETnPN12hb_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_tEUlS5_E_RK4$_11LPv0EERK8hb_set_tRK3$_5LSF_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_tEUlS5_E_RK4$_11LPv0EETnPN12hb_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_tEUlS5_E_RK4$_10LPv0EERK8hb_set_tRK3$_5LSF_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_tEUlS5_E_RK4$_10LPv0EETnPN12hb_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_tEUlS5_E_RK4$_10LPv0EERK8hb_set_tRK3$_5LSF_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_tEUlS5_E_RK4$_10LPv0EETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NSI_6item_tEEE5valueEvE4typeELSF_0EEEvP22hb_serialize_context_tSI_
401
402
  unsigned get_language () const
403
0
  {
404
0
    return language;
405
0
  }
406
407
  struct accelerator_t
408
  {
409
0
    accelerator_t () {}
410
0
    accelerator_t (const CmapSubtableFormat4 *subtable) { init (subtable); }
411
412
    void init (const CmapSubtableFormat4 *subtable)
413
0
    {
414
0
      segCount = subtable->segCountX2 / 2;
415
0
      endCount = subtable->values.arrayZ;
416
0
      startCount = endCount + segCount + 1;
417
0
      idDelta = startCount + segCount;
418
0
      idRangeOffset = idDelta + segCount;
419
0
      glyphIdArray = idRangeOffset + segCount;
420
0
      glyphIdArrayLength = (subtable->length - 16 - 8 * segCount) / 2;
421
0
    }
422
423
    bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
424
0
    {
425
0
      struct CustomRange
426
0
      {
427
0
  int cmp (hb_codepoint_t k,
428
0
     unsigned distance) const
429
0
  {
430
0
    if (k > last) return +1;
431
0
    if (k < (&last)[distance]/*first*/) return -1;
432
0
    return 0;
433
0
  }
434
0
  HBUINT16 last;
435
0
      };
436
437
0
      const HBUINT16 *found = hb_bsearch (codepoint,
438
0
            this->endCount,
439
0
            this->segCount,
440
0
            sizeof (CustomRange),
441
0
            _hb_cmp_method<hb_codepoint_t, CustomRange, unsigned>,
442
0
            this->segCount + 1);
443
0
      if (unlikely (!found))
444
0
  return false;
445
0
      unsigned int i = found - endCount;
446
447
0
      hb_codepoint_t gid;
448
0
      unsigned int rangeOffset = this->idRangeOffset[i];
449
0
      if (rangeOffset == 0)
450
0
  gid = codepoint + this->idDelta[i];
451
0
      else
452
0
      {
453
  /* Somebody has been smoking... */
454
0
  unsigned int index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount;
455
0
  if (unlikely (index >= this->glyphIdArrayLength))
456
0
    return false;
457
0
  gid = this->glyphIdArray[index];
458
0
  if (unlikely (!gid))
459
0
    return false;
460
0
  gid += this->idDelta[i];
461
0
      }
462
0
      gid &= 0xFFFFu;
463
0
      if (unlikely (!gid))
464
0
  return false;
465
0
      *glyph = gid;
466
0
      return true;
467
0
    }
468
469
    HB_INTERNAL static bool get_glyph_func (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph)
470
0
    { return ((const accelerator_t *) obj)->get_glyph (codepoint, glyph); }
471
472
    void collect_unicodes (hb_set_t *out) const
473
0
    {
474
0
      unsigned int count = this->segCount;
475
0
      if (count && this->startCount[count - 1] == 0xFFFFu)
476
0
  count--; /* Skip sentinel segment. */
477
0
      for (unsigned int i = 0; i < count; i++)
478
0
      {
479
0
  hb_codepoint_t start = this->startCount[i];
480
0
  hb_codepoint_t end = this->endCount[i];
481
0
  unsigned int rangeOffset = this->idRangeOffset[i];
482
0
        out->add_range(start, end);
483
0
  if (rangeOffset == 0)
484
0
  {
485
0
    for (hb_codepoint_t codepoint = start; codepoint <= end; codepoint++)
486
0
    {
487
0
      hb_codepoint_t gid = (codepoint + this->idDelta[i]) & 0xFFFFu;
488
0
      if (unlikely (!gid))
489
0
              out->del(codepoint);
490
0
    }
491
0
  }
492
0
  else
493
0
  {
494
0
    for (hb_codepoint_t codepoint = start; codepoint <= end; codepoint++)
495
0
    {
496
0
      unsigned int index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount;
497
0
      if (unlikely (index >= this->glyphIdArrayLength))
498
0
            {
499
0
              out->del_range (codepoint, end);
500
0
        break;
501
0
            }
502
0
      hb_codepoint_t gid = this->glyphIdArray[index];
503
0
      if (unlikely (!gid))
504
0
              out->del(codepoint);
505
0
    }
506
0
  }
507
0
      }
508
0
    }
509
510
    void collect_mapping (hb_set_t *unicodes, /* OUT */
511
        hb_map_t *mapping /* OUT */) const
512
0
    {
513
      // TODO(grieger): optimize similar to collect_unicodes
514
      // (ie. use add_range())
515
0
      unsigned count = this->segCount;
516
0
      if (count && this->startCount[count - 1] == 0xFFFFu)
517
0
  count--; /* Skip sentinel segment. */
518
0
      for (unsigned i = 0; i < count; i++)
519
0
      {
520
0
  hb_codepoint_t start = this->startCount[i];
521
0
  hb_codepoint_t end = this->endCount[i];
522
0
  unsigned rangeOffset = this->idRangeOffset[i];
523
0
  if (rangeOffset == 0)
524
0
  {
525
0
    for (hb_codepoint_t codepoint = start; codepoint <= end; codepoint++)
526
0
    {
527
0
      hb_codepoint_t gid = (codepoint + this->idDelta[i]) & 0xFFFFu;
528
0
      if (unlikely (!gid))
529
0
        continue;
530
0
      unicodes->add (codepoint);
531
0
      mapping->set (codepoint, gid);
532
0
    }
533
0
  }
534
0
  else
535
0
  {
536
0
    for (hb_codepoint_t codepoint = start; codepoint <= end; codepoint++)
537
0
    {
538
0
      unsigned index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount;
539
0
      if (unlikely (index >= this->glyphIdArrayLength))
540
0
        break;
541
0
      hb_codepoint_t gid = this->glyphIdArray[index];
542
0
      if (unlikely (!gid))
543
0
        continue;
544
0
      unicodes->add (codepoint);
545
0
      mapping->set (codepoint, gid);
546
0
    }
547
0
  }
548
0
      }
549
0
    }
550
551
    const HBUINT16 *endCount;
552
    const HBUINT16 *startCount;
553
    const HBUINT16 *idDelta;
554
    const HBUINT16 *idRangeOffset;
555
    const HBUINT16 *glyphIdArray;
556
    unsigned int segCount;
557
    unsigned int glyphIdArrayLength;
558
  };
559
560
  bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
561
0
  {
562
0
    accelerator_t accel (this);
563
0
    return accel.get_glyph_func (&accel, codepoint, glyph);
564
0
  }
565
  void collect_unicodes (hb_set_t *out) const
566
0
  {
567
0
    accelerator_t accel (this);
568
0
    accel.collect_unicodes (out);
569
0
  }
570
571
  void collect_mapping (hb_set_t *unicodes, /* OUT */
572
      hb_map_t *mapping /* OUT */) const
573
0
  {
574
0
    accelerator_t accel (this);
575
0
    accel.collect_mapping (unicodes, mapping);
576
0
  }
577
578
  bool sanitize (hb_sanitize_context_t *c) const
579
0
  {
580
0
    TRACE_SANITIZE (this);
581
0
    if (unlikely (!c->check_struct (this)))
582
0
      return_trace (false);
583
0
    hb_barrier ();
584
585
0
    if (unlikely (!c->check_range (this, length)))
586
0
    {
587
      /* Some broken fonts have too long of a "length" value.
588
       * If that is the case, just change the value to truncate
589
       * the subtable at the end of the blob. */
590
0
      uint16_t new_length = (uint16_t) hb_min ((uintptr_t) 65535,
591
0
                 (uintptr_t) (c->end -
592
0
                  (char *) this));
593
0
      if (!c->try_set (&length, new_length))
594
0
  return_trace (false);
595
0
    }
596
597
0
    return_trace (16 + 4 * (unsigned int) segCountX2 <= length);
598
0
  }
599
600
601
602
  protected:
603
  HBUINT16  format;   /* Format number is set to 4. */
604
  HBUINT16  length;   /* This is the length in bytes of the
605
         * subtable. */
606
  HBUINT16  language; /* Ignore. */
607
  HBUINT16  segCountX2; /* 2 x segCount. */
608
  HBUINT16  searchRange;  /* 2 * (2**floor(log2(segCount))) */
609
  HBUINT16  entrySelector;  /* log2(searchRange/2) */
610
  HBUINT16  rangeShift; /* 2 x segCount - searchRange */
611
612
  UnsizedArrayOf<HBUINT16>
613
    values;
614
#if 0
615
  HBUINT16  endCount[segCount]; /* End characterCode for each segment,
616
           * last=0xFFFFu. */
617
  HBUINT16  reservedPad;    /* Set to 0. */
618
  HBUINT16  startCount[segCount]; /* Start character code for each segment. */
619
  HBINT16   idDelta[segCount];  /* Delta for all character codes in segment. */
620
  HBUINT16  idRangeOffset[segCount];/* Offsets into glyphIdArray or 0 */
621
  UnsizedArrayOf<HBUINT16>
622
    glyphIdArray; /* Glyph index array (arbitrary length) */
623
#endif
624
625
  public:
626
  DEFINE_SIZE_ARRAY (14, values);
627
};
628
629
struct CmapSubtableLongGroup
630
{
631
  friend struct CmapSubtableFormat12;
632
  friend struct CmapSubtableFormat13;
633
  template<typename U>
634
  friend struct CmapSubtableLongSegmented;
635
  friend struct cmap;
636
637
  int cmp (hb_codepoint_t codepoint) const
638
0
  {
639
0
    if (codepoint < startCharCode) return -1;
640
0
    if (codepoint > endCharCode)   return +1;
641
0
    return 0;
642
0
  }
643
644
  bool sanitize (hb_sanitize_context_t *c) const
645
0
  {
646
0
    TRACE_SANITIZE (this);
647
0
    return_trace (c->check_struct (this));
648
0
  }
649
650
  private:
651
  HBUINT32    startCharCode;  /* First character code in this group. */
652
  HBUINT32    endCharCode;  /* Last character code in this group. */
653
  HBUINT32    glyphID;  /* Glyph index; interpretation depends on
654
           * subtable format. */
655
  public:
656
  DEFINE_SIZE_STATIC (12);
657
};
658
DECLARE_NULL_NAMESPACE_BYTES (OT, CmapSubtableLongGroup);
659
660
template <typename UINT>
661
struct CmapSubtableTrimmed
662
{
663
  bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
664
0
  {
665
    /* Rely on our implicit array bound-checking. */
666
0
    hb_codepoint_t gid = glyphIdArray[codepoint - startCharCode];
667
0
    if (unlikely (!gid))
668
0
      return false;
669
0
    *glyph = gid;
670
0
    return true;
671
0
  }
Unexecuted instantiation: OT::CmapSubtableTrimmed<OT::IntType<unsigned short, 2u> >::get_glyph(unsigned int, unsigned int*) const
Unexecuted instantiation: OT::CmapSubtableTrimmed<OT::IntType<unsigned int, 4u> >::get_glyph(unsigned int, unsigned int*) const
672
673
  unsigned get_language () const
674
0
  {
675
0
    return language;
676
0
  }
Unexecuted instantiation: OT::CmapSubtableTrimmed<OT::IntType<unsigned short, 2u> >::get_language() const
Unexecuted instantiation: OT::CmapSubtableTrimmed<OT::IntType<unsigned int, 4u> >::get_language() const
677
678
  void collect_unicodes (hb_set_t *out) const
679
0
  {
680
0
    hb_codepoint_t start = startCharCode;
681
0
    unsigned int count = glyphIdArray.len;
682
0
    for (unsigned int i = 0; i < count; i++)
683
0
      if (glyphIdArray[i])
684
0
  out->add (start + i);
685
0
  }
Unexecuted instantiation: OT::CmapSubtableTrimmed<OT::IntType<unsigned short, 2u> >::collect_unicodes(hb_set_t*) const
Unexecuted instantiation: OT::CmapSubtableTrimmed<OT::IntType<unsigned int, 4u> >::collect_unicodes(hb_set_t*) const
686
687
  void collect_mapping (hb_set_t *unicodes, /* OUT */
688
      hb_map_t *mapping /* OUT */) const
689
0
  {
690
0
    hb_codepoint_t start_cp = startCharCode;
691
0
    unsigned count = glyphIdArray.len;
692
0
    for (unsigned i = 0; i < count; i++)
693
0
      if (glyphIdArray[i])
694
0
      {
695
0
  hb_codepoint_t unicode = start_cp + i;
696
0
  hb_codepoint_t glyphid = glyphIdArray[i];
697
0
  unicodes->add (unicode);
698
0
  mapping->set (unicode, glyphid);
699
0
      }
700
0
  }
Unexecuted instantiation: OT::CmapSubtableTrimmed<OT::IntType<unsigned short, 2u> >::collect_mapping(hb_set_t*, hb_map_t*) const
Unexecuted instantiation: OT::CmapSubtableTrimmed<OT::IntType<unsigned int, 4u> >::collect_mapping(hb_set_t*, hb_map_t*) const
701
702
  bool sanitize (hb_sanitize_context_t *c) const
703
0
  {
704
0
    TRACE_SANITIZE (this);
705
0
    return_trace (c->check_struct (this) && glyphIdArray.sanitize (c));
706
0
  }
Unexecuted instantiation: OT::CmapSubtableTrimmed<OT::IntType<unsigned short, 2u> >::sanitize(hb_sanitize_context_t*) const
Unexecuted instantiation: OT::CmapSubtableTrimmed<OT::IntType<unsigned int, 4u> >::sanitize(hb_sanitize_context_t*) const
707
708
  protected:
709
  UINT    formatReserved; /* Subtable format and (maybe) padding. */
710
  UINT    length;   /* Byte length of this subtable. */
711
  UINT    language; /* Ignore. */
712
  UINT    startCharCode;  /* First character code covered. */
713
  ArrayOf<HBGlyphID16, UINT>
714
    glyphIdArray; /* Array of glyph index values for character
715
         * codes in the range. */
716
  public:
717
  DEFINE_SIZE_ARRAY (5 * sizeof (UINT), glyphIdArray);
718
};
719
720
struct CmapSubtableFormat6  : CmapSubtableTrimmed<HBUINT16> {};
721
struct CmapSubtableFormat10 : CmapSubtableTrimmed<HBUINT32> {};
722
723
template <typename T>
724
struct CmapSubtableLongSegmented
725
{
726
  friend struct cmap;
727
728
  bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
729
0
  {
730
0
    hb_codepoint_t gid = T::group_get_glyph (groups.bsearch (codepoint), codepoint);
731
0
    if (unlikely (!gid))
732
0
      return false;
733
0
    *glyph = gid;
734
0
    return true;
735
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
736
737
  unsigned get_language () const
738
0
  {
739
0
    return language;
740
0
  }
Unexecuted instantiation: OT::CmapSubtableLongSegmented<OT::CmapSubtableFormat12>::get_language() const
Unexecuted instantiation: OT::CmapSubtableLongSegmented<OT::CmapSubtableFormat13>::get_language() const
741
742
  void collect_unicodes (hb_set_t *out, unsigned int num_glyphs) const
743
0
  {
744
0
    for (unsigned int i = 0; i < this->groups.len; i++)
745
0
    {
746
0
      hb_codepoint_t start = this->groups[i].startCharCode;
747
0
      hb_codepoint_t end = hb_min ((hb_codepoint_t) this->groups[i].endCharCode,
748
0
           (hb_codepoint_t) HB_UNICODE_MAX);
749
0
      hb_codepoint_t gid = this->groups[i].glyphID;
750
0
      if (!gid)
751
0
      {
752
  /* Intention is: if (hb_is_same (T, CmapSubtableFormat13)) continue; */
753
0
  if (! T::group_get_glyph (this->groups[i], end)) continue;
754
0
  start++;
755
0
  gid++;
756
0
      }
757
0
      if (unlikely ((unsigned int) gid >= num_glyphs)) continue;
758
0
      if (unlikely ((unsigned int) (gid + end - start) >= num_glyphs))
759
0
  end = start + (hb_codepoint_t) num_glyphs - gid;
760
761
0
      out->add_range (start, hb_min (end, 0x10FFFFu));
762
0
    }
763
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
764
765
  void collect_mapping (hb_set_t *unicodes, /* OUT */
766
      hb_map_t *mapping, /* OUT */
767
      unsigned num_glyphs) const
768
0
  {
769
0
    hb_codepoint_t last_end = 0;
770
0
    unsigned count = this->groups.len;
771
0
    for (unsigned i = 0; i < count; i++)
772
0
    {
773
0
      hb_codepoint_t start = this->groups.arrayZ[i].startCharCode;
774
0
      hb_codepoint_t end = hb_min ((hb_codepoint_t) this->groups.arrayZ[i].endCharCode,
775
0
           (hb_codepoint_t) HB_UNICODE_MAX);
776
0
      if (unlikely (start > end || start < last_end)) {
777
        // Range is not in order and is invalid, skip it.
778
0
        continue;
779
0
      }
780
0
      last_end = end;
781
782
783
0
      hb_codepoint_t gid = this->groups.arrayZ[i].glyphID;
784
0
      if (!gid)
785
0
      {
786
0
        if (T::formatNumber == 13) continue;
787
0
  start++;
788
0
  gid++;
789
0
      }
790
0
      if (unlikely ((unsigned int) gid >= num_glyphs)) continue;
791
0
      if (unlikely ((unsigned int) (gid + end - start) >= num_glyphs))
792
0
  end = start + (hb_codepoint_t) num_glyphs - gid;
793
794
0
      mapping->alloc (mapping->get_population () + end - start + 1);
795
796
0
      unicodes->add_range (start, end);
797
0
      for (unsigned cp = start; cp <= end; cp++)
798
0
      {
799
0
  mapping->set (cp, gid);
800
0
        gid += T::increment;
801
0
      }
802
0
    }
803
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
804
805
  bool sanitize (hb_sanitize_context_t *c) const
806
0
  {
807
0
    TRACE_SANITIZE (this);
808
0
    return_trace (c->check_struct (this) && groups.sanitize (c));
809
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
810
811
  protected:
812
  HBUINT16  format;   /* Subtable format; set to 12. */
813
  HBUINT16  reserved; /* Reserved; set to 0. */
814
  HBUINT32  length;   /* Byte length of this subtable. */
815
  HBUINT32  language; /* Ignore. */
816
  SortedArray32Of<CmapSubtableLongGroup>
817
    groups;   /* Groupings. */
818
  public:
819
  DEFINE_SIZE_ARRAY (16, groups);
820
};
821
822
struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
823
{
824
  static constexpr int increment = 1;
825
  static constexpr int formatNumber = 12;
826
827
  static hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
828
           hb_codepoint_t u)
829
0
  { return likely (group.startCharCode <= group.endCharCode) ?
830
0
     group.glyphID + (u - group.startCharCode) : 0; }
831
832
833
  template<typename Iterator,
834
     hb_requires (hb_is_iterator (Iterator))>
835
  void serialize (hb_serialize_context_t *c,
836
      Iterator it)
837
0
  {
838
0
    if (!it) return;
839
0
    unsigned table_initpos = c->length ();
840
0
    if (unlikely (!c->extend_min (this))) return;
841
0
842
0
    hb_codepoint_t startCharCode = (hb_codepoint_t) -1, endCharCode = (hb_codepoint_t) -1;
843
0
    hb_codepoint_t glyphID = 0;
844
0
845
0
    for (const auto& _ : +it)
846
0
    {
847
0
      if (startCharCode == (hb_codepoint_t) -1)
848
0
      {
849
0
  startCharCode = _.first;
850
0
  endCharCode = _.first;
851
0
  glyphID = _.second;
852
0
      }
853
0
      else if (!_is_gid_consecutive (endCharCode, startCharCode, glyphID, _.first, _.second))
854
0
      {
855
0
  CmapSubtableLongGroup  grouprecord;
856
0
  grouprecord.startCharCode = startCharCode;
857
0
  grouprecord.endCharCode = endCharCode;
858
0
  grouprecord.glyphID = glyphID;
859
0
  c->copy<CmapSubtableLongGroup> (grouprecord);
860
0
861
0
  startCharCode = _.first;
862
0
  endCharCode = _.first;
863
0
  glyphID = _.second;
864
0
      }
865
0
      else
866
0
  endCharCode = _.first;
867
0
    }
868
0
869
0
    CmapSubtableLongGroup record;
870
0
    record.startCharCode = startCharCode;
871
0
    record.endCharCode = endCharCode;
872
0
    record.glyphID = glyphID;
873
0
    c->copy<CmapSubtableLongGroup> (record);
874
0
875
0
    this->format = 12;
876
0
    this->reserved = 0;
877
0
    this->length = c->length () - table_initpos;
878
0
    this->groups.len = (this->length - min_size) / CmapSubtableLongGroup::static_size;
879
0
  }
Unexecuted instantiation: hb-face.cc:_ZN2OT20CmapSubtableFormat129serializeI16hb_filter_iter_tIS2_I17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS_4cmap6subsetEP19hb_subset_context_tEUlS5_E_RK4$_10LPv0EERK8hb_set_tRK3$_5LSF_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_tEUlS5_E_RK4$_10LPv0EETnPN12hb_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_tEUlS5_E_RK4$_11LPv0EERK8hb_set_tRK3$_5LSF_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_tEUlS5_E_RK4$_11LPv0EETnPN12hb_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_tEUlS5_E_RK4$_10LPv0EERK8hb_set_tRK3$_5LSF_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_tEUlS5_E_RK4$_10LPv0EETnPN12hb_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_tEUlS5_E_RK4$_10LPv0EERK8hb_set_tRK3$_5LSF_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_tEUlS5_E_RK4$_10LPv0EETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NSI_6item_tEEE5valueEvE4typeELSF_0EEEvP22hb_serialize_context_tSI_
880
881
  static size_t get_sub_table_size (const hb_sorted_vector_t<CmapSubtableLongGroup> &groups_data)
882
0
  { return 16 + 12 * groups_data.length; }
883
884
  private:
885
  static bool _is_gid_consecutive (hb_codepoint_t endCharCode,
886
           hb_codepoint_t startCharCode,
887
           hb_codepoint_t glyphID,
888
           hb_codepoint_t cp,
889
           hb_codepoint_t new_gid)
890
0
  {
891
0
    return (cp - 1 == endCharCode) &&
892
0
  new_gid == glyphID + (cp - startCharCode);
893
0
  }
894
895
};
896
897
struct CmapSubtableFormat13 : CmapSubtableLongSegmented<CmapSubtableFormat13>
898
{
899
  static constexpr int increment = 0;
900
  static constexpr int formatNumber = 13;
901
902
  static hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
903
           hb_codepoint_t u HB_UNUSED)
904
0
  { return group.glyphID; }
905
};
906
907
typedef enum
908
{
909
  GLYPH_VARIANT_NOT_FOUND = 0,
910
  GLYPH_VARIANT_FOUND = 1,
911
  GLYPH_VARIANT_USE_DEFAULT = 2
912
} glyph_variant_t;
913
914
struct UnicodeValueRange
915
{
916
  int cmp (const hb_codepoint_t &codepoint) const
917
0
  {
918
0
    if (codepoint < startUnicodeValue) return -1;
919
0
    if (codepoint > startUnicodeValue + additionalCount) return +1;
920
0
    return 0;
921
0
  }
922
923
  bool sanitize (hb_sanitize_context_t *c) const
924
0
  {
925
0
    TRACE_SANITIZE (this);
926
0
    return_trace (c->check_struct (this));
927
0
  }
928
929
  HBUINT24  startUnicodeValue;  /* First value in this range. */
930
  HBUINT8 additionalCount;  /* Number of additional values in this
931
           * range. */
932
  public:
933
  DEFINE_SIZE_STATIC (4);
934
};
935
936
struct DefaultUVS : SortedArray32Of<UnicodeValueRange>
937
{
938
  void collect_unicodes (hb_set_t *out) const
939
0
  {
940
0
    unsigned int count = len;
941
0
    for (unsigned int i = 0; i < count; i++)
942
0
    {
943
0
      hb_codepoint_t first = arrayZ[i].startUnicodeValue;
944
0
      hb_codepoint_t last = hb_min ((hb_codepoint_t) (first + arrayZ[i].additionalCount),
945
0
            (hb_codepoint_t) HB_UNICODE_MAX);
946
0
      out->add_range (first, last);
947
0
    }
948
0
  }
949
950
  DefaultUVS* copy (hb_serialize_context_t *c,
951
        const hb_set_t *unicodes) const
952
0
  {
953
0
    auto *out = c->start_embed<DefaultUVS> ();
954
0
    auto snap = c->snapshot ();
955
0
956
0
    HBUINT32 len;
957
0
    len = 0;
958
0
    if (unlikely (!c->copy<HBUINT32> (len))) return nullptr;
959
0
    unsigned init_len = c->length ();
960
0
961
0
    if (this->len > unicodes->get_population () * hb_bit_storage ((unsigned) this->len))
962
0
    {
963
0
      hb_codepoint_t start = HB_SET_VALUE_INVALID;
964
0
      hb_codepoint_t end = HB_SET_VALUE_INVALID;
965
0
966
0
      for (auto u : *unicodes)
967
0
      {
968
0
        if (!as_array ().bsearch (u))
969
0
    continue;
970
0
  if (start == HB_SET_VALUE_INVALID)
971
0
  {
972
0
    start = u;
973
0
    end = start - 1;
974
0
  }
975
0
  if (end + 1 != u || end - start == 255)
976
0
        {
977
0
    UnicodeValueRange rec;
978
0
    rec.startUnicodeValue = start;
979
0
    rec.additionalCount = end - start;
980
0
    c->copy<UnicodeValueRange> (rec);
981
0
    start = u;
982
0
  }
983
0
  end = u;
984
0
      }
985
0
      if (start != HB_SET_VALUE_INVALID)
986
0
      {
987
0
  UnicodeValueRange rec;
988
0
  rec.startUnicodeValue = start;
989
0
  rec.additionalCount = end - start;
990
0
  c->copy<UnicodeValueRange> (rec);
991
0
      }
992
0
993
0
    }
994
0
    else
995
0
    {
996
0
      hb_codepoint_t lastCode = HB_SET_VALUE_INVALID;
997
0
      int count = -1;
998
0
999
0
      for (const UnicodeValueRange& _ : *this)
1000
0
      {
1001
0
  hb_codepoint_t curEntry = (hb_codepoint_t) (_.startUnicodeValue - 1);
1002
0
  hb_codepoint_t end = curEntry + _.additionalCount + 2;
1003
0
1004
0
  for (; unicodes->next (&curEntry) && curEntry < end;)
1005
0
  {
1006
0
    count += 1;
1007
0
    if (lastCode == HB_SET_VALUE_INVALID)
1008
0
      lastCode = curEntry;
1009
0
    else if (lastCode + count != curEntry)
1010
0
    {
1011
0
      UnicodeValueRange rec;
1012
0
      rec.startUnicodeValue = lastCode;
1013
0
      rec.additionalCount = count - 1;
1014
0
      c->copy<UnicodeValueRange> (rec);
1015
0
1016
0
      lastCode = curEntry;
1017
0
      count = 0;
1018
0
    }
1019
0
  }
1020
0
      }
1021
0
1022
0
      if (lastCode != HB_MAP_VALUE_INVALID)
1023
0
      {
1024
0
  UnicodeValueRange rec;
1025
0
  rec.startUnicodeValue = lastCode;
1026
0
  rec.additionalCount = count;
1027
0
  c->copy<UnicodeValueRange> (rec);
1028
0
      }
1029
0
    }
1030
0
1031
0
    if (c->length () - init_len == 0)
1032
0
    {
1033
0
      c->revert (snap);
1034
0
      return nullptr;
1035
0
    }
1036
0
    else
1037
0
    {
1038
0
      if (unlikely (!c->check_assign (out->len,
1039
0
                                      (c->length () - init_len) / UnicodeValueRange::static_size,
1040
0
                                      HB_SERIALIZE_ERROR_INT_OVERFLOW))) return nullptr;
1041
0
      return out;
1042
0
    }
1043
0
  }
1044
1045
  public:
1046
  DEFINE_SIZE_ARRAY (4, *this);
1047
};
1048
1049
struct UVSMapping
1050
{
1051
  int cmp (const hb_codepoint_t &codepoint) const
1052
0
  { return unicodeValue.cmp (codepoint); }
1053
1054
  bool sanitize (hb_sanitize_context_t *c) const
1055
0
  {
1056
0
    TRACE_SANITIZE (this);
1057
0
    return_trace (c->check_struct (this));
1058
0
  }
1059
1060
  HBUINT24  unicodeValue; /* Base Unicode value of the UVS */
1061
  HBGlyphID16 glyphID;  /* Glyph ID of the UVS */
1062
  public:
1063
  DEFINE_SIZE_STATIC (5);
1064
};
1065
1066
struct NonDefaultUVS : SortedArray32Of<UVSMapping>
1067
{
1068
  void collect_unicodes (hb_set_t *out) const
1069
0
  {
1070
0
    for (const auto& a : as_array ())
1071
0
      out->add (a.unicodeValue);
1072
0
  }
1073
1074
  void collect_mapping (hb_set_t *unicodes, /* OUT */
1075
      hb_map_t *mapping /* OUT */) const
1076
0
  {
1077
0
    for (const auto& a : as_array ())
1078
0
    {
1079
0
      hb_codepoint_t unicode = a.unicodeValue;
1080
0
      hb_codepoint_t glyphid = a.glyphID;
1081
0
      unicodes->add (unicode);
1082
0
      mapping->set (unicode, glyphid);
1083
0
    }
1084
0
  }
1085
1086
  void closure_glyphs (const hb_set_t      *unicodes,
1087
           hb_set_t            *glyphset) const
1088
0
  {
1089
0
    + as_array ()
1090
0
    | hb_filter (unicodes, &UVSMapping::unicodeValue)
1091
0
    | hb_map (&UVSMapping::glyphID)
1092
0
    | hb_sink (glyphset)
1093
0
    ;
1094
0
  }
1095
1096
  NonDefaultUVS* copy (hb_serialize_context_t *c,
1097
           const hb_set_t *unicodes,
1098
           const hb_set_t *glyphs_requested,
1099
           const hb_map_t *glyph_map) const
1100
0
  {
1101
0
    auto *out = c->start_embed<NonDefaultUVS> ();
1102
0
    auto it =
1103
0
    + as_array ()
1104
0
    | hb_filter ([&] (const UVSMapping& _)
1105
0
     {
1106
0
       return unicodes->has (_.unicodeValue) || glyphs_requested->has (_.glyphID);
1107
0
     })
1108
0
    ;
1109
0
1110
0
    if (!it) return nullptr;
1111
0
1112
0
    HBUINT32 len;
1113
0
    len = it.len ();
1114
0
    if (unlikely (!c->copy<HBUINT32> (len))) return nullptr;
1115
0
1116
0
    for (const UVSMapping& _ : it)
1117
0
    {
1118
0
      UVSMapping mapping;
1119
0
      mapping.unicodeValue = _.unicodeValue;
1120
0
      mapping.glyphID = glyph_map->get (_.glyphID);
1121
0
      c->copy<UVSMapping> (mapping);
1122
0
    }
1123
0
1124
0
    return out;
1125
0
  }
1126
1127
  public:
1128
  DEFINE_SIZE_ARRAY (4, *this);
1129
};
1130
1131
struct VariationSelectorRecord
1132
{
1133
  glyph_variant_t get_glyph (hb_codepoint_t codepoint,
1134
           hb_codepoint_t *glyph,
1135
           const void *base) const
1136
0
  {
1137
0
    if ((base+defaultUVS).bfind (codepoint))
1138
0
      return GLYPH_VARIANT_USE_DEFAULT;
1139
0
    const UVSMapping &nonDefault = (base+nonDefaultUVS).bsearch (codepoint);
1140
0
    if (nonDefault.glyphID)
1141
0
    {
1142
0
      *glyph = nonDefault.glyphID;
1143
0
       return GLYPH_VARIANT_FOUND;
1144
0
    }
1145
0
    return GLYPH_VARIANT_NOT_FOUND;
1146
0
  }
1147
1148
  VariationSelectorRecord(const VariationSelectorRecord& other)
1149
0
  {
1150
0
    *this = other;
1151
0
  }
1152
1153
  void operator= (const VariationSelectorRecord& other)
1154
0
  {
1155
0
    varSelector = other.varSelector;
1156
0
    HBUINT32 offset = other.defaultUVS;
1157
0
    defaultUVS = offset;
1158
0
    offset = other.nonDefaultUVS;
1159
0
    nonDefaultUVS = offset;
1160
0
  }
1161
1162
  void collect_unicodes (hb_set_t *out, const void *base) const
1163
0
  {
1164
0
    (base+defaultUVS).collect_unicodes (out);
1165
0
    (base+nonDefaultUVS).collect_unicodes (out);
1166
0
  }
1167
1168
  void collect_mapping (const void *base,
1169
      hb_set_t *unicodes, /* OUT */
1170
      hb_map_t *mapping /* OUT */) const
1171
0
  {
1172
0
    (base+defaultUVS).collect_unicodes (unicodes);
1173
0
    (base+nonDefaultUVS).collect_mapping (unicodes, mapping);
1174
0
  }
1175
1176
  int cmp (const hb_codepoint_t &variation_selector) const
1177
0
  { return varSelector.cmp (variation_selector); }
1178
1179
  bool sanitize (hb_sanitize_context_t *c, const void *base) const
1180
0
  {
1181
0
    TRACE_SANITIZE (this);
1182
0
    return_trace (c->check_struct (this) &&
1183
0
      defaultUVS.sanitize (c, base) &&
1184
0
      nonDefaultUVS.sanitize (c, base));
1185
0
  }
1186
1187
  hb_pair_t<unsigned, unsigned>
1188
  copy (hb_serialize_context_t *c,
1189
  const hb_set_t *unicodes,
1190
  const hb_set_t *glyphs_requested,
1191
  const hb_map_t *glyph_map,
1192
  const void *base) const
1193
0
  {
1194
0
    auto snap = c->snapshot ();
1195
0
    auto *out = c->embed<VariationSelectorRecord> (*this);
1196
0
    if (unlikely (!out)) return hb_pair (0, 0);
1197
0
1198
0
    out->defaultUVS = 0;
1199
0
    out->nonDefaultUVS = 0;
1200
0
1201
0
    unsigned non_default_uvs_objidx = 0;
1202
0
    if (nonDefaultUVS != 0)
1203
0
    {
1204
0
      c->push ();
1205
0
      if (c->copy (base+nonDefaultUVS, unicodes, glyphs_requested, glyph_map))
1206
0
  non_default_uvs_objidx = c->pop_pack ();
1207
0
      else c->pop_discard ();
1208
0
    }
1209
0
1210
0
    unsigned default_uvs_objidx = 0;
1211
0
    if (defaultUVS != 0)
1212
0
    {
1213
0
      c->push ();
1214
0
      if (c->copy (base+defaultUVS, unicodes))
1215
0
  default_uvs_objidx = c->pop_pack ();
1216
0
      else c->pop_discard ();
1217
0
    }
1218
0
1219
0
1220
0
    if (!default_uvs_objidx && !non_default_uvs_objidx)
1221
0
      c->revert (snap);
1222
0
1223
0
    return hb_pair (default_uvs_objidx, non_default_uvs_objidx);
1224
0
  }
1225
1226
  HBUINT24  varSelector;  /* Variation selector. */
1227
  Offset32To<DefaultUVS>
1228
    defaultUVS; /* Offset to Default UVS Table.  May be 0. */
1229
  Offset32To<NonDefaultUVS>
1230
    nonDefaultUVS;  /* Offset to Non-Default UVS Table.  May be 0. */
1231
  public:
1232
  DEFINE_SIZE_STATIC (11);
1233
};
1234
1235
struct CmapSubtableFormat14
1236
{
1237
  glyph_variant_t get_glyph_variant (hb_codepoint_t codepoint,
1238
             hb_codepoint_t variation_selector,
1239
             hb_codepoint_t *glyph) const
1240
0
  { return record.bsearch (variation_selector).get_glyph (codepoint, glyph, this); }
1241
1242
  void collect_variation_selectors (hb_set_t *out) const
1243
0
  {
1244
0
    for (const auto& a : record.as_array ())
1245
0
      out->add (a.varSelector);
1246
0
  }
1247
  void collect_variation_unicodes (hb_codepoint_t variation_selector,
1248
           hb_set_t *out) const
1249
0
  { record.bsearch (variation_selector).collect_unicodes (out, this); }
1250
1251
  void serialize (hb_serialize_context_t *c,
1252
      const hb_set_t *unicodes,
1253
      const hb_set_t *glyphs_requested,
1254
      const hb_map_t *glyph_map,
1255
      const void *base)
1256
0
  {
1257
0
    auto snap = c->snapshot ();
1258
0
    unsigned table_initpos = c->length ();
1259
0
    const char* init_tail = c->tail;
1260
0
1261
0
    if (unlikely (!c->extend_min (this))) return;
1262
0
    this->format = 14;
1263
0
1264
0
    auto src_tbl = reinterpret_cast<const CmapSubtableFormat14*> (base);
1265
0
1266
0
    /*
1267
0
     * Some versions of OTS require that offsets are in order. Due to the use
1268
0
     * of push()/pop_pack() serializing the variation records in order results
1269
0
     * in the offsets being in reverse order (first record has the largest
1270
0
     * offset). While this is perfectly valid, it will cause some versions of
1271
0
     * OTS to consider this table bad.
1272
0
     *
1273
0
     * So to prevent this issue we serialize the variation records in reverse
1274
0
     * order, so that the offsets are ordered from small to large. Since
1275
0
     * variation records are supposed to be in increasing order of varSelector
1276
0
     * we then have to reverse the order of the written variation selector
1277
0
     * records after everything is finalized.
1278
0
     */
1279
0
    hb_vector_t<hb_pair_t<unsigned, unsigned>> obj_indices;
1280
0
    for (int i = src_tbl->record.len - 1; i >= 0; i--)
1281
0
    {
1282
0
      hb_pair_t<unsigned, unsigned> result = src_tbl->record[i].copy (c, unicodes, glyphs_requested, glyph_map, base);
1283
0
      if (result.first || result.second)
1284
0
  obj_indices.push (result);
1285
0
    }
1286
0
1287
0
    if (c->length () - table_initpos == CmapSubtableFormat14::min_size)
1288
0
    {
1289
0
      c->revert (snap);
1290
0
      return;
1291
0
    }
1292
0
1293
0
    if (unlikely (!c->check_success (!obj_indices.in_error ())))
1294
0
      return;
1295
0
1296
0
    int tail_len = init_tail - c->tail;
1297
0
    c->check_assign (this->length, c->length () - table_initpos + tail_len,
1298
0
                     HB_SERIALIZE_ERROR_INT_OVERFLOW);
1299
0
    c->check_assign (this->record.len,
1300
0
         (c->length () - table_initpos - CmapSubtableFormat14::min_size) /
1301
0
         VariationSelectorRecord::static_size,
1302
0
                     HB_SERIALIZE_ERROR_INT_OVERFLOW);
1303
0
1304
0
    /* Correct the incorrect write order by reversing the order of the variation
1305
0
       records array. */
1306
0
    _reverse_variation_records ();
1307
0
1308
0
    /* Now that records are in the right order, we can set up the offsets. */
1309
0
    _add_links_to_variation_records (c, obj_indices);
1310
0
  }
1311
1312
  void _reverse_variation_records ()
1313
0
  {
1314
0
    record.as_array ().reverse ();
1315
0
  }
1316
1317
  void _add_links_to_variation_records (hb_serialize_context_t *c,
1318
          const hb_vector_t<hb_pair_t<unsigned, unsigned>>& obj_indices)
1319
0
  {
1320
0
    for (unsigned i = 0; i < obj_indices.length; i++)
1321
0
    {
1322
0
      /*
1323
0
       * Since the record array has been reversed (see comments in copy())
1324
0
       * but obj_indices has not been, the indices at obj_indices[i]
1325
0
       * are for the variation record at record[j].
1326
0
       */
1327
0
      int j = obj_indices.length - 1 - i;
1328
0
      c->add_link (record[j].defaultUVS, obj_indices[i].first);
1329
0
      c->add_link (record[j].nonDefaultUVS, obj_indices[i].second);
1330
0
    }
1331
0
  }
1332
1333
  void closure_glyphs (const hb_set_t      *unicodes,
1334
           hb_set_t            *glyphset) const
1335
0
  {
1336
0
    + hb_iter (record)
1337
0
    | hb_filter (hb_bool, &VariationSelectorRecord::nonDefaultUVS)
1338
0
    | hb_map (&VariationSelectorRecord::nonDefaultUVS)
1339
0
    | hb_map (hb_add (this))
1340
0
    | hb_apply ([=] (const NonDefaultUVS& _) { _.closure_glyphs (unicodes, glyphset); })
1341
0
    ;
1342
0
  }
1343
1344
  void collect_unicodes (hb_set_t *out) const
1345
0
  {
1346
0
    for (const VariationSelectorRecord& _ : record)
1347
0
      _.collect_unicodes (out, this);
1348
0
  }
1349
1350
  void collect_mapping (hb_set_t *unicodes, /* OUT */
1351
      hb_map_t *mapping /* OUT */) const
1352
0
  {
1353
0
    for (const VariationSelectorRecord& _ : record)
1354
0
      _.collect_mapping (this, unicodes, mapping);
1355
0
  }
1356
1357
  bool sanitize (hb_sanitize_context_t *c) const
1358
0
  {
1359
0
    TRACE_SANITIZE (this);
1360
0
    return_trace (c->check_struct (this) &&
1361
0
      record.sanitize (c, this));
1362
0
  }
1363
1364
  protected:
1365
  HBUINT16  format;   /* Format number is set to 14. */
1366
  HBUINT32  length;   /* Byte length of this subtable. */
1367
  SortedArray32Of<VariationSelectorRecord>
1368
    record;   /* Variation selector records; sorted
1369
         * in increasing order of `varSelector'. */
1370
  public:
1371
  DEFINE_SIZE_ARRAY (10, record);
1372
};
1373
1374
struct CmapSubtable
1375
{
1376
  /* Note: We intentionally do NOT implement subtable formats 2 and 8. */
1377
1378
  bool get_glyph (hb_codepoint_t codepoint,
1379
      hb_codepoint_t *glyph) const
1380
0
  {
1381
0
    switch (u.format) {
1382
0
    case  0: return u.format0 .get_glyph (codepoint, glyph);
1383
0
    case  4: return u.format4 .get_glyph (codepoint, glyph);
1384
0
    case  6: return u.format6 .get_glyph (codepoint, glyph);
1385
0
    case 10: return u.format10.get_glyph (codepoint, glyph);
1386
0
    case 12: return u.format12.get_glyph (codepoint, glyph);
1387
0
    case 13: return u.format13.get_glyph (codepoint, glyph);
1388
0
    case 14:
1389
0
    default: return false;
1390
0
    }
1391
0
  }
1392
  void collect_unicodes (hb_set_t *out, unsigned int num_glyphs = UINT_MAX) const
1393
0
  {
1394
0
    switch (u.format) {
1395
0
    case  0: u.format0 .collect_unicodes (out); return;
1396
0
    case  4: u.format4 .collect_unicodes (out); return;
1397
0
    case  6: u.format6 .collect_unicodes (out); return;
1398
0
    case 10: u.format10.collect_unicodes (out); return;
1399
0
    case 12: u.format12.collect_unicodes (out, num_glyphs); return;
1400
0
    case 13: u.format13.collect_unicodes (out, num_glyphs); return;
1401
0
    case 14:
1402
0
    default: return;
1403
0
    }
1404
0
  }
1405
1406
  void collect_mapping (hb_set_t *unicodes, /* OUT */
1407
      hb_map_t *mapping, /* OUT */
1408
      unsigned num_glyphs = UINT_MAX) const
1409
0
  {
1410
0
    switch (u.format) {
1411
0
    case  0: u.format0 .collect_mapping (unicodes, mapping); return;
1412
0
    case  4: u.format4 .collect_mapping (unicodes, mapping); return;
1413
0
    case  6: u.format6 .collect_mapping (unicodes, mapping); return;
1414
0
    case 10: u.format10.collect_mapping (unicodes, mapping); return;
1415
0
    case 12: u.format12.collect_mapping (unicodes, mapping, num_glyphs); return;
1416
0
    case 13: u.format13.collect_mapping (unicodes, mapping, num_glyphs); return;
1417
0
    case 14:
1418
0
    default: return;
1419
0
    }
1420
0
  }
1421
1422
  unsigned get_language () const
1423
0
  {
1424
0
    switch (u.format) {
1425
0
    case  0: return u.format0 .get_language ();
1426
0
    case  4: return u.format4 .get_language ();
1427
0
    case  6: return u.format6 .get_language ();
1428
0
    case 10: return u.format10.get_language ();
1429
0
    case 12: return u.format12.get_language ();
1430
0
    case 13: return u.format13.get_language ();
1431
0
    case 14:
1432
0
    default: return 0;
1433
0
    }
1434
0
  }
1435
1436
  template<typename Iterator,
1437
     hb_requires (hb_is_iterator (Iterator))>
1438
  void serialize (hb_serialize_context_t *c,
1439
      Iterator it,
1440
      unsigned format,
1441
      const hb_subset_plan_t *plan,
1442
      const void *base)
1443
0
  {
1444
0
    switch (format) {
1445
0
    case  4: return u.format4.serialize (c, it);
1446
0
    case 12: return u.format12.serialize (c, it);
1447
0
    case 14: return u.format14.serialize (c, &plan->unicodes, &plan->glyphs_requested, plan->glyph_map, base);
1448
0
    default: return;
1449
0
    }
1450
0
  }
Unexecuted instantiation: hb-face.cc:_ZN2OT12CmapSubtable9serializeI16hb_filter_iter_tIS2_I17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS_4cmap6subsetEP19hb_subset_context_tEUlS5_E_RK4$_10LPv0EERK8hb_set_tRK3$_5LSF_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_tEUlS5_E_RK4$_10LPv0EETnPN12hb_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_tEUlS5_E_RK4$_11LPv0EERK8hb_set_tRK3$_5LSF_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_tEUlS5_E_RK4$_11LPv0EETnPN12hb_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_tEUlS5_E_RK4$_10LPv0EERK8hb_set_tRK3$_5LSF_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_tEUlS5_E_RK4$_10LPv0EETnPN12hb_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_tEUlS5_E_RK4$_10LPv0EERK8hb_set_tRK3$_5LSF_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_tEUlS5_E_RK4$_10LPv0EETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NSI_6item_tEEE5valueEvE4typeELSF_0EEEvP22hb_serialize_context_tSI_jPK16hb_subset_plan_tPKv
1451
1452
  bool sanitize (hb_sanitize_context_t *c) const
1453
0
  {
1454
0
    TRACE_SANITIZE (this);
1455
0
    if (!u.format.sanitize (c)) return_trace (false);
1456
0
    hb_barrier ();
1457
0
    switch (u.format) {
1458
0
    case  0: return_trace (u.format0 .sanitize (c));
1459
0
    case  4: return_trace (u.format4 .sanitize (c));
1460
0
    case  6: return_trace (u.format6 .sanitize (c));
1461
0
    case 10: return_trace (u.format10.sanitize (c));
1462
0
    case 12: return_trace (u.format12.sanitize (c));
1463
0
    case 13: return_trace (u.format13.sanitize (c));
1464
0
    case 14: return_trace (u.format14.sanitize (c));
1465
0
    default:return_trace (true);
1466
0
    }
1467
0
  }
1468
1469
  public:
1470
  union {
1471
  HBUINT16    format;   /* Format identifier */
1472
  CmapSubtableFormat0 format0;
1473
  CmapSubtableFormat4 format4;
1474
  CmapSubtableFormat6 format6;
1475
  CmapSubtableFormat10  format10;
1476
  CmapSubtableFormat12  format12;
1477
  CmapSubtableFormat13  format13;
1478
  CmapSubtableFormat14  format14;
1479
  } u;
1480
  public:
1481
  DEFINE_SIZE_UNION (2, format);
1482
};
1483
1484
1485
struct EncodingRecord
1486
{
1487
  int cmp (const EncodingRecord &other) const
1488
0
  {
1489
0
    int ret;
1490
0
    ret = platformID.cmp (other.platformID);
1491
0
    if (ret) return ret;
1492
0
    if (other.encodingID != 0xFFFF)
1493
0
    {
1494
0
      ret = encodingID.cmp (other.encodingID);
1495
0
      if (ret) return ret;
1496
0
    }
1497
0
    return 0;
1498
0
  }
1499
1500
  bool sanitize (hb_sanitize_context_t *c, const void *base) const
1501
0
  {
1502
0
    TRACE_SANITIZE (this);
1503
0
    return_trace (c->check_struct (this) &&
1504
0
      subtable.sanitize (c, base));
1505
0
  }
1506
1507
  template<typename Iterator,
1508
     hb_requires (hb_is_iterator (Iterator))>
1509
  EncodingRecord* copy (hb_serialize_context_t *c,
1510
      Iterator it,
1511
      unsigned format,
1512
      const void *base,
1513
      const hb_subset_plan_t *plan,
1514
      /* INOUT */ unsigned *objidx) const
1515
0
  {
1516
0
    TRACE_SERIALIZE (this);
1517
0
    auto snap = c->snapshot ();
1518
0
    auto *out = c->embed (this);
1519
0
    if (unlikely (!out)) return_trace (nullptr);
1520
0
    out->subtable = 0;
1521
0
1522
0
    if (*objidx == 0)
1523
0
    {
1524
0
      CmapSubtable *cmapsubtable = c->push<CmapSubtable> ();
1525
0
      unsigned origin_length = c->length ();
1526
0
      cmapsubtable->serialize (c, it, format, plan, &(base+subtable));
1527
0
      if (c->length () - origin_length > 0) *objidx = c->pop_pack ();
1528
0
      else c->pop_discard ();
1529
0
    }
1530
0
1531
0
    if (*objidx == 0)
1532
0
    {
1533
0
      c->revert (snap);
1534
0
      return_trace (nullptr);
1535
0
    }
1536
0
1537
0
    c->add_link (out->subtable, *objidx);
1538
0
    return_trace (out);
1539
0
  }
Unexecuted instantiation: hb-face.cc:_ZNK2OT14EncodingRecord4copyI16hb_filter_iter_tIS2_I17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS_4cmap6subsetEP19hb_subset_context_tEUlS5_E_RK4$_10LPv0EERK8hb_set_tRK3$_5LSF_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_tEUlS5_E_RK4$_10LPv0EETnPN12hb_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_tEUlS5_E_RK4$_11LPv0EERK8hb_set_tRK3$_5LSF_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_tEUlS5_E_RK4$_11LPv0EETnPN12hb_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_tEUlS5_E_RK4$_10LPv0EERK8hb_set_tRK3$_5LSF_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_tEUlS5_E_RK4$_10LPv0EETnPN12hb_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_tEUlS5_E_RK4$_10LPv0EERK8hb_set_tRK3$_5LSF_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_tEUlS5_E_RK4$_10LPv0EETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT_NSI_6item_tEEE5valueEvE4typeELSF_0EEEPS0_P22hb_serialize_context_tSI_jPKvPK16hb_subset_plan_tPj
1540
1541
  HBUINT16  platformID; /* Platform ID. */
1542
  HBUINT16  encodingID; /* Platform-specific encoding ID. */
1543
  Offset32To<CmapSubtable>
1544
    subtable; /* Byte offset from beginning of table to the subtable for this encoding. */
1545
  public:
1546
  DEFINE_SIZE_STATIC (8);
1547
};
1548
1549
struct cmap;
1550
1551
struct SubtableUnicodesCache {
1552
1553
 private:
1554
  hb_blob_ptr_t<cmap> base_blob;
1555
  const char* base;
1556
  hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> cached_unicodes;
1557
1558
 public:
1559
1560
  static SubtableUnicodesCache* create (hb_blob_ptr_t<cmap> source_table)
1561
0
  {
1562
0
    SubtableUnicodesCache* cache =
1563
0
        (SubtableUnicodesCache*) hb_malloc (sizeof(SubtableUnicodesCache));
1564
0
    new (cache) SubtableUnicodesCache (source_table);
1565
0
    return cache;
1566
0
  }
1567
1568
0
  static void destroy (void* value) {
1569
0
    if (!value) return;
1570
0
1571
0
    SubtableUnicodesCache* cache = (SubtableUnicodesCache*) value;
1572
0
    cache->~SubtableUnicodesCache ();
1573
0
    hb_free (cache);
1574
0
  }
1575
1576
  SubtableUnicodesCache(const void* cmap_base)
1577
      : base_blob(),
1578
        base ((const char*) cmap_base),
1579
        cached_unicodes ()
1580
0
  {}
1581
1582
  SubtableUnicodesCache(hb_blob_ptr_t<cmap> base_blob_)
1583
      : base_blob(base_blob_),
1584
        base ((const char *) base_blob.get()),
1585
        cached_unicodes ()
1586
0
  {}
1587
1588
  ~SubtableUnicodesCache()
1589
0
  {
1590
0
    base_blob.destroy ();
1591
0
  }
1592
1593
  bool same_base(const void* other) const
1594
0
  {
1595
0
    return other == (const void*) base;
1596
0
  }
1597
1598
  const hb_set_t* set_for (const EncodingRecord* record,
1599
                           SubtableUnicodesCache& mutable_cache) const
1600
0
  {
1601
0
    if (cached_unicodes.has ((unsigned) ((const char *) record - base)))
1602
0
      return cached_unicodes.get ((unsigned) ((const char *) record - base));
1603
0
1604
0
    return mutable_cache.set_for (record);
1605
0
  }
1606
1607
  const hb_set_t* set_for (const EncodingRecord* record)
1608
0
  {
1609
0
    if (!cached_unicodes.has ((unsigned) ((const char *) record - base)))
1610
0
    {
1611
0
      hb_set_t *s = hb_set_create ();
1612
0
      if (unlikely (s->in_error ()))
1613
0
  return hb_set_get_empty ();
1614
0
1615
0
      (base+record->subtable).collect_unicodes (s);
1616
0
1617
0
      if (unlikely (!cached_unicodes.set ((unsigned) ((const char *) record - base), hb::unique_ptr<hb_set_t> {s})))
1618
0
        return hb_set_get_empty ();
1619
0
1620
0
      return s;
1621
0
    }
1622
0
    return cached_unicodes.get ((unsigned) ((const char *) record - base));
1623
0
  }
1624
1625
};
1626
1627
static inline uint_fast16_t
1628
_hb_symbol_pua_map (unsigned codepoint)
1629
0
{
1630
0
  if (codepoint <= 0x00FFu)
1631
0
  {
1632
    /* For symbol-encoded OpenType fonts, we duplicate the
1633
     * U+F000..F0FF range at U+0000..U+00FF.  That's what
1634
     * Windows seems to do, and that's hinted about at:
1635
     * https://docs.microsoft.com/en-us/typography/opentype/spec/recom
1636
     * under "Non-Standard (Symbol) Fonts". */
1637
0
    return 0xF000u + codepoint;
1638
0
  }
1639
0
  return 0;
1640
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)
1641
1642
struct cmap
1643
{
1644
  static constexpr hb_tag_t tableTag = HB_OT_TAG_cmap;
1645
1646
1647
0
  static SubtableUnicodesCache* create_filled_cache(hb_blob_ptr_t<cmap> source_table) {
1648
0
    const cmap* cmap = source_table.get();
1649
0
    auto it =
1650
0
    + hb_iter (cmap->encodingRecord)
1651
0
    | hb_filter ([&](const EncodingRecord& _) {
1652
0
      return cmap::filter_encoding_records_for_subset (cmap, _);
1653
0
    })
1654
0
    ;
1655
0
1656
0
    SubtableUnicodesCache* cache = SubtableUnicodesCache::create(source_table);
1657
0
    for (const EncodingRecord& _ : it)
1658
0
      cache->set_for(&_); // populate the cache for this encoding record.
1659
0
1660
0
    return cache;
1661
0
  }
1662
1663
  template<typename Iterator, typename EncodingRecIter,
1664
     hb_requires (hb_is_iterator (EncodingRecIter))>
1665
  bool serialize (hb_serialize_context_t *c,
1666
      Iterator it,
1667
      EncodingRecIter encodingrec_iter,
1668
      const void *base,
1669
      hb_subset_plan_t *plan,
1670
                  bool drop_format_4 = false)
1671
0
  {
1672
0
    if (unlikely (!c->extend_min ((*this))))  return false;
1673
0
    this->version = 0;
1674
0
1675
0
    unsigned format4objidx = 0, format12objidx = 0, format14objidx = 0;
1676
0
    auto snap = c->snapshot ();
1677
0
1678
0
    SubtableUnicodesCache local_unicodes_cache (base);
1679
0
    const SubtableUnicodesCache* unicodes_cache = &local_unicodes_cache;
1680
0
1681
0
    if (plan->accelerator &&
1682
0
        plan->accelerator->cmap_cache &&
1683
0
        plan->accelerator->cmap_cache->same_base (base))
1684
0
      unicodes_cache = plan->accelerator->cmap_cache;
1685
0
1686
0
    for (const EncodingRecord& _ : encodingrec_iter)
1687
0
    {
1688
0
      if (c->in_error ())
1689
0
        return false;
1690
0
1691
0
      unsigned format = (base+_.subtable).u.format;
1692
0
      if (format != 4 && format != 12 && format != 14) continue;
1693
0
1694
0
      const hb_set_t* unicodes_set = unicodes_cache->set_for (&_, local_unicodes_cache);
1695
0
1696
0
      if (!drop_format_4 && format == 4)
1697
0
      {
1698
0
        c->copy (_, + it | hb_filter (*unicodes_set, hb_first), 4u, base, plan, &format4objidx);
1699
0
        if (c->in_error () && c->only_overflow ())
1700
0
        {
1701
0
          // cmap4 overflowed, reset and retry serialization without format 4 subtables.
1702
0
          c->revert (snap);
1703
0
          return serialize (c, it,
1704
0
                            encodingrec_iter,
1705
0
                            base,
1706
0
                            plan,
1707
0
                            true);
1708
0
        }
1709
0
      }
1710
0
1711
0
      else if (format == 12)
1712
0
      {
1713
0
        if (_can_drop (_,
1714
0
                       *unicodes_set,
1715
0
                       base,
1716
0
                       *unicodes_cache,
1717
0
                       local_unicodes_cache,
1718
0
                       + it | hb_map (hb_first), encodingrec_iter))
1719
0
          continue;
1720
0
        c->copy (_, + it | hb_filter (*unicodes_set, hb_first), 12u, base, plan, &format12objidx);
1721
0
      }
1722
0
      else if (format == 14) c->copy (_, it, 14u, base, plan, &format14objidx);
1723
0
    }
1724
0
    c->check_assign(this->encodingRecord.len,
1725
0
                    (c->length () - cmap::min_size)/EncodingRecord::static_size,
1726
0
                    HB_SERIALIZE_ERROR_INT_OVERFLOW);
1727
0
1728
0
    // Fail if format 4 was dropped and there is no cmap12.
1729
0
    return !drop_format_4 || format12objidx;
1730
0
  }
Unexecuted instantiation: hb-face.cc:_ZN2OT4cmap9serializeI16hb_filter_iter_tI17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS0_6subsetEP19hb_subset_context_tEUlS5_E_RK4$_10LPv0EES2_IS3_IKNS_14EncodingRecordEEZNKS0_6subsetES9_EUlRSH_E_SD_LSE_0EETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT0_NSN_6item_tEEE5valueEvE4typeELSE_0EEEbP22hb_serialize_context_tT_SN_PKvP16hb_subset_plan_tb
Unexecuted instantiation: hb-ot-face.cc:_ZN2OT4cmap9serializeI16hb_filter_iter_tI17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS0_6subsetEP19hb_subset_context_tEUlS5_E_RK4$_11LPv0EES2_IS3_IKNS_14EncodingRecordEEZNKS0_6subsetES9_EUlRSH_E_SD_LSE_0EETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT0_NSN_6item_tEEE5valueEvE4typeELSE_0EEEbP22hb_serialize_context_tT_SN_PKvP16hb_subset_plan_tb
Unexecuted instantiation: hb-ot-font.cc:_ZN2OT4cmap9serializeI16hb_filter_iter_tI17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS0_6subsetEP19hb_subset_context_tEUlS5_E_RK4$_10LPv0EES2_IS3_IKNS_14EncodingRecordEEZNKS0_6subsetES9_EUlRSH_E_SD_LSE_0EETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT0_NSN_6item_tEEE5valueEvE4typeELSE_0EEEbP22hb_serialize_context_tT_SN_PKvP16hb_subset_plan_tb
Unexecuted instantiation: hb-static.cc:_ZN2OT4cmap9serializeI16hb_filter_iter_tI17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS0_6subsetEP19hb_subset_context_tEUlS5_E_RK4$_10LPv0EES2_IS3_IKNS_14EncodingRecordEEZNKS0_6subsetES9_EUlRSH_E_SD_LSE_0EETnPN12hb_enable_ifIXsr17hb_is_iterator_ofIT0_NSN_6item_tEEE5valueEvE4typeELSE_0EEEbP22hb_serialize_context_tT_SN_PKvP16hb_subset_plan_tb
1731
1732
  template<typename Iterator, typename EncodingRecordIterator,
1733
      hb_requires (hb_is_iterator (Iterator)),
1734
      hb_requires (hb_is_iterator (EncodingRecordIterator))>
1735
  bool _can_drop (const EncodingRecord& cmap12,
1736
                  const hb_set_t& cmap12_unicodes,
1737
                  const void* base,
1738
                  const SubtableUnicodesCache& unicodes_cache,
1739
                  SubtableUnicodesCache& local_unicodes_cache,
1740
                  Iterator subset_unicodes,
1741
                  EncodingRecordIterator encoding_records)
1742
0
  {
1743
0
    for (auto cp : + subset_unicodes | hb_filter (cmap12_unicodes))
1744
0
    {
1745
0
      if (cp >= 0x10000) return false;
1746
0
    }
1747
0
1748
0
    unsigned target_platform;
1749
0
    unsigned target_encoding;
1750
0
    unsigned target_language = (base+cmap12.subtable).get_language ();
1751
0
1752
0
    if (cmap12.platformID == 0 && cmap12.encodingID == 4)
1753
0
    {
1754
0
      target_platform = 0;
1755
0
      target_encoding = 3;
1756
0
    } else if (cmap12.platformID == 3 && cmap12.encodingID == 10) {
1757
0
      target_platform = 3;
1758
0
      target_encoding = 1;
1759
0
    } else {
1760
0
      return false;
1761
0
    }
1762
0
1763
0
    for (const auto& _ : encoding_records)
1764
0
    {
1765
0
      if (_.platformID != target_platform
1766
0
          || _.encodingID != target_encoding
1767
0
          || (base+_.subtable).get_language() != target_language)
1768
0
        continue;
1769
0
1770
0
      const hb_set_t* sibling_unicodes = unicodes_cache.set_for (&_, local_unicodes_cache);
1771
0
1772
0
      auto cmap12 = + subset_unicodes | hb_filter (cmap12_unicodes);
1773
0
      auto sibling = + subset_unicodes | hb_filter (*sibling_unicodes);
1774
0
      for (; cmap12 && sibling; cmap12++, sibling++)
1775
0
      {
1776
0
        unsigned a = *cmap12;
1777
0
        unsigned b = *sibling;
1778
0
        if (a != b) return false;
1779
0
      }
1780
0
1781
0
      return !cmap12 && !sibling;
1782
0
    }
1783
0
1784
0
    return false;
1785
0
  }
Unexecuted instantiation: hb-face.cc:_ZN2OT4cmap9_can_dropI13hb_map_iter_tI16hb_filter_iter_tI17hb_sorted_array_tIK9hb_pair_tIjjEEZNKS0_6subsetEP19hb_subset_context_tEUlS6_E_RK4$_10LPv0EERK3$_5L24hb_function_sortedness_t0ELSF_0EES3_IS4_IKNS_14EncodingRecordEEZNKS0_6subsetESA_EUlRSN_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_tEUlS6_E_RK4$_11LPv0EERK3$_5L24hb_function_sortedness_t0ELSF_0EES3_IS4_IKNS_14EncodingRecordEEZNKS0_6subsetESA_EUlRSN_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_tEUlS6_E_RK4$_10LPv0EERK3$_5L24hb_function_sortedness_t0ELSF_0EES3_IS4_IKNS_14EncodingRecordEEZNKS0_6subsetESA_EUlRSN_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_tEUlS6_E_RK4$_10LPv0EERK3$_5L24hb_function_sortedness_t0ELSF_0EES3_IS4_IKNS_14EncodingRecordEEZNKS0_6subsetESA_EUlRSN_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_
1786
1787
  void closure_glyphs (const hb_set_t      *unicodes,
1788
           hb_set_t            *glyphset) const
1789
0
  {
1790
0
    + hb_iter (encodingRecord)
1791
0
    | hb_map (&EncodingRecord::subtable)
1792
0
    | hb_map (hb_add (this))
1793
0
    | hb_filter ([&] (const CmapSubtable& _) { return _.u.format == 14; })
1794
0
    | hb_apply ([=] (const CmapSubtable& _) { _.u.format14.closure_glyphs (unicodes, glyphset); })
1795
0
    ;
1796
0
  }
1797
1798
  bool subset (hb_subset_context_t *c) const
1799
0
  {
1800
0
    TRACE_SUBSET (this);
1801
0
1802
0
    cmap *cmap_prime = c->serializer->start_embed<cmap> ();
1803
0
1804
0
    auto encodingrec_iter =
1805
0
    + hb_iter (encodingRecord)
1806
0
    | hb_filter ([&](const EncodingRecord& _) {
1807
0
      return cmap::filter_encoding_records_for_subset (this, _);
1808
0
    })
1809
0
    ;
1810
0
1811
0
    if (unlikely (!encodingrec_iter.len ())) return_trace (false);
1812
0
1813
0
    const EncodingRecord *unicode_bmp= nullptr, *unicode_ucs4 = nullptr, *ms_bmp = nullptr, *ms_ucs4 = nullptr;
1814
0
    bool has_format12 = false;
1815
0
1816
0
    for (const EncodingRecord& _ : encodingrec_iter)
1817
0
    {
1818
0
      unsigned format = (this + _.subtable).u.format;
1819
0
      if (format == 12) has_format12 = true;
1820
0
1821
0
      const EncodingRecord *table = std::addressof (_);
1822
0
      if      (_.platformID == 0 && _.encodingID ==  3) unicode_bmp = table;
1823
0
      else if (_.platformID == 0 && _.encodingID ==  4) unicode_ucs4 = table;
1824
0
      else if (_.platformID == 3 && _.encodingID ==  1) ms_bmp = table;
1825
0
      else if (_.platformID == 3 && _.encodingID == 10) ms_ucs4 = table;
1826
0
    }
1827
0
1828
0
    if (unlikely (!has_format12 && !unicode_bmp && !ms_bmp)) return_trace (false);
1829
0
    if (unlikely (has_format12 && (!unicode_ucs4 && !ms_ucs4))) return_trace (false);
1830
0
1831
0
    auto it =
1832
0
    + c->plan->unicode_to_new_gid_list.iter ()
1833
0
    | hb_filter ([&] (const hb_codepoint_pair_t _)
1834
0
     { return (_.second != HB_MAP_VALUE_INVALID); })
1835
0
    ;
1836
0
1837
0
    return_trace (cmap_prime->serialize (c->serializer,
1838
0
                                         it,
1839
0
                                         encodingrec_iter,
1840
0
                                         this,
1841
0
                                         c->plan));
1842
0
  }
1843
1844
  const CmapSubtable *find_best_subtable (bool *symbol = nullptr,
1845
            bool *mac = nullptr,
1846
            bool *macroman = nullptr) const
1847
0
  {
1848
0
    if (symbol) *symbol = false;
1849
0
    if (mac) *mac = false;
1850
0
    if (macroman) *macroman = false;
1851
1852
0
    const CmapSubtable *subtable;
1853
1854
    /* Symbol subtable.
1855
     * Prefer symbol if available.
1856
     * https://github.com/harfbuzz/harfbuzz/issues/1918 */
1857
0
    if ((subtable = this->find_subtable (3, 0)))
1858
0
    {
1859
0
      if (symbol) *symbol = true;
1860
0
      return subtable;
1861
0
    }
1862
1863
    /* 32-bit subtables. */
1864
0
    if ((subtable = this->find_subtable (3, 10))) return subtable;
1865
0
    if ((subtable = this->find_subtable (0, 6))) return subtable;
1866
0
    if ((subtable = this->find_subtable (0, 4))) return subtable;
1867
1868
    /* 16-bit subtables. */
1869
0
    if ((subtable = this->find_subtable (3, 1))) return subtable;
1870
0
    if ((subtable = this->find_subtable (0, 3))) return subtable;
1871
0
    if ((subtable = this->find_subtable (0, 2))) return subtable;
1872
0
    if ((subtable = this->find_subtable (0, 1))) return subtable;
1873
0
    if ((subtable = this->find_subtable (0, 0))) return subtable;
1874
1875
    /* MacRoman subtable. */
1876
0
    if ((subtable = this->find_subtable (1, 0)))
1877
0
    {
1878
0
      if (mac) *mac = true;
1879
0
      if (macroman) *macroman = true;
1880
0
      return subtable;
1881
0
    }
1882
    /* Any other Mac subtable; we just map ASCII for these. */
1883
0
    if ((subtable = this->find_subtable (1, 0xFFFF)))
1884
0
    {
1885
0
      if (mac) *mac = true;
1886
0
      return subtable;
1887
0
    }
1888
1889
    /* Meh. */
1890
0
    return &Null (CmapSubtable);
1891
0
  }
1892
1893
  struct accelerator_t
1894
  {
1895
    using cache_t = hb_cache_t<21, 16, 8, true>;
1896
1897
    accelerator_t (hb_face_t *face)
1898
0
    {
1899
0
      this->table = hb_sanitize_context_t ().reference_table<cmap> (face);
1900
0
      bool symbol, mac, macroman;
1901
0
      this->subtable = table->find_best_subtable (&symbol, &mac, &macroman);
1902
0
      this->subtable_uvs = &Null (CmapSubtableFormat14);
1903
0
      {
1904
0
  const CmapSubtable *st = table->find_subtable (0, 5);
1905
0
  if (st && st->u.format == 14)
1906
0
    subtable_uvs = &st->u.format14;
1907
0
      }
1908
1909
0
      this->get_glyph_data = subtable;
1910
0
#ifndef HB_NO_CMAP_LEGACY_SUBTABLES
1911
0
      if (unlikely (symbol))
1912
0
      {
1913
0
  switch ((unsigned) face->table.OS2->get_font_page ()) {
1914
0
  case OS2::font_page_t::FONT_PAGE_NONE:
1915
0
    this->get_glyph_funcZ = get_glyph_from_symbol<CmapSubtable, _hb_symbol_pua_map>;
1916
0
    break;
1917
0
#ifndef HB_NO_OT_SHAPER_ARABIC_FALLBACK
1918
0
  case OS2::font_page_t::FONT_PAGE_SIMP_ARABIC:
1919
0
    this->get_glyph_funcZ = get_glyph_from_symbol<CmapSubtable, _hb_arabic_pua_simp_map>;
1920
0
    break;
1921
0
  case OS2::font_page_t::FONT_PAGE_TRAD_ARABIC:
1922
0
    this->get_glyph_funcZ = get_glyph_from_symbol<CmapSubtable, _hb_arabic_pua_trad_map>;
1923
0
    break;
1924
0
#endif
1925
0
  default:
1926
0
    this->get_glyph_funcZ = get_glyph_from<CmapSubtable>;
1927
0
    break;
1928
0
  }
1929
0
      }
1930
0
      else if (unlikely (macroman))
1931
0
      {
1932
0
  this->get_glyph_funcZ = get_glyph_from_macroman<CmapSubtable>;
1933
0
      }
1934
0
      else if (unlikely (mac))
1935
0
      {
1936
0
  this->get_glyph_funcZ = get_glyph_from_ascii<CmapSubtable>;
1937
0
      }
1938
0
      else
1939
0
#endif
1940
0
      {
1941
0
  switch (subtable->u.format) {
1942
  /* Accelerate format 4 and format 12. */
1943
0
  default:
1944
0
    this->get_glyph_funcZ = get_glyph_from<CmapSubtable>;
1945
0
    break;
1946
0
  case 12:
1947
0
    this->get_glyph_funcZ = get_glyph_from<CmapSubtableFormat12>;
1948
0
    break;
1949
0
  case  4:
1950
0
  {
1951
0
    this->format4_accel.init (&subtable->u.format4);
1952
0
    this->get_glyph_data = &this->format4_accel;
1953
0
    this->get_glyph_funcZ = this->format4_accel.get_glyph_func;
1954
0
    break;
1955
0
  }
1956
0
  }
1957
0
      }
1958
0
    }
1959
0
    ~accelerator_t () { this->table.destroy (); }
1960
1961
    inline bool _cached_get (hb_codepoint_t unicode,
1962
           hb_codepoint_t *glyph,
1963
           cache_t *cache) const
1964
0
    {
1965
0
      unsigned v;
1966
0
      if (cache && cache->get (unicode, &v))
1967
0
      {
1968
0
        *glyph = v;
1969
0
  return true;
1970
0
      }
1971
0
      bool ret  = this->get_glyph_funcZ (this->get_glyph_data, unicode, glyph);
1972
1973
0
      if (cache && ret)
1974
0
        cache->set (unicode, *glyph);
1975
0
      return ret;
1976
0
    }
1977
1978
    bool get_nominal_glyph (hb_codepoint_t  unicode,
1979
          hb_codepoint_t *glyph,
1980
          cache_t *cache = nullptr) const
1981
0
    {
1982
0
      if (unlikely (!this->get_glyph_funcZ)) return false;
1983
0
      return _cached_get (unicode, glyph, cache);
1984
0
    }
1985
1986
    unsigned int get_nominal_glyphs (unsigned int count,
1987
             const hb_codepoint_t *first_unicode,
1988
             unsigned int unicode_stride,
1989
             hb_codepoint_t *first_glyph,
1990
             unsigned int glyph_stride,
1991
             cache_t *cache = nullptr) const
1992
0
    {
1993
0
      if (unlikely (!this->get_glyph_funcZ)) return 0;
1994
1995
0
      unsigned int done;
1996
0
      for (done = 0;
1997
0
     done < count && _cached_get (*first_unicode, first_glyph, cache);
1998
0
     done++)
1999
0
      {
2000
0
  first_unicode = &StructAtOffsetUnaligned<hb_codepoint_t> (first_unicode, unicode_stride);
2001
0
  first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
2002
0
      }
2003
0
      return done;
2004
0
    }
2005
2006
    bool get_variation_glyph (hb_codepoint_t  unicode,
2007
            hb_codepoint_t  variation_selector,
2008
            hb_codepoint_t *glyph,
2009
            cache_t *cache = nullptr) const
2010
0
    {
2011
0
      switch (this->subtable_uvs->get_glyph_variant (unicode,
2012
0
                 variation_selector,
2013
0
                 glyph))
2014
0
      {
2015
0
  case GLYPH_VARIANT_NOT_FOUND: return false;
2016
0
  case GLYPH_VARIANT_FOUND: return true;
2017
0
  case GLYPH_VARIANT_USE_DEFAULT: break;
2018
0
      }
2019
2020
0
      return get_nominal_glyph (unicode, glyph, cache);
2021
0
    }
2022
2023
    void collect_unicodes (hb_set_t *out, unsigned int num_glyphs) const
2024
0
    { subtable->collect_unicodes (out, num_glyphs); }
2025
    void collect_mapping (hb_set_t *unicodes, hb_map_t *mapping,
2026
        unsigned num_glyphs = UINT_MAX) const
2027
0
    { subtable->collect_mapping (unicodes, mapping, num_glyphs); }
2028
    void collect_variation_selectors (hb_set_t *out) const
2029
0
    { subtable_uvs->collect_variation_selectors (out); }
2030
    void collect_variation_unicodes (hb_codepoint_t variation_selector,
2031
             hb_set_t *out) const
2032
0
    { subtable_uvs->collect_variation_unicodes (variation_selector, out); }
2033
2034
    protected:
2035
    typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj,
2036
                hb_codepoint_t codepoint,
2037
                hb_codepoint_t *glyph);
2038
    typedef uint_fast16_t (*hb_pua_remap_func_t) (unsigned);
2039
2040
    template <typename Type>
2041
    HB_INTERNAL static bool get_glyph_from (const void *obj,
2042
              hb_codepoint_t codepoint,
2043
              hb_codepoint_t *glyph)
2044
0
    {
2045
0
      const Type *typed_obj = (const Type *) obj;
2046
0
      return typed_obj->get_glyph (codepoint, glyph);
2047
0
    }
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*)
2048
2049
    template <typename Type, hb_pua_remap_func_t remap>
2050
    HB_INTERNAL static bool get_glyph_from_symbol (const void *obj,
2051
               hb_codepoint_t codepoint,
2052
               hb_codepoint_t *glyph)
2053
0
    {
2054
0
      const Type *typed_obj = (const Type *) obj;
2055
0
      if (likely (typed_obj->get_glyph (codepoint, glyph)))
2056
0
  return true;
2057
2058
0
      if (hb_codepoint_t c = remap (codepoint))
2059
0
  return typed_obj->get_glyph (c, glyph);
2060
2061
0
      return false;
2062
0
    }
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::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::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::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::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::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::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::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::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::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::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::CmapSubtable, &(_hb_arabic_pua_trad_map(unsigned int))>(void const*, unsigned int, unsigned int*)
2063
2064
    template <typename Type>
2065
    HB_INTERNAL static bool get_glyph_from_ascii (const void *obj,
2066
              hb_codepoint_t codepoint,
2067
              hb_codepoint_t *glyph)
2068
0
    {
2069
0
      const Type *typed_obj = (const Type *) obj;
2070
0
      return codepoint < 0x80 && typed_obj->get_glyph (codepoint, glyph);
2071
0
    }
2072
2073
    template <typename Type>
2074
    HB_INTERNAL static bool get_glyph_from_macroman (const void *obj,
2075
                 hb_codepoint_t codepoint,
2076
                 hb_codepoint_t *glyph)
2077
0
    {
2078
0
      if (get_glyph_from_ascii<Type> (obj, codepoint, glyph))
2079
0
  return true;
2080
2081
0
      const Type *typed_obj = (const Type *) obj;
2082
0
      unsigned c = unicode_to_macroman (codepoint);
2083
0
      return c && typed_obj->get_glyph (c, glyph);
2084
0
    }
2085
2086
    private:
2087
    hb_nonnull_ptr_t<const CmapSubtable> subtable;
2088
    hb_nonnull_ptr_t<const CmapSubtableFormat14> subtable_uvs;
2089
2090
    hb_cmap_get_glyph_func_t get_glyph_funcZ;
2091
    const void *get_glyph_data;
2092
2093
    CmapSubtableFormat4::accelerator_t format4_accel;
2094
2095
    public:
2096
    hb_blob_ptr_t<cmap> table;
2097
  };
2098
2099
  protected:
2100
2101
  const CmapSubtable *find_subtable (unsigned int platform_id,
2102
             unsigned int encoding_id) const
2103
0
  {
2104
0
    EncodingRecord key;
2105
0
    key.platformID = platform_id;
2106
0
    key.encodingID = encoding_id;
2107
2108
0
    const EncodingRecord &result = encodingRecord.bsearch (key);
2109
0
    if (!result.subtable)
2110
0
      return nullptr;
2111
2112
0
    return &(this+result.subtable);
2113
0
  }
2114
2115
  public:
2116
2117
  bool sanitize (hb_sanitize_context_t *c) const
2118
0
  {
2119
0
    TRACE_SANITIZE (this);
2120
0
    return_trace (c->check_struct (this) &&
2121
0
      hb_barrier () &&
2122
0
      likely (version == 0) &&
2123
0
      encodingRecord.sanitize (c, this));
2124
0
  }
2125
2126
 private:
2127
2128
  static bool filter_encoding_records_for_subset(const cmap* cmap,
2129
                                                 const EncodingRecord& _)
2130
0
  {
2131
0
    return
2132
0
        (_.platformID == 0 && _.encodingID == 3) ||
2133
0
        (_.platformID == 0 && _.encodingID == 4) ||
2134
0
        (_.platformID == 3 && _.encodingID == 1) ||
2135
0
        (_.platformID == 3 && _.encodingID == 10) ||
2136
0
        (cmap + _.subtable).u.format == 14;
2137
0
  }
2138
2139
  protected:
2140
  HBUINT16  version;  /* Table version number (0). */
2141
  SortedArray16Of<EncodingRecord>
2142
    encodingRecord; /* Encoding tables. */
2143
  public:
2144
  DEFINE_SIZE_ARRAY (4, encodingRecord);
2145
};
2146
2147
struct cmap_accelerator_t : cmap::accelerator_t {
2148
0
  cmap_accelerator_t (hb_face_t *face) : cmap::accelerator_t (face) {}
2149
};
2150
2151
} /* namespace OT */
2152
2153
2154
#endif /* HB_OT_CMAP_TABLE_HH */