Coverage Report

Created: 2023-10-27 07:46

/src/harfbuzz/src/hb-ot-cff2-table.hh
Line
Count
Source (jump to first uncovered line)
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-cff2.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 CFFIndex<HBUINT32>  CFF2Index;
44
template <typename Type> struct CFF2IndexOf : CFFIndexOf<HBUINT32, Type> {};
45
46
typedef CFF2Index         CFF2CharStrings;
47
typedef Subrs<HBUINT32>   CFF2Subrs;
48
49
typedef FDSelect3_4<HBUINT32, HBUINT16> FDSelect4;
50
typedef FDSelect3_4_Range<HBUINT32, HBUINT16> FDSelect4_Range;
51
52
struct CFF2FDSelect
53
{
54
  bool serialize (hb_serialize_context_t *c, const CFF2FDSelect &src, unsigned int num_glyphs)
55
0
  {
56
0
    TRACE_SERIALIZE (this);
57
0
    unsigned int size = src.get_size (num_glyphs);
58
0
    CFF2FDSelect *dest = c->allocate_size<CFF2FDSelect> (size);
59
0
    if (unlikely (!dest)) return_trace (false);
60
0
    hb_memcpy (dest, &src, size);
61
0
    return_trace (true);
62
0
  }
63
64
  unsigned int get_size (unsigned int num_glyphs) const
65
0
  {
66
0
    switch (format)
67
0
    {
68
0
    case 0: return format.static_size + u.format0.get_size (num_glyphs);
69
0
    case 3: return format.static_size + u.format3.get_size ();
70
0
    case 4: return format.static_size + u.format4.get_size ();
71
0
    default:return 0;
72
0
    }
73
0
  }
74
75
  hb_codepoint_t get_fd (hb_codepoint_t glyph) const
76
210k
  {
77
210k
    if (this == &Null (CFF2FDSelect))
78
210k
      return 0;
79
80
0
    switch (format)
81
0
    {
82
0
    case 0: return u.format0.get_fd (glyph);
83
0
    case 3: return u.format3.get_fd (glyph);
84
0
    case 4: return u.format4.get_fd (glyph);
85
0
    default:return 0;
86
0
    }
87
0
  }
88
89
  bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
90
234
  {
91
234
    TRACE_SANITIZE (this);
92
234
    if (unlikely (!c->check_struct (this)))
93
56
      return_trace (false);
94
95
178
    switch (format)
96
178
    {
97
45
    case 0: return_trace (u.format0.sanitize (c, fdcount));
98
27
    case 3: return_trace (u.format3.sanitize (c, fdcount));
99
81
    case 4: return_trace (u.format4.sanitize (c, fdcount));
100
25
    default:return_trace (false);
101
178
    }
102
178
  }
103
104
  HBUINT8 format;
105
  union {
106
  FDSelect0 format0;
107
  FDSelect3 format3;
108
  FDSelect4 format4;
109
  } u;
110
  public:
111
  DEFINE_SIZE_MIN (2);
112
};
113
114
struct CFF2VariationStore
115
{
116
  bool sanitize (hb_sanitize_context_t *c) const
117
11.9k
  {
118
11.9k
    TRACE_SANITIZE (this);
119
11.9k
    return_trace (likely (c->check_struct (this)) && c->check_range (&varStore, size) && varStore.sanitize (c));
120
11.9k
  }
121
122
  bool serialize (hb_serialize_context_t *c, const CFF2VariationStore *varStore)
123
0
  {
124
0
    TRACE_SERIALIZE (this);
125
0
    unsigned int size_ = varStore->get_size ();
126
0
    CFF2VariationStore *dest = c->allocate_size<CFF2VariationStore> (size_);
127
0
    if (unlikely (!dest)) return_trace (false);
128
0
    hb_memcpy (dest, varStore, size_);
129
0
    return_trace (true);
130
0
  }
131
132
0
  unsigned int get_size () const { return HBUINT16::static_size + size; }
133
134
  HBUINT16  size;
135
  VariationStore  varStore;
136
137
  DEFINE_SIZE_MIN (2 + VariationStore::min_size);
138
};
139
140
struct cff2_top_dict_values_t : top_dict_values_t<>
141
{
142
  void init ()
143
513k
  {
144
513k
    top_dict_values_t<>::init ();
145
513k
    vstoreOffset = 0;
146
513k
    FDSelectOffset = 0;
147
513k
  }
148
934k
  void fini () { top_dict_values_t<>::fini (); }
149
150
  unsigned int  vstoreOffset;
151
  unsigned int  FDSelectOffset;
152
};
153
154
struct cff2_top_dict_opset_t : top_dict_opset_t<>
155
{
156
  static void process_op (op_code_t op, num_interp_env_t& env, cff2_top_dict_values_t& dictval)
157
167k
  {
158
167k
    switch (op) {
159
5.09k
      case OpCode_FontMatrix:
160
5.09k
  {
161
5.09k
    dict_val_t val;
162
5.09k
    val.init ();
163
5.09k
    dictval.add_op (op, env.str_ref);
164
5.09k
    env.clear_args ();
165
5.09k
  }
166
5.09k
  break;
167
168
12.3k
      case OpCode_vstore:
169
12.3k
  dictval.vstoreOffset = env.argStack.pop_uint ();
170
12.3k
  env.clear_args ();
171
12.3k
  break;
172
530
      case OpCode_FDSelect:
173
530
  dictval.FDSelectOffset = env.argStack.pop_uint ();
174
530
  env.clear_args ();
175
530
  break;
176
177
149k
      default:
178
149k
  SUPER::process_op (op, env, dictval);
179
  /* Record this operand below if stack is empty, otherwise done */
180
149k
  if (!env.argStack.is_empty ()) return;
181
167k
    }
182
183
57.5k
    if (unlikely (env.in_error ())) return;
184
185
56.9k
    dictval.add_op (op, env.str_ref);
186
56.9k
  }
187
188
  typedef top_dict_opset_t<> SUPER;
189
};
190
191
struct cff2_font_dict_values_t : dict_values_t<op_str_t>
192
{
193
  void init ()
194
791k
  {
195
791k
    dict_values_t<op_str_t>::init ();
196
791k
    privateDictInfo.init ();
197
791k
  }
198
0
  void fini () { dict_values_t<op_str_t>::fini (); }
199
200
  table_info_t    privateDictInfo;
201
};
202
203
struct cff2_font_dict_opset_t : dict_opset_t
204
{
205
  static void process_op (op_code_t op, num_interp_env_t& env, cff2_font_dict_values_t& dictval)
206
603k
  {
207
603k
    switch (op) {
208
12.8k
      case OpCode_Private:
209
12.8k
  dictval.privateDictInfo.offset = env.argStack.pop_uint ();
210
12.8k
  dictval.privateDictInfo.size = env.argStack.pop_uint ();
211
12.8k
  env.clear_args ();
212
12.8k
  break;
213
214
591k
      default:
215
591k
  SUPER::process_op (op, env);
216
591k
  if (!env.argStack.is_empty ())
217
590k
    return;
218
603k
    }
219
220
13.2k
    if (unlikely (env.in_error ())) return;
221
222
12.7k
    dictval.add_op (op, env.str_ref);
223
12.7k
  }
224
225
  private:
226
  typedef dict_opset_t SUPER;
227
};
228
229
template <typename VAL>
230
struct cff2_private_dict_values_base_t : dict_values_t<VAL>
231
{
232
  void init ()
233
789k
  {
234
789k
    dict_values_t<VAL>::init ();
235
789k
    subrsOffset = 0;
236
789k
    localSubrs = &Null (CFF2Subrs);
237
789k
    ivs = 0;
238
789k
  }
239
  void fini () { dict_values_t<VAL>::fini (); }
240
241
  unsigned int      subrsOffset;
242
  const CFF2Subrs   *localSubrs;
243
  unsigned int      ivs;
244
};
245
246
typedef cff2_private_dict_values_base_t<op_str_t> cff2_private_dict_values_subset_t;
247
typedef cff2_private_dict_values_base_t<num_dict_val_t> cff2_private_dict_values_t;
248
249
struct cff2_priv_dict_interp_env_t : num_interp_env_t
250
{
251
  cff2_priv_dict_interp_env_t (const hb_ubytes_t &str) :
252
394k
    num_interp_env_t (str) {}
253
254
  void process_vsindex ()
255
859
  {
256
859
    if (likely (!seen_vsindex))
257
158
    {
258
158
      set_ivs (argStack.pop_uint ());
259
158
    }
260
859
    seen_vsindex = true;
261
859
  }
262
263
859
  unsigned int get_ivs () const { return ivs; }
264
158
  void   set_ivs (unsigned int ivs_) { ivs = ivs_; }
265
266
  protected:
267
  unsigned int  ivs = 0;
268
  bool    seen_vsindex = false;
269
};
270
271
struct cff2_private_dict_opset_t : dict_opset_t
272
{
273
  static void process_op (op_code_t op, cff2_priv_dict_interp_env_t& env, cff2_private_dict_values_t& dictval)
274
1.18M
  {
275
1.18M
    num_dict_val_t val;
276
1.18M
    val.init ();
277
278
1.18M
    switch (op) {
279
11.4k
      case OpCode_StdHW:
280
20.9k
      case OpCode_StdVW:
281
29.9k
      case OpCode_BlueScale:
282
30.0k
      case OpCode_BlueShift:
283
38.8k
      case OpCode_BlueFuzz:
284
38.9k
      case OpCode_ExpansionFactor:
285
38.9k
      case OpCode_LanguageGroup:
286
38.9k
  val.single_val = env.argStack.pop_num ();
287
38.9k
  env.clear_args ();
288
38.9k
  break;
289
9.67k
      case OpCode_BlueValues:
290
20.1k
      case OpCode_OtherBlues:
291
26.9k
      case OpCode_FamilyBlues:
292
34.1k
      case OpCode_FamilyOtherBlues:
293
39.8k
      case OpCode_StemSnapH:
294
44.8k
      case OpCode_StemSnapV:
295
44.8k
  env.clear_args ();
296
44.8k
  break;
297
10.7k
      case OpCode_Subrs:
298
10.7k
  dictval.subrsOffset = env.argStack.pop_uint ();
299
10.7k
  env.clear_args ();
300
10.7k
  break;
301
859
      case OpCode_vsindexdict:
302
859
  env.process_vsindex ();
303
859
  dictval.ivs = env.get_ivs ();
304
859
  env.clear_args ();
305
859
  break;
306
46.9k
      case OpCode_blenddict:
307
46.9k
  break;
308
309
1.04M
      default:
310
1.04M
  dict_opset_t::process_op (op, env);
311
1.04M
  if (!env.argStack.is_empty ()) return;
312
259
  break;
313
1.18M
    }
314
315
142k
    if (unlikely (env.in_error ())) return;
316
317
142k
    dictval.add_op (op, env.str_ref, val);
318
142k
  }
319
};
320
321
struct cff2_private_dict_opset_subset_t : dict_opset_t
322
{
323
  static void process_op (op_code_t op, cff2_priv_dict_interp_env_t& env, cff2_private_dict_values_subset_t& dictval)
324
0
  {
325
0
    switch (op) {
326
0
      case OpCode_BlueValues:
327
0
      case OpCode_OtherBlues:
328
0
      case OpCode_FamilyBlues:
329
0
      case OpCode_FamilyOtherBlues:
330
0
      case OpCode_StdHW:
331
0
      case OpCode_StdVW:
332
0
      case OpCode_BlueScale:
333
0
      case OpCode_BlueShift:
334
0
      case OpCode_BlueFuzz:
335
0
      case OpCode_StemSnapH:
336
0
      case OpCode_StemSnapV:
337
0
      case OpCode_LanguageGroup:
338
0
      case OpCode_ExpansionFactor:
339
0
  env.clear_args ();
340
0
  break;
341
0
342
0
      case OpCode_blenddict:
343
0
  env.clear_args ();
344
0
  return;
345
0
346
0
      case OpCode_Subrs:
347
0
  dictval.subrsOffset = env.argStack.pop_uint ();
348
0
  env.clear_args ();
349
0
  break;
350
0
351
0
      default:
352
0
  SUPER::process_op (op, env);
353
0
  if (!env.argStack.is_empty ()) return;
354
0
  break;
355
0
    }
356
0
357
0
    if (unlikely (env.in_error ())) return;
358
0
359
0
    dictval.add_op (op, env.str_ref);
360
0
  }
361
362
  private:
363
  typedef dict_opset_t SUPER;
364
};
365
366
typedef dict_interpreter_t<cff2_top_dict_opset_t, cff2_top_dict_values_t> cff2_top_dict_interpreter_t;
367
typedef dict_interpreter_t<cff2_font_dict_opset_t, cff2_font_dict_values_t> cff2_font_dict_interpreter_t;
368
369
struct CFF2FDArray : FDArray<HBUINT32>
370
{
371
  /* FDArray::serialize does not compile without this partial specialization */
372
  template <typename ITER, typename OP_SERIALIZER>
373
  bool serialize (hb_serialize_context_t *c, ITER it, OP_SERIALIZER& opszr)
374
  { return FDArray<HBUINT32>::serialize<cff2_font_dict_values_t, table_info_t> (c, it, opszr); }
375
};
376
377
} /* namespace CFF */
378
379
namespace OT {
380
381
using namespace CFF;
382
383
struct cff2
384
{
385
  static constexpr hb_tag_t tableTag = HB_OT_TAG_cff2;
386
387
  bool sanitize (hb_sanitize_context_t *c) const
388
22.5k
  {
389
22.5k
    TRACE_SANITIZE (this);
390
22.5k
    return_trace (c->check_struct (this) &&
391
22.5k
      likely (version.major == 2));
392
22.5k
  }
393
394
  template <typename PRIVOPSET, typename PRIVDICTVAL>
395
  struct accelerator_templ_t
396
  {
397
    accelerator_templ_t (hb_face_t *face)
398
474k
    {
399
474k
      topDict.init ();
400
474k
      fontDicts.init ();
401
474k
      privateDicts.init ();
402
403
474k
      this->blob = sc.reference_table<cff2> (face);
404
405
      /* setup for run-time santization */
406
474k
      sc.init (this->blob);
407
474k
      sc.start_processing ();
408
409
474k
      const OT::cff2 *cff2 = this->blob->template as<OT::cff2> ();
410
411
474k
      if (cff2 == &Null (OT::cff2))
412
454k
        goto fail;
413
414
19.7k
      { /* parse top dict */
415
19.7k
  hb_ubytes_t topDictStr = (cff2 + cff2->topDict).as_ubytes (cff2->topDictSize);
416
19.7k
  if (unlikely (!topDictStr.sanitize (&sc))) goto fail;
417
19.7k
  num_interp_env_t env (topDictStr);
418
19.7k
  cff2_top_dict_interpreter_t top_interp (env);
419
19.7k
  topDict.init ();
420
19.7k
  if (unlikely (!top_interp.interpret (topDict))) goto fail;
421
19.7k
      }
422
423
19.0k
      globalSubrs = &StructAtOffset<CFF2Subrs> (cff2, cff2->topDict + cff2->topDictSize);
424
19.0k
      varStore = &StructAtOffsetOrNull<CFF2VariationStore> (cff2, topDict.vstoreOffset);
425
19.0k
      charStrings = &StructAtOffsetOrNull<CFF2CharStrings> (cff2, topDict.charStringsOffset);
426
19.0k
      fdArray = &StructAtOffsetOrNull<CFF2FDArray> (cff2, topDict.FDArrayOffset);
427
19.0k
      fdSelect = &StructAtOffsetOrNull<CFF2FDSelect> (cff2, topDict.FDSelectOffset);
428
429
19.0k
      if (((varStore != &Null (CFF2VariationStore)) && unlikely (!varStore->sanitize (&sc))) ||
430
19.0k
    (charStrings == &Null (CFF2CharStrings)) || unlikely (!charStrings->sanitize (&sc)) ||
431
19.0k
    (globalSubrs == &Null (CFF2Subrs)) || unlikely (!globalSubrs->sanitize (&sc)) ||
432
19.0k
    (fdArray == &Null (CFF2FDArray)) || unlikely (!fdArray->sanitize (&sc)) ||
433
19.0k
    (((fdSelect != &Null (CFF2FDSelect)) && unlikely (!fdSelect->sanitize (&sc, fdArray->count)))))
434
2.92k
        goto fail;
435
436
16.1k
      num_glyphs = charStrings->count;
437
16.1k
      if (num_glyphs != sc.get_num_glyphs ())
438
627
        goto fail;
439
440
15.4k
      fdCount = fdArray->count;
441
15.4k
      if (!privateDicts.resize (fdCount))
442
37
        goto fail;
443
444
      /* parse font dicts and gather private dicts */
445
409k
      for (unsigned int i = 0; i < fdCount; i++)
446
395k
      {
447
395k
  const hb_ubytes_t fontDictStr = (*fdArray)[i];
448
395k
  if (unlikely (!fontDictStr.sanitize (&sc))) goto fail;
449
395k
  cff2_font_dict_values_t  *font;
450
395k
  num_interp_env_t env (fontDictStr);
451
395k
  cff2_font_dict_interpreter_t font_interp (env);
452
395k
  font = fontDicts.push ();
453
395k
  if (unlikely (font == &Crap (cff2_font_dict_values_t))) goto fail;
454
395k
  font->init ();
455
395k
  if (unlikely (!font_interp.interpret (*font))) goto fail;
456
457
395k
  const hb_ubytes_t privDictStr = StructAtOffsetOrNull<UnsizedByteStr> (cff2, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size);
458
395k
  if (unlikely (!privDictStr.sanitize (&sc))) goto fail;
459
394k
  cff2_priv_dict_interp_env_t env2 (privDictStr);
460
394k
  dict_interpreter_t<PRIVOPSET, PRIVDICTVAL, cff2_priv_dict_interp_env_t> priv_interp (env2);
461
394k
  privateDicts[i].init ();
462
394k
  if (unlikely (!priv_interp.interpret (privateDicts[i]))) goto fail;
463
464
394k
  privateDicts[i].localSubrs = &StructAtOffsetOrNull<CFF2Subrs> (&privDictStr[0], privateDicts[i].subrsOffset);
465
394k
  if (privateDicts[i].localSubrs != &Null (CFF2Subrs) &&
466
394k
    unlikely (!privateDicts[i].localSubrs->sanitize (&sc)))
467
110
    goto fail;
468
394k
      }
469
470
471
14.2k
      return;
472
473
460k
      fail:
474
460k
        _fini ();
475
460k
    }
476
474k
    ~accelerator_templ_t () { _fini (); }
477
    void _fini ()
478
934k
    {
479
934k
      sc.end_processing ();
480
934k
      topDict.fini ();
481
934k
      fontDicts.fini ();
482
934k
      privateDicts.fini ();
483
934k
      hb_blob_destroy (blob);
484
934k
      blob = nullptr;
485
934k
    }
486
487
    hb_map_t *create_glyph_to_sid_map () const
488
    {
489
      return nullptr;
490
    }
491
492
1.62M
    bool is_valid () const { return blob; }
493
494
    protected:
495
    hb_sanitize_context_t sc;
496
497
    public:
498
    hb_blob_t     *blob = nullptr;
499
    cff2_top_dict_values_t  topDict;
500
    const CFF2Subrs   *globalSubrs = nullptr;
501
    const CFF2VariationStore  *varStore = nullptr;
502
    const CFF2CharStrings *charStrings = nullptr;
503
    const CFF2FDArray   *fdArray = nullptr;
504
    const CFF2FDSelect    *fdSelect = nullptr;
505
    unsigned int    fdCount = 0;
506
507
    hb_vector_t<cff2_font_dict_values_t>     fontDicts;
508
    hb_vector_t<PRIVDICTVAL>  privateDicts;
509
510
    unsigned int        num_glyphs = 0;
511
  };
512
513
  struct accelerator_t : accelerator_templ_t<cff2_private_dict_opset_t, cff2_private_dict_values_t>
514
  {
515
474k
    accelerator_t (hb_face_t *face) : accelerator_templ_t (face) {}
516
517
    HB_INTERNAL bool get_extents (hb_font_t *font,
518
          hb_codepoint_t glyph,
519
          hb_glyph_extents_t *extents) const;
520
    HB_INTERNAL bool paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const;
521
    HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const;
522
  };
523
524
  typedef accelerator_templ_t<cff2_private_dict_opset_subset_t, cff2_private_dict_values_subset_t> accelerator_subset_t;
525
526
0
  bool subset (hb_subset_context_t *c) const { return hb_subset_cff2 (c); }
527
528
  public:
529
  FixedVersion<HBUINT8>   version;  /* Version of CFF2 table. set to 0x0200u */
530
  NNOffsetTo<TopDict, HBUINT8>  topDict;  /* headerSize = Offset to Top DICT. */
531
  HBUINT16      topDictSize;  /* Top DICT size */
532
533
  public:
534
  DEFINE_SIZE_STATIC (5);
535
};
536
537
struct cff2_accelerator_t : cff2::accelerator_t {
538
474k
  cff2_accelerator_t (hb_face_t *face) : cff2::accelerator_t (face) {}
539
};
540
541
} /* namespace OT */
542
543
#endif /* HB_OT_CFF2_TABLE_HH */