Coverage Report

Created: 2026-11-06 11:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/workdir/UnpackedTarball/harfbuzz/src/hb-ot-cff2-table.hh
Line
Count
Source
1
/*
2
 * Copyright © 2018 Adobe 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
 * Adobe Author(s): Michiharu Ariza
25
 */
26
27
#ifndef HB_OT_CFF2_TABLE_HH
28
#define HB_OT_CFF2_TABLE_HH
29
30
#include "hb-ot-cff-common.hh"
31
#include "hb-subset-cff-common.hh"
32
#include "hb-draw.hh"
33
#include "hb-paint.hh"
34
35
namespace CFF {
36
37
/*
38
 * CFF2 -- Compact Font Format (CFF) Version 2
39
 * https://docs.microsoft.com/en-us/typography/opentype/spec/cff2
40
 */
41
#define HB_OT_TAG_CFF2 HB_TAG('C','F','F','2')
42
43
typedef CFF2Index         CFF2CharStrings;
44
typedef Subrs<HBUINT32>   CFF2Subrs;
45
46
typedef FDSelect3_4<HBUINT32, HBUINT16> FDSelect4;
47
typedef FDSelect3_4_Range<HBUINT32, HBUINT16> FDSelect4_Range;
48
49
struct CFF2FDSelect
50
{
51
  bool serialize (hb_serialize_context_t *c, const CFF2FDSelect &src, unsigned int num_glyphs)
52
0
  {
53
0
    TRACE_SERIALIZE (this);
54
0
    unsigned int size = src.get_size (num_glyphs);
55
0
    CFF2FDSelect *dest = c->allocate_size<CFF2FDSelect> (size);
56
0
    if (unlikely (!dest)) return_trace (false);
57
0
    hb_memcpy (dest, &src, size);
58
0
    return_trace (true);
59
0
  }
60
61
  size_t get_size (unsigned int num_glyphs) const
62
0
  {
63
0
    switch (format)
64
0
    {
65
0
    case 0: hb_barrier (); return format.static_size + u.format0.get_size (num_glyphs);
66
0
    case 3: hb_barrier (); return format.static_size + u.format3.get_size ();
67
0
    case 4: hb_barrier (); return format.static_size + u.format4.get_size ();
68
0
    default:return 0;
69
0
    }
70
0
  }
71
72
  hb_codepoint_t get_fd (hb_codepoint_t glyph) const
73
0
  {
74
0
    if (this == &Null (CFF2FDSelect))
75
0
      return 0;
76
77
0
    switch (format)
78
0
    {
79
0
    case 0: hb_barrier (); return u.format0.get_fd (glyph);
80
0
    case 3: hb_barrier (); return u.format3.get_fd (glyph);
81
0
    case 4: hb_barrier (); return u.format4.get_fd (glyph);
82
0
    default:return 0;
83
0
    }
84
0
  }
85
86
  bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount,
87
                 unsigned int charstring_count = HB_CODEPOINT_INVALID) const
88
0
  {
89
0
    TRACE_SANITIZE (this);
90
0
    if (unlikely (!c->check_struct (this)))
91
0
      return_trace (false);
92
0
    hb_barrier ();
93
94
0
    switch (format)
95
0
    {
96
0
    case 0: hb_barrier (); return_trace (u.format0.sanitize (c, fdcount, charstring_count));
97
0
    case 3: hb_barrier (); return_trace (u.format3.sanitize (c, fdcount, charstring_count));
98
0
    case 4: hb_barrier (); return_trace (u.format4.sanitize (c, fdcount, charstring_count));
99
0
    default:return_trace (false);
100
0
    }
101
0
  }
102
103
  HBUINT8 format;
104
  union {
105
  FDSelect0 format0;
106
  FDSelect3 format3;
107
  FDSelect4 format4;
108
  } u;
109
  public:
110
  DEFINE_SIZE_MIN (2);
111
};
112
113
struct CFF2ItemVariationStore
114
{
115
  bool sanitize (hb_sanitize_context_t *c) const
116
0
  {
117
0
    TRACE_SANITIZE (this);
118
0
    return_trace (c->check_struct (this) &&
119
0
      hb_barrier () &&
120
0
      c->check_range (&varStore, size) &&
121
0
      varStore.sanitize (c));
122
0
  }
123
124
  bool serialize (hb_serialize_context_t *c, const CFF2ItemVariationStore *varStore)
125
0
  {
126
0
    TRACE_SERIALIZE (this);
127
0
    unsigned int size_ = varStore->get_size ();
128
0
    CFF2ItemVariationStore *dest = c->allocate_size<CFF2ItemVariationStore> (size_);
129
0
    if (unlikely (!dest)) return_trace (false);
130
0
    hb_memcpy (dest, varStore, size_);
131
0
    return_trace (true);
132
0
  }
133
134
0
  size_t get_size () const { return HBUINT16::static_size + size; }
135
136
  HBUINT16  size;
137
  ItemVariationStore  varStore;
138
139
  DEFINE_SIZE_MIN (2 + ItemVariationStore::min_size);
140
};
141
142
struct cff2_top_dict_values_t : top_dict_values_t<>
143
{
144
  void init ()
145
4
  {
146
4
    top_dict_values_t<>::init ();
147
4
    vstoreOffset = 0;
148
4
    FDSelectOffset = 0;
149
4
  }
150
4
  void fini () { top_dict_values_t<>::fini (); }
151
152
  int  vstoreOffset;
153
  int  FDSelectOffset;
154
};
155
156
struct cff2_top_dict_opset_t : top_dict_opset_t<>
157
{
158
  static void process_op (op_code_t op, num_interp_env_t& env, cff2_top_dict_values_t& dictval)
159
0
  {
160
0
    switch (op) {
161
0
      case OpCode_FontMatrix:
162
0
  {
163
0
    dict_val_t val;
164
0
    val.init ();
165
0
    dictval.add_op (op, env.str_ref);
166
0
    env.clear_args ();
167
0
  }
168
0
  break;
169
170
0
      case OpCode_vstore:
171
0
  dictval.vstoreOffset = env.argStack.pop_int ();
172
0
  env.clear_args ();
173
0
  break;
174
0
      case OpCode_FDSelect:
175
0
  dictval.FDSelectOffset = env.argStack.pop_int ();
176
0
  env.clear_args ();
177
0
  break;
178
179
0
      default:
180
0
  SUPER::process_op (op, env, dictval);
181
  /* Record this operand below if stack is empty, otherwise done */
182
0
  if (!env.argStack.is_empty ()) return;
183
0
    }
184
185
0
    if (unlikely (env.in_error ())) return;
186
187
0
    dictval.add_op (op, env.str_ref);
188
0
  }
189
190
  typedef top_dict_opset_t<> SUPER;
191
};
192
193
struct cff2_font_dict_values_t : dict_values_t<op_str_t>
194
{
195
  void init ()
196
0
  {
197
0
    dict_values_t<op_str_t>::init ();
198
0
    privateDictInfo.init ();
199
0
  }
200
0
  void fini () { dict_values_t<op_str_t>::fini (); }
201
202
  table_info_t    privateDictInfo;
203
};
204
205
struct cff2_font_dict_opset_t : dict_opset_t
206
{
207
  static void process_op (op_code_t op, num_interp_env_t& env, cff2_font_dict_values_t& dictval)
208
0
  {
209
0
    switch (op) {
210
0
      case OpCode_Private:
211
0
  dictval.privateDictInfo.offset = env.argStack.pop_uint ();
212
0
  dictval.privateDictInfo.size = env.argStack.pop_uint ();
213
0
  env.clear_args ();
214
0
  break;
215
216
0
      default:
217
0
  SUPER::process_op (op, env);
218
0
  if (!env.argStack.is_empty ())
219
0
    return;
220
0
    }
221
222
0
    if (unlikely (env.in_error ())) return;
223
224
0
    dictval.add_op (op, env.str_ref);
225
0
  }
226
227
  private:
228
  typedef dict_opset_t SUPER;
229
};
230
231
template <typename VAL>
232
struct cff2_private_dict_values_base_t : dict_values_t<VAL>
233
{
234
  void init ()
235
0
  {
236
0
    dict_values_t<VAL>::init ();
237
0
    subrsOffset = 0;
238
0
    localSubrs = &Null (CFF2Subrs);
239
0
    ivs = 0;
240
0
  }
Unexecuted instantiation: CFF::cff2_private_dict_values_base_t<CFF::dict_val_t>::init()
Unexecuted instantiation: CFF::cff2_private_dict_values_base_t<CFF::op_str_t>::init()
241
  void fini () { dict_values_t<VAL>::fini (); }
242
243
  int                subrsOffset;
244
  const CFF2Subrs   *localSubrs;
245
  unsigned int      ivs;
246
};
247
248
typedef cff2_private_dict_values_base_t<op_str_t> cff2_private_dict_values_subset_t;
249
typedef cff2_private_dict_values_base_t<num_dict_val_t> cff2_private_dict_values_t;
250
251
struct cff2_priv_dict_interp_env_t : num_interp_env_t
252
{
253
  cff2_priv_dict_interp_env_t (const hb_ubytes_t &str) :
254
0
    num_interp_env_t (str) {}
255
256
  void process_vsindex ()
257
0
  {
258
0
    if (likely (!seen_vsindex))
259
0
    {
260
0
      set_ivs (argStack.pop_uint ());
261
0
    }
262
0
    seen_vsindex = true;
263
0
  }
264
265
0
  unsigned int get_ivs () const { return ivs; }
266
0
  void   set_ivs (unsigned int ivs_) { ivs = ivs_; }
267
268
  protected:
269
  unsigned int  ivs = 0;
270
  bool    seen_vsindex = false;
271
};
272
273
struct cff2_private_dict_opset_t : dict_opset_t
274
{
275
  static void process_op (op_code_t op, cff2_priv_dict_interp_env_t& env, cff2_private_dict_values_t& dictval)
276
0
  {
277
0
    num_dict_val_t val;
278
0
    val.init ();
279
280
0
    switch (op) {
281
0
      case OpCode_StdHW:
282
0
      case OpCode_StdVW:
283
0
      case OpCode_BlueScale:
284
0
      case OpCode_BlueShift:
285
0
      case OpCode_BlueFuzz:
286
0
      case OpCode_ExpansionFactor:
287
0
      case OpCode_LanguageGroup:
288
0
      case OpCode_BlueValues:
289
0
      case OpCode_OtherBlues:
290
0
      case OpCode_FamilyBlues:
291
0
      case OpCode_FamilyOtherBlues:
292
0
      case OpCode_StemSnapH:
293
0
      case OpCode_StemSnapV:
294
0
  env.clear_args ();
295
0
  break;
296
0
      case OpCode_Subrs:
297
0
  dictval.subrsOffset = env.argStack.pop_int ();
298
0
  env.clear_args ();
299
0
  break;
300
0
      case OpCode_vsindexdict:
301
0
  env.process_vsindex ();
302
0
  dictval.ivs = env.get_ivs ();
303
0
  env.clear_args ();
304
0
  break;
305
0
      case OpCode_blenddict:
306
        /* Hint values are ignored here. Discard each group so raw operands
307
         * from successive blends cannot overflow the stack. */
308
0
        env.clear_args ();
309
0
  break;
310
311
0
      default:
312
0
  dict_opset_t::process_op (op, env);
313
0
  if (!env.argStack.is_empty ()) return;
314
0
  break;
315
0
    }
316
317
0
    if (unlikely (env.in_error ())) return;
318
319
0
    dictval.add_op (op, env.str_ref, val);
320
0
  }
321
};
322
323
struct cff2_private_dict_opset_subset_t : dict_opset_t
324
{
325
  static void process_op (op_code_t op, cff2_priv_dict_interp_env_t& env, cff2_private_dict_values_subset_t& dictval)
326
0
  {
327
0
    switch (op) {
328
0
      case OpCode_BlueValues:
329
0
      case OpCode_OtherBlues:
330
0
      case OpCode_FamilyBlues:
331
0
      case OpCode_FamilyOtherBlues:
332
0
      case OpCode_StdHW:
333
0
      case OpCode_StdVW:
334
0
      case OpCode_BlueScale:
335
0
      case OpCode_BlueShift:
336
0
      case OpCode_BlueFuzz:
337
0
      case OpCode_StemSnapH:
338
0
      case OpCode_StemSnapV:
339
0
      case OpCode_LanguageGroup:
340
0
      case OpCode_ExpansionFactor:
341
0
  env.clear_args ();
342
0
  break;
343
344
0
      case OpCode_blenddict:
345
0
  env.clear_args ();
346
0
  return;
347
348
0
      case OpCode_Subrs:
349
0
  dictval.subrsOffset = env.argStack.pop_int ();
350
0
  env.clear_args ();
351
0
  break;
352
353
0
      case OpCode_vsindexdict:
354
0
  env.process_vsindex ();
355
0
  dictval.ivs = env.get_ivs ();
356
0
  env.clear_args ();
357
0
  break;
358
359
0
      default:
360
0
  SUPER::process_op (op, env);
361
0
  if (!env.argStack.is_empty ()) return;
362
0
  break;
363
0
    }
364
365
0
    if (unlikely (env.in_error ())) return;
366
367
0
    dictval.add_op (op, env.str_ref);
368
0
  }
369
370
  private:
371
  typedef dict_opset_t SUPER;
372
};
373
374
typedef dict_interpreter_t<cff2_top_dict_opset_t, cff2_top_dict_values_t> cff2_top_dict_interpreter_t;
375
typedef dict_interpreter_t<cff2_font_dict_opset_t, cff2_font_dict_values_t> cff2_font_dict_interpreter_t;
376
377
struct CFF2FDArray : FDArray<HBUINT32>
378
{
379
  /* FDArray::serialize does not compile without this partial specialization */
380
  template <typename ITER, typename OP_SERIALIZER>
381
  bool serialize (hb_serialize_context_t *c, ITER it, OP_SERIALIZER& opszr)
382
0
  { return FDArray<HBUINT32>::serialize<cff2_font_dict_values_t, table_info_t> (c, it, opszr); }
383
};
384
385
} /* namespace CFF */
386
387
namespace OT {
388
389
using namespace CFF;
390
391
struct cff2
392
{
393
  static constexpr hb_tag_t tableTag = HB_OT_TAG_CFF2;
394
395
  bool sanitize (hb_sanitize_context_t *c) const
396
0
  {
397
0
    TRACE_SANITIZE (this);
398
0
    return_trace (c->check_struct (this) &&
399
0
      hb_barrier () &&
400
0
      likely (version.major == 2));
401
0
  }
402
403
  template <typename PRIVOPSET, typename PRIVDICTVAL>
404
  struct accelerator_templ_t
405
  {
406
    static constexpr hb_tag_t tableTag = cff2::tableTag;
407
408
    accelerator_templ_t (hb_face_t *face)
409
4
    {
410
4
      if (!face) return;
411
412
4
      topDict.init ();
413
4
      fontDicts.init ();
414
4
      privateDicts.init ();
415
416
4
      this->blob = sc.reference_table<cff2> (face);
417
418
      /* setup for run-time sanitization */
419
4
      sc.init (this->blob);
420
4
      sc.start_processing ();
421
422
4
      const OT::cff2 *cff2 = this->blob->template as<OT::cff2> ();
423
424
4
      if (cff2 == &Null (OT::cff2))
425
4
        goto fail;
426
427
0
      { /* parse top dict */
428
0
  hb_ubytes_t topDictStr = (cff2 + cff2->topDict).as_ubytes (cff2->topDictSize);
429
0
  if (unlikely (!topDictStr.sanitize (&sc))) goto fail;
430
0
  hb_barrier ();
431
0
  num_interp_env_t env (topDictStr);
432
0
  cff2_top_dict_interpreter_t top_interp (env);
433
0
  topDict.init ();
434
0
  if (unlikely (!top_interp.interpret (topDict))) goto fail;
435
0
      }
436
437
0
      globalSubrs = &StructAtOffsetOrNull<CFF2Subrs> (cff2, cff2->topDict + cff2->topDictSize, sc);
438
0
      varStore = &StructAtOffsetOrNull<CFF2ItemVariationStore> (cff2, topDict.vstoreOffset, sc);
439
0
      charStrings = &StructAtOffsetOrNull<CFF2CharStrings> (cff2, topDict.charStringsOffset, sc);
440
0
      fdArray = &StructAtOffsetOrNull<CFF2FDArray> (cff2, topDict.FDArrayOffset, sc);
441
442
0
      if (charStrings == &Null (CFF2CharStrings) ||
443
0
    globalSubrs == &Null (CFF2Subrs) ||
444
0
    fdArray == &Null (CFF2FDArray))
445
0
        goto fail;
446
447
0
      num_glyphs = charStrings->count;
448
0
      if (num_glyphs != sc.get_num_glyphs ())
449
0
      {
450
        /* VARC can define glyphs beyond the CFF2 CharStrings INDEX. */
451
0
        hb_blob_t *varc = face->reference_table (HB_TAG ('V','A','R','C'));
452
0
        bool valid_count = num_glyphs < sc.get_num_glyphs () &&
453
0
                           hb_blob_get_length (varc);
454
0
        hb_blob_destroy (varc);
455
0
        if (!valid_count) goto fail;
456
0
      }
457
458
0
      fdSelect = &StructAtOffsetOrNull<CFF2FDSelect> (cff2, topDict.FDSelectOffset, sc,
459
0
                                                   fdArray->count, num_glyphs);
460
0
      if (topDict.FDSelectOffset && fdSelect == &Null (CFF2FDSelect))
461
0
        goto fail;
462
463
0
      fdCount = fdArray->count;
464
0
      if (!privateDicts.resize (fdCount))
465
0
        goto fail;
466
467
      /* parse font dicts and gather private dicts */
468
0
      for (unsigned int i = 0; i < fdCount; i++)
469
0
      {
470
0
  const hb_ubytes_t fontDictStr = (*fdArray)[i];
471
0
  if (unlikely (!fontDictStr.sanitize (&sc))) goto fail;
472
0
  hb_barrier ();
473
0
  cff2_font_dict_values_t  *font;
474
0
  num_interp_env_t env (fontDictStr);
475
0
  cff2_font_dict_interpreter_t font_interp (env);
476
0
  font = fontDicts.push ();
477
0
  if (unlikely (font == &Crap (cff2_font_dict_values_t))) goto fail;
478
0
  font->init ();
479
0
  if (unlikely (!font_interp.interpret (*font))) goto fail;
480
481
0
  const hb_ubytes_t privDictStr = StructAtOffsetOrNull<UnsizedByteStr> (cff2, font->privateDictInfo.offset, sc, font->privateDictInfo.size).as_ubytes (font->privateDictInfo.size);
482
0
  if (unlikely (font->privateDictInfo.size &&
483
0
          privDictStr == (const unsigned char *) &Null (UnsizedByteStr))) goto fail;
484
0
  cff2_priv_dict_interp_env_t env2 (privDictStr);
485
0
  dict_interpreter_t<PRIVOPSET, PRIVDICTVAL, cff2_priv_dict_interp_env_t> priv_interp (env2);
486
0
  privateDicts[i].init ();
487
0
  if (unlikely (!priv_interp.interpret (privateDicts[i]))) goto fail;
488
489
0
  privateDicts[i].localSubrs = &StructAtOffsetOrNull<CFF2Subrs> (&privDictStr[0], privateDicts[i].subrsOffset, sc);
490
0
      }
491
492
0
      return;
493
494
4
      fail:
495
4
        _fini ();
496
4
    }
OT::cff2::accelerator_templ_t<CFF::cff2_private_dict_opset_t, CFF::cff2_private_dict_values_base_t<CFF::dict_val_t> >::accelerator_templ_t(hb_face_t*)
Line
Count
Source
409
4
    {
410
4
      if (!face) return;
411
412
4
      topDict.init ();
413
4
      fontDicts.init ();
414
4
      privateDicts.init ();
415
416
4
      this->blob = sc.reference_table<cff2> (face);
417
418
      /* setup for run-time sanitization */
419
4
      sc.init (this->blob);
420
4
      sc.start_processing ();
421
422
4
      const OT::cff2 *cff2 = this->blob->template as<OT::cff2> ();
423
424
4
      if (cff2 == &Null (OT::cff2))
425
4
        goto fail;
426
427
0
      { /* parse top dict */
428
0
  hb_ubytes_t topDictStr = (cff2 + cff2->topDict).as_ubytes (cff2->topDictSize);
429
0
  if (unlikely (!topDictStr.sanitize (&sc))) goto fail;
430
0
  hb_barrier ();
431
0
  num_interp_env_t env (topDictStr);
432
0
  cff2_top_dict_interpreter_t top_interp (env);
433
0
  topDict.init ();
434
0
  if (unlikely (!top_interp.interpret (topDict))) goto fail;
435
0
      }
436
437
0
      globalSubrs = &StructAtOffsetOrNull<CFF2Subrs> (cff2, cff2->topDict + cff2->topDictSize, sc);
438
0
      varStore = &StructAtOffsetOrNull<CFF2ItemVariationStore> (cff2, topDict.vstoreOffset, sc);
439
0
      charStrings = &StructAtOffsetOrNull<CFF2CharStrings> (cff2, topDict.charStringsOffset, sc);
440
0
      fdArray = &StructAtOffsetOrNull<CFF2FDArray> (cff2, topDict.FDArrayOffset, sc);
441
442
0
      if (charStrings == &Null (CFF2CharStrings) ||
443
0
    globalSubrs == &Null (CFF2Subrs) ||
444
0
    fdArray == &Null (CFF2FDArray))
445
0
        goto fail;
446
447
0
      num_glyphs = charStrings->count;
448
0
      if (num_glyphs != sc.get_num_glyphs ())
449
0
      {
450
        /* VARC can define glyphs beyond the CFF2 CharStrings INDEX. */
451
0
        hb_blob_t *varc = face->reference_table (HB_TAG ('V','A','R','C'));
452
0
        bool valid_count = num_glyphs < sc.get_num_glyphs () &&
453
0
                           hb_blob_get_length (varc);
454
0
        hb_blob_destroy (varc);
455
0
        if (!valid_count) goto fail;
456
0
      }
457
458
0
      fdSelect = &StructAtOffsetOrNull<CFF2FDSelect> (cff2, topDict.FDSelectOffset, sc,
459
0
                                                   fdArray->count, num_glyphs);
460
0
      if (topDict.FDSelectOffset && fdSelect == &Null (CFF2FDSelect))
461
0
        goto fail;
462
463
0
      fdCount = fdArray->count;
464
0
      if (!privateDicts.resize (fdCount))
465
0
        goto fail;
466
467
      /* parse font dicts and gather private dicts */
468
0
      for (unsigned int i = 0; i < fdCount; i++)
469
0
      {
470
0
  const hb_ubytes_t fontDictStr = (*fdArray)[i];
471
0
  if (unlikely (!fontDictStr.sanitize (&sc))) goto fail;
472
0
  hb_barrier ();
473
0
  cff2_font_dict_values_t  *font;
474
0
  num_interp_env_t env (fontDictStr);
475
0
  cff2_font_dict_interpreter_t font_interp (env);
476
0
  font = fontDicts.push ();
477
0
  if (unlikely (font == &Crap (cff2_font_dict_values_t))) goto fail;
478
0
  font->init ();
479
0
  if (unlikely (!font_interp.interpret (*font))) goto fail;
480
481
0
  const hb_ubytes_t privDictStr = StructAtOffsetOrNull<UnsizedByteStr> (cff2, font->privateDictInfo.offset, sc, font->privateDictInfo.size).as_ubytes (font->privateDictInfo.size);
482
0
  if (unlikely (font->privateDictInfo.size &&
483
0
          privDictStr == (const unsigned char *) &Null (UnsizedByteStr))) goto fail;
484
0
  cff2_priv_dict_interp_env_t env2 (privDictStr);
485
0
  dict_interpreter_t<PRIVOPSET, PRIVDICTVAL, cff2_priv_dict_interp_env_t> priv_interp (env2);
486
0
  privateDicts[i].init ();
487
0
  if (unlikely (!priv_interp.interpret (privateDicts[i]))) goto fail;
488
489
0
  privateDicts[i].localSubrs = &StructAtOffsetOrNull<CFF2Subrs> (&privDictStr[0], privateDicts[i].subrsOffset, sc);
490
0
      }
491
492
0
      return;
493
494
4
      fail:
495
4
        _fini ();
496
4
    }
Unexecuted instantiation: OT::cff2::accelerator_templ_t<CFF::cff2_private_dict_opset_subset_t, CFF::cff2_private_dict_values_base_t<CFF::op_str_t> >::accelerator_templ_t(hb_face_t*)
497
0
    ~accelerator_templ_t () { _fini (); }
Unexecuted instantiation: OT::cff2::accelerator_templ_t<CFF::cff2_private_dict_opset_t, CFF::cff2_private_dict_values_base_t<CFF::dict_val_t> >::~accelerator_templ_t()
Unexecuted instantiation: OT::cff2::accelerator_templ_t<CFF::cff2_private_dict_opset_subset_t, CFF::cff2_private_dict_values_base_t<CFF::op_str_t> >::~accelerator_templ_t()
498
    void _fini ()
499
4
    {
500
4
      sc.end_processing ();
501
4
      topDict.fini ();
502
4
      fontDicts.fini ();
503
4
      privateDicts.fini ();
504
4
      hb_blob_destroy (blob);
505
4
      blob = nullptr;
506
507
4
      auto *scalars = cached_scalars_vector.get_acquire ();
508
4
      if (scalars && cached_scalars_vector.cmpexch (scalars, nullptr))
509
0
      {
510
0
  scalars->fini ();
511
0
  hb_free (scalars);
512
0
      }
513
4
    }
OT::cff2::accelerator_templ_t<CFF::cff2_private_dict_opset_t, CFF::cff2_private_dict_values_base_t<CFF::dict_val_t> >::_fini()
Line
Count
Source
499
4
    {
500
4
      sc.end_processing ();
501
4
      topDict.fini ();
502
4
      fontDicts.fini ();
503
4
      privateDicts.fini ();
504
4
      hb_blob_destroy (blob);
505
4
      blob = nullptr;
506
507
4
      auto *scalars = cached_scalars_vector.get_acquire ();
508
4
      if (scalars && cached_scalars_vector.cmpexch (scalars, nullptr))
509
0
      {
510
0
  scalars->fini ();
511
0
  hb_free (scalars);
512
0
      }
513
4
    }
Unexecuted instantiation: OT::cff2::accelerator_templ_t<CFF::cff2_private_dict_opset_subset_t, CFF::cff2_private_dict_values_base_t<CFF::op_str_t> >::_fini()
514
515
    hb_vector_t<uint16_t> *create_glyph_to_sid_map () const
516
    {
517
      return nullptr;
518
    }
519
520
0
    hb_blob_t *get_blob () const { return blob; }
521
522
99.5k
    bool is_valid () const { return blob; }
523
524
    protected:
525
    hb_sanitize_context_t sc;
526
527
    public:
528
    hb_blob_t     *blob = nullptr;
529
    cff2_top_dict_values_t  topDict;
530
    const CFF2Subrs   *globalSubrs = nullptr;
531
    const CFF2ItemVariationStore  *varStore = nullptr;
532
    const CFF2CharStrings *charStrings = nullptr;
533
    const CFF2FDArray   *fdArray = nullptr;
534
    const CFF2FDSelect    *fdSelect = nullptr;
535
    unsigned int    fdCount = 0;
536
537
    hb_vector_t<cff2_font_dict_values_t>     fontDicts;
538
    hb_vector_t<PRIVDICTVAL>  privateDicts;
539
540
    mutable hb_atomic_t<hb_vector_t<float> *> cached_scalars_vector;
541
542
    unsigned int        num_glyphs = 0;
543
  };
544
545
  struct accelerator_t : accelerator_templ_t<cff2_private_dict_opset_t, cff2_private_dict_values_t>
546
  {
547
4
    accelerator_t (hb_face_t *face) : accelerator_templ_t (face) {}
548
549
    HB_INTERNAL bool get_extents (hb_font_t *font,
550
          hb_codepoint_t glyph,
551
          hb_glyph_extents_t *extents) const;
552
    HB_INTERNAL bool get_extents_at (hb_font_t *font,
553
             hb_codepoint_t glyph,
554
             hb_glyph_extents_t *extents,
555
             hb_array_t<const int> coords,
556
             int64_t *budget = nullptr) const;
557
    HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session, int64_t *budget = nullptr) const;
558
    HB_INTERNAL bool get_path_at (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session, hb_array_t<const int> coords, int64_t *budget = nullptr) const;
559
  };
560
561
  struct accelerator_subset_t : accelerator_templ_t<cff2_private_dict_opset_subset_t, cff2_private_dict_values_subset_t>
562
  {
563
0
    accelerator_subset_t (hb_face_t *face) : SUPER (face) {}
564
    ~accelerator_subset_t ()
565
0
    {
566
0
      if (cff_accelerator)
567
0
  cff_subset_accelerator_t::destroy (cff_accelerator);
568
0
    }
569
570
    HB_INTERNAL bool subset (hb_subset_context_t *c) const;
571
    HB_INTERNAL bool serialize (hb_serialize_context_t *c,
572
        struct cff2_subset_plan &plan,
573
        hb_array_t<int> normalized_coords) const;
574
575
    mutable CFF::cff_subset_accelerator_t* cff_accelerator = nullptr;
576
577
    typedef accelerator_templ_t<cff2_private_dict_opset_subset_t, cff2_private_dict_values_subset_t> SUPER;
578
  };
579
580
  public:
581
  FixedVersion<HBUINT8>   version;  /* Version of CFF2 table. set to 0x0200u */
582
  NNOffsetTo<TopDict, HBUINT8>  topDict;  /* headerSize = Offset to Top DICT. */
583
  HBUINT16      topDictSize;  /* Top DICT size */
584
585
  public:
586
  DEFINE_SIZE_STATIC (5);
587
};
588
589
struct cff2_accelerator_t : cff2::accelerator_t {
590
4
  cff2_accelerator_t (hb_face_t *face) : cff2::accelerator_t (face) {}
591
};
592
593
struct cff2_subset_accelerator_t : cff2::accelerator_subset_t {
594
0
  cff2_subset_accelerator_t (hb_face_t *face) : cff2::accelerator_subset_t (face) {}
595
};
596
597
} /* namespace OT */
598
599
#endif /* HB_OT_CFF2_TABLE_HH */