Coverage Report

Created: 2023-03-09 17:58

/src/harfbuzz/src/hb-ot-layout-base-table.hh
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright © 2016  Elie Roux <elie.roux@telecom-bretagne.eu>
3
 * Copyright © 2018  Google, Inc.
4
 * Copyright © 2018-2019  Ebrahim Byagowi
5
 *
6
 *  This is part of HarfBuzz, a text shaping library.
7
 *
8
 * Permission is hereby granted, without written agreement and without
9
 * license or royalty fees, to use, copy, modify, and distribute this
10
 * software and its documentation for any purpose, provided that the
11
 * above copyright notice and the following two paragraphs appear in
12
 * all copies of this software.
13
 *
14
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
15
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
16
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
17
 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
18
 * DAMAGE.
19
 *
20
 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
21
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
22
 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
23
 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
24
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
25
 *
26
 * Google Author(s): Behdad Esfahbod
27
 */
28
29
#ifndef HB_OT_LAYOUT_BASE_TABLE_HH
30
#define HB_OT_LAYOUT_BASE_TABLE_HH
31
32
#include "hb-open-type.hh"
33
#include "hb-ot-layout-common.hh"
34
35
namespace OT {
36
37
/*
38
 * BASE -- Baseline
39
 * https://docs.microsoft.com/en-us/typography/opentype/spec/base
40
 */
41
42
struct BaseCoordFormat1
43
{
44
  hb_position_t get_coord (hb_font_t *font, hb_direction_t direction) const
45
0
  {
46
0
    return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_y (coordinate) : font->em_scale_x (coordinate);
47
0
  }
48
49
  bool sanitize (hb_sanitize_context_t *c) const
50
127k
  {
51
127k
    TRACE_SANITIZE (this);
52
127k
    return_trace (c->check_struct (this));
53
127k
  }
54
55
  protected:
56
  HBUINT16  format;   /* Format identifier--format = 1 */
57
  FWORD   coordinate; /* X or Y value, in design units */
58
  public:
59
  DEFINE_SIZE_STATIC (4);
60
};
61
62
struct BaseCoordFormat2
63
{
64
  hb_position_t get_coord (hb_font_t *font, hb_direction_t direction) const
65
0
  {
66
    /* TODO */
67
0
    return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_y (coordinate) : font->em_scale_x (coordinate);
68
0
  }
69
70
  bool sanitize (hb_sanitize_context_t *c) const
71
17.8k
  {
72
17.8k
    TRACE_SANITIZE (this);
73
17.8k
    return_trace (c->check_struct (this));
74
17.8k
  }
75
76
  protected:
77
  HBUINT16  format;   /* Format identifier--format = 2 */
78
  FWORD   coordinate; /* X or Y value, in design units */
79
  HBGlyphID16 referenceGlyph; /* Glyph ID of control glyph */
80
  HBUINT16  coordPoint; /* Index of contour point on the
81
         * reference glyph */
82
  public:
83
  DEFINE_SIZE_STATIC (8);
84
};
85
86
struct BaseCoordFormat3
87
{
88
  hb_position_t get_coord (hb_font_t *font,
89
         const VariationStore &var_store,
90
         hb_direction_t direction) const
91
0
  {
92
0
    const Device &device = this+deviceTable;
93
94
0
    return HB_DIRECTION_IS_HORIZONTAL (direction)
95
0
   ? font->em_scale_y (coordinate) + device.get_y_delta (font, var_store)
96
0
   : font->em_scale_x (coordinate) + device.get_x_delta (font, var_store);
97
0
  }
98
99
100
  bool sanitize (hb_sanitize_context_t *c) const
101
9.87k
  {
102
9.87k
    TRACE_SANITIZE (this);
103
9.87k
    return_trace (likely (c->check_struct (this) &&
104
9.87k
        deviceTable.sanitize (c, this)));
105
9.87k
  }
106
107
  protected:
108
  HBUINT16  format;   /* Format identifier--format = 3 */
109
  FWORD   coordinate; /* X or Y value, in design units */
110
  Offset16To<Device>
111
    deviceTable;  /* Offset to Device table for X or
112
         * Y value, from beginning of
113
         * BaseCoord table (may be NULL). */
114
  public:
115
  DEFINE_SIZE_STATIC (6);
116
};
117
118
struct BaseCoord
119
{
120
0
  bool has_data () const { return u.format; }
121
122
  hb_position_t get_coord (hb_font_t            *font,
123
         const VariationStore &var_store,
124
         hb_direction_t        direction) const
125
0
  {
126
0
    switch (u.format) {
127
0
    case 1: return u.format1.get_coord (font, direction);
128
0
    case 2: return u.format2.get_coord (font, direction);
129
0
    case 3: return u.format3.get_coord (font, var_store, direction);
130
0
    default:return 0;
131
0
    }
132
0
  }
133
134
  bool sanitize (hb_sanitize_context_t *c) const
135
211k
  {
136
211k
    TRACE_SANITIZE (this);
137
211k
    if (unlikely (!u.format.sanitize (c))) return_trace (false);
138
199k
    switch (u.format) {
139
127k
    case 1: return_trace (u.format1.sanitize (c));
140
17.8k
    case 2: return_trace (u.format2.sanitize (c));
141
9.87k
    case 3: return_trace (u.format3.sanitize (c));
142
43.5k
    default:return_trace (false);
143
199k
    }
144
199k
  }
145
146
  protected:
147
  union {
148
  HBUINT16    format;
149
  BaseCoordFormat1  format1;
150
  BaseCoordFormat2  format2;
151
  BaseCoordFormat3  format3;
152
  } u;
153
  public:
154
  DEFINE_SIZE_UNION (2, format);
155
};
156
157
struct FeatMinMaxRecord
158
{
159
0
  int cmp (hb_tag_t key) const { return tag.cmp (key); }
160
161
0
  bool has_data () const { return tag; }
162
163
  void get_min_max (const BaseCoord **min, const BaseCoord **max) const
164
0
  {
165
0
    if (likely (min)) *min = &(this+minCoord);
166
0
    if (likely (max)) *max = &(this+maxCoord);
167
0
  }
168
169
  bool sanitize (hb_sanitize_context_t *c, const void *base) const
170
93.9M
  {
171
93.9M
    TRACE_SANITIZE (this);
172
93.9M
    return_trace (likely (c->check_struct (this) &&
173
93.9M
        minCoord.sanitize (c, this) &&
174
93.9M
        maxCoord.sanitize (c, this)));
175
93.9M
  }
176
177
  protected:
178
  Tag   tag;    /* 4-byte feature identification tag--must
179
         * match feature tag in FeatureList */
180
  Offset16To<BaseCoord>
181
    minCoord; /* Offset to BaseCoord table that defines
182
         * the minimum extent value, from beginning
183
         * of MinMax table (may be NULL) */
184
  Offset16To<BaseCoord>
185
    maxCoord; /* Offset to BaseCoord table that defines
186
         * the maximum extent value, from beginning
187
         * of MinMax table (may be NULL) */
188
  public:
189
  DEFINE_SIZE_STATIC (8);
190
191
};
192
193
struct MinMax
194
{
195
  void get_min_max (hb_tag_t          feature_tag,
196
        const BaseCoord **min,
197
        const BaseCoord **max) const
198
0
  {
199
0
    const FeatMinMaxRecord &minMaxCoord = featMinMaxRecords.bsearch (feature_tag);
200
0
    if (minMaxCoord.has_data ())
201
0
      minMaxCoord.get_min_max (min, max);
202
0
    else
203
0
    {
204
0
      if (likely (min)) *min = &(this+minCoord);
205
0
      if (likely (max)) *max = &(this+maxCoord);
206
0
    }
207
0
  }
208
209
  bool sanitize (hb_sanitize_context_t *c) const
210
39.3M
  {
211
39.3M
    TRACE_SANITIZE (this);
212
39.3M
    return_trace (likely (c->check_struct (this) &&
213
39.3M
        minCoord.sanitize (c, this) &&
214
39.3M
        maxCoord.sanitize (c, this) &&
215
39.3M
        featMinMaxRecords.sanitize (c, this)));
216
39.3M
  }
217
218
  protected:
219
  Offset16To<BaseCoord>
220
    minCoord; /* Offset to BaseCoord table that defines
221
         * minimum extent value, from the beginning
222
         * of MinMax table (may be NULL) */
223
  Offset16To<BaseCoord>
224
    maxCoord; /* Offset to BaseCoord table that defines
225
         * maximum extent value, from the beginning
226
         * of MinMax table (may be NULL) */
227
  SortedArray16Of<FeatMinMaxRecord>
228
    featMinMaxRecords;
229
        /* Array of FeatMinMaxRecords, in alphabetical
230
         * order by featureTableTag */
231
  public:
232
  DEFINE_SIZE_ARRAY (6, featMinMaxRecords);
233
};
234
235
struct BaseValues
236
{
237
  const BaseCoord &get_base_coord (int baseline_tag_index) const
238
0
  {
239
0
    if (baseline_tag_index == -1) baseline_tag_index = defaultIndex;
240
0
    return this+baseCoords[baseline_tag_index];
241
0
  }
242
243
  bool sanitize (hb_sanitize_context_t *c) const
244
188k
  {
245
188k
    TRACE_SANITIZE (this);
246
188k
    return_trace (likely (c->check_struct (this) &&
247
188k
        baseCoords.sanitize (c, this)));
248
188k
  }
249
250
  protected:
251
  Index   defaultIndex; /* Index number of default baseline for this
252
         * script — equals index position of baseline tag
253
         * in baselineTags array of the BaseTagList */
254
  Array16OfOffset16To<BaseCoord>
255
    baseCoords; /* Number of BaseCoord tables defined — should equal
256
         * baseTagCount in the BaseTagList
257
         *
258
         * Array of offsets to BaseCoord tables, from beginning of
259
         * BaseValues table — order matches baselineTags array in
260
         * the BaseTagList */
261
  public:
262
  DEFINE_SIZE_ARRAY (4, baseCoords);
263
};
264
265
struct BaseLangSysRecord
266
{
267
0
  int cmp (hb_tag_t key) const { return baseLangSysTag.cmp (key); }
268
269
0
  bool has_data () const { return baseLangSysTag; }
270
271
0
  const MinMax &get_min_max () const { return this+minMax; }
272
273
  bool sanitize (hb_sanitize_context_t *c, const void *base) const
274
899M
  {
275
899M
    TRACE_SANITIZE (this);
276
899M
    return_trace (likely (c->check_struct (this) &&
277
899M
        minMax.sanitize (c, this)));
278
899M
  }
279
280
  protected:
281
  Tag   baseLangSysTag; /* 4-byte language system identification tag */
282
  Offset16To<MinMax>
283
    minMax;   /* Offset to MinMax table, from beginning
284
         * of BaseScript table */
285
  public:
286
  DEFINE_SIZE_STATIC (6);
287
};
288
289
struct BaseScript
290
{
291
  const MinMax &get_min_max (hb_tag_t language_tag) const
292
0
  {
293
0
    const BaseLangSysRecord& record = baseLangSysRecords.bsearch (language_tag);
294
0
    return record.has_data () ? record.get_min_max () : this+defaultMinMax;
295
0
  }
296
297
  const BaseCoord &get_base_coord (int baseline_tag_index) const
298
0
  { return (this+baseValues).get_base_coord (baseline_tag_index); }
299
300
372k
  bool has_data () const { return baseValues; }
301
302
  bool sanitize (hb_sanitize_context_t *c) const
303
1.81M
  {
304
1.81M
    TRACE_SANITIZE (this);
305
1.81M
    return_trace (likely (c->check_struct (this) &&
306
1.81M
        baseValues.sanitize (c, this) &&
307
1.81M
        defaultMinMax.sanitize (c, this) &&
308
1.81M
        baseLangSysRecords.sanitize (c, this)));
309
1.81M
  }
310
311
  protected:
312
  Offset16To<BaseValues>
313
    baseValues; /* Offset to BaseValues table, from beginning
314
         * of BaseScript table (may be NULL) */
315
  Offset16To<MinMax>
316
    defaultMinMax;  /* Offset to MinMax table, from beginning of
317
         * BaseScript table (may be NULL) */
318
  SortedArray16Of<BaseLangSysRecord>
319
    baseLangSysRecords;
320
        /* Number of BaseLangSysRecords
321
         * defined — may be zero (0) */
322
323
  public:
324
  DEFINE_SIZE_ARRAY (6, baseLangSysRecords);
325
};
326
327
struct BaseScriptList;
328
struct BaseScriptRecord
329
{
330
19.7k
  int cmp (hb_tag_t key) const { return baseScriptTag.cmp (key); }
331
332
745k
  bool has_data () const { return baseScriptTag; }
333
334
  const BaseScript &get_base_script (const BaseScriptList *list) const
335
3.44k
  { return list+baseScript; }
336
337
  bool sanitize (hb_sanitize_context_t *c, const void *base) const
338
16.2M
  {
339
16.2M
    TRACE_SANITIZE (this);
340
16.2M
    return_trace (likely (c->check_struct (this) &&
341
16.2M
        baseScript.sanitize (c, base)));
342
16.2M
  }
343
344
  protected:
345
  Tag   baseScriptTag;  /* 4-byte script identification tag */
346
  Offset16To<BaseScript>
347
    baseScript; /* Offset to BaseScript table, from beginning
348
         * of BaseScriptList */
349
350
  public:
351
  DEFINE_SIZE_STATIC (6);
352
};
353
354
struct BaseScriptList
355
{
356
  const BaseScript &get_base_script (hb_tag_t script) const
357
372k
  {
358
372k
    const BaseScriptRecord *record = &baseScriptRecords.bsearch (script);
359
372k
    if (!record->has_data ()) record = &baseScriptRecords.bsearch (HB_TAG ('D','F','L','T'));
360
372k
    return record->has_data () ? record->get_base_script (this) : Null (BaseScript);
361
372k
  }
362
363
  bool sanitize (hb_sanitize_context_t *c) const
364
15.5k
  {
365
15.5k
    TRACE_SANITIZE (this);
366
15.5k
    return_trace (c->check_struct (this) &&
367
15.5k
      baseScriptRecords.sanitize (c, this));
368
15.5k
  }
369
370
  protected:
371
  SortedArray16Of<BaseScriptRecord>
372
      baseScriptRecords;
373
374
  public:
375
  DEFINE_SIZE_ARRAY (2, baseScriptRecords);
376
};
377
378
struct Axis
379
{
380
  bool get_baseline (hb_tag_t          baseline_tag,
381
         hb_tag_t          script_tag,
382
         hb_tag_t          language_tag,
383
         const BaseCoord **coord) const
384
372k
  {
385
372k
    const BaseScript &base_script = (this+baseScriptList).get_base_script (script_tag);
386
372k
    if (!base_script.has_data ())
387
369k
    {
388
369k
      *coord = nullptr;
389
369k
      return false;
390
369k
    }
391
392
3.05k
    if (likely (coord))
393
3.05k
    {
394
3.05k
      unsigned int tag_index = 0;
395
3.05k
      if (!(this+baseTagList).bfind (baseline_tag, &tag_index))
396
3.05k
      {
397
3.05k
        *coord = nullptr;
398
3.05k
        return false;
399
3.05k
      }
400
0
      *coord = &base_script.get_base_coord (tag_index);
401
0
    }
402
403
0
    return true;
404
3.05k
  }
405
406
  bool get_min_max (hb_tag_t          script_tag,
407
        hb_tag_t          language_tag,
408
        hb_tag_t          feature_tag,
409
        const BaseCoord **min_coord,
410
        const BaseCoord **max_coord) const
411
0
  {
412
0
    const BaseScript &base_script = (this+baseScriptList).get_base_script (script_tag);
413
0
    if (!base_script.has_data ())
414
0
    {
415
0
      *min_coord = *max_coord = nullptr;
416
0
      return false;
417
0
    }
418
0
419
0
    base_script.get_min_max (language_tag).get_min_max (feature_tag, min_coord, max_coord);
420
0
421
0
    return true;
422
0
  }
423
424
  bool sanitize (hb_sanitize_context_t *c) const
425
17.5k
  {
426
17.5k
    TRACE_SANITIZE (this);
427
17.5k
    return_trace (likely (c->check_struct (this) &&
428
17.5k
        (this+baseTagList).sanitize (c) &&
429
17.5k
        (this+baseScriptList).sanitize (c)));
430
17.5k
  }
431
432
  protected:
433
  Offset16To<SortedArray16Of<Tag>>
434
    baseTagList;  /* Offset to BaseTagList table, from beginning
435
         * of Axis table (may be NULL)
436
         * Array of 4-byte baseline identification tags — must
437
         * be in alphabetical order */
438
  Offset16To<BaseScriptList>
439
    baseScriptList; /* Offset to BaseScriptList table, from beginning
440
         * of Axis table
441
         * Array of BaseScriptRecords, in alphabetical order
442
         * by baseScriptTag */
443
444
  public:
445
  DEFINE_SIZE_STATIC (4);
446
};
447
448
struct BASE
449
{
450
  static constexpr hb_tag_t tableTag = HB_OT_TAG_BASE;
451
452
  const Axis &get_axis (hb_direction_t direction) const
453
372k
  { return HB_DIRECTION_IS_VERTICAL (direction) ? this+vAxis : this+hAxis; }
454
455
  const VariationStore &get_var_store () const
456
0
  { return version.to_int () < 0x00010001u ? Null (VariationStore) : this+varStore; }
457
458
  bool get_baseline (hb_font_t      *font,
459
         hb_tag_t        baseline_tag,
460
         hb_direction_t  direction,
461
         hb_tag_t        script_tag,
462
         hb_tag_t        language_tag,
463
         hb_position_t  *base) const
464
372k
  {
465
372k
    const BaseCoord *base_coord = nullptr;
466
372k
    if (unlikely (!get_axis (direction).get_baseline (baseline_tag, script_tag, language_tag, &base_coord) ||
467
372k
      !base_coord || !base_coord->has_data ()))
468
372k
      return false;
469
470
0
    if (likely (base))
471
0
      *base = base_coord->get_coord (font, get_var_store (), direction);
472
473
0
    return true;
474
372k
  }
475
476
  /* TODO: Expose this separately sometime? */
477
  bool get_min_max (hb_font_t      *font,
478
        hb_direction_t  direction,
479
        hb_tag_t        script_tag,
480
        hb_tag_t        language_tag,
481
        hb_tag_t        feature_tag,
482
        hb_position_t  *min,
483
        hb_position_t  *max)
484
0
  {
485
0
    const BaseCoord *min_coord, *max_coord;
486
0
    if (!get_axis (direction).get_min_max (script_tag, language_tag, feature_tag,
487
0
             &min_coord, &max_coord))
488
0
      return false;
489
0
490
0
    const VariationStore &var_store = get_var_store ();
491
0
    if (likely (min && min_coord)) *min = min_coord->get_coord (font, var_store, direction);
492
0
    if (likely (max && max_coord)) *max = max_coord->get_coord (font, var_store, direction);
493
0
    return true;
494
0
  }
495
496
  bool sanitize (hb_sanitize_context_t *c) const
497
21.4k
  {
498
21.4k
    TRACE_SANITIZE (this);
499
21.4k
    return_trace (likely (c->check_struct (this) &&
500
21.4k
        likely (version.major == 1) &&
501
21.4k
        hAxis.sanitize (c, this) &&
502
21.4k
        vAxis.sanitize (c, this) &&
503
21.4k
        (version.to_int () < 0x00010001u || varStore.sanitize (c, this))));
504
21.4k
  }
505
506
  protected:
507
  FixedVersion<>version;  /* Version of the BASE table */
508
  Offset16To<Axis>hAxis;    /* Offset to horizontal Axis table, from beginning
509
         * of BASE table (may be NULL) */
510
  Offset16To<Axis>vAxis;    /* Offset to vertical Axis table, from beginning
511
         * of BASE table (may be NULL) */
512
  Offset32To<VariationStore>
513
    varStore; /* Offset to the table of Item Variation
514
         * Store--from beginning of BASE
515
         * header (may be NULL).  Introduced
516
         * in version 0x00010001. */
517
  public:
518
  DEFINE_SIZE_MIN (8);
519
};
520
521
522
} /* namespace OT */
523
524
525
#endif /* HB_OT_LAYOUT_BASE_TABLE_HH */