Coverage Report

Created: 2023-12-14 14:03

/src/harfbuzz/src/hb-ot-os2-table.hh
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright © 2011,2012  Google, Inc.
3
 * Copyright © 2018  Ebrahim Byagowi
4
 *
5
 *  This is part of HarfBuzz, a text shaping library.
6
 *
7
 * Permission is hereby granted, without written agreement and without
8
 * license or royalty fees, to use, copy, modify, and distribute this
9
 * software and its documentation for any purpose, provided that the
10
 * above copyright notice and the following two paragraphs appear in
11
 * all copies of this software.
12
 *
13
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16
 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
17
 * DAMAGE.
18
 *
19
 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21
 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
22
 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24
 *
25
 * Google Author(s): Behdad Esfahbod
26
 */
27
28
#ifndef HB_OT_OS2_TABLE_HH
29
#define HB_OT_OS2_TABLE_HH
30
31
#include "hb-open-type.hh"
32
#include "hb-ot-os2-unicode-ranges.hh"
33
#include "hb-ot-var-mvar-table.hh"
34
35
#include "hb-set.hh"
36
37
/*
38
 * OS/2 and Windows Metrics
39
 * https://docs.microsoft.com/en-us/typography/opentype/spec/os2
40
 */
41
#define HB_OT_TAG_OS2 HB_TAG('O','S','/','2')
42
43
44
namespace OT {
45
46
struct OS2V1Tail
47
{
48
  bool sanitize (hb_sanitize_context_t *c) const
49
155k
  {
50
155k
    TRACE_SANITIZE (this);
51
155k
    return_trace (c->check_struct (this));
52
155k
  }
53
54
  public:
55
  HBUINT32  ulCodePageRange1;
56
  HBUINT32  ulCodePageRange2;
57
  public:
58
  DEFINE_SIZE_STATIC (8);
59
};
60
61
struct OS2V2Tail
62
{
63
0
  bool has_data () const { return sxHeight || sCapHeight; }
64
65
0
  const OS2V2Tail * operator -> () const { return this; }
66
0
  OS2V2Tail * operator -> () { return this; }
67
68
  bool sanitize (hb_sanitize_context_t *c) const
69
151k
  {
70
151k
    TRACE_SANITIZE (this);
71
151k
    return_trace (c->check_struct (this));
72
151k
  }
73
74
  public:
75
  HBINT16 sxHeight;
76
  HBINT16 sCapHeight;
77
  HBUINT16  usDefaultChar;
78
  HBUINT16  usBreakChar;
79
  HBUINT16  usMaxContext;
80
  public:
81
  DEFINE_SIZE_STATIC (10);
82
};
83
84
struct OS2V5Tail
85
{
86
  inline bool get_optical_size (unsigned int *lower, unsigned int *upper) const
87
0
  {
88
0
    unsigned int lower_optical_size = usLowerOpticalPointSize;
89
0
    unsigned int upper_optical_size = usUpperOpticalPointSize;
90
0
91
0
    /* Per https://docs.microsoft.com/en-us/typography/opentype/spec/os2#lps */
92
0
    if (lower_optical_size < upper_optical_size &&
93
0
  lower_optical_size >= 1 && lower_optical_size <= 0xFFFE &&
94
0
  upper_optical_size >= 2 && upper_optical_size <= 0xFFFF)
95
0
    {
96
0
      *lower = lower_optical_size;
97
0
      *upper = upper_optical_size;
98
0
      return true;
99
0
    }
100
0
    return false;
101
0
  }
102
103
  bool sanitize (hb_sanitize_context_t *c) const
104
17.4k
  {
105
17.4k
    TRACE_SANITIZE (this);
106
17.4k
    return_trace (c->check_struct (this));
107
17.4k
  }
108
109
  public:
110
  HBUINT16  usLowerOpticalPointSize;
111
  HBUINT16  usUpperOpticalPointSize;
112
  public:
113
  DEFINE_SIZE_STATIC (4);
114
};
115
116
struct OS2
117
{
118
  static constexpr hb_tag_t tableTag = HB_OT_TAG_OS2;
119
120
245k
  bool has_data () const { return usWeightClass || usWidthClass || usFirstCharIndex || usLastCharIndex; }
121
122
0
  const OS2V1Tail &v1 () const { return version >= 1 ? v1X : Null (OS2V1Tail); }
123
0
  const OS2V2Tail &v2 () const { return version >= 2 ? v2X : Null (OS2V2Tail); }
124
0
  const OS2V5Tail &v5 () const { return version >= 5 ? v5X : Null (OS2V5Tail); }
125
126
  enum selection_flag_t {
127
    ITALIC    = 1u<<0,
128
    UNDERSCORE    = 1u<<1,
129
    NEGATIVE    = 1u<<2,
130
    OUTLINED    = 1u<<3,
131
    STRIKEOUT   = 1u<<4,
132
    BOLD    = 1u<<5,
133
    REGULAR   = 1u<<6,
134
    USE_TYPO_METRICS  = 1u<<7,
135
    WWS     = 1u<<8,
136
    OBLIQUE   = 1u<<9
137
  };
138
139
0
  bool        is_italic () const { return fsSelection & ITALIC; }
140
0
  bool       is_oblique () const { return fsSelection & OBLIQUE; }
141
1.72M
  bool use_typo_metrics () const { return fsSelection & USE_TYPO_METRICS; }
142
143
  enum width_class_t {
144
    FWIDTH_ULTRA_CONDENSED  = 1, /* 50% */
145
    FWIDTH_EXTRA_CONDENSED  = 2, /* 62.5% */
146
    FWIDTH_CONDENSED    = 3, /* 75% */
147
    FWIDTH_SEMI_CONDENSED = 4, /* 87.5% */
148
    FWIDTH_NORMAL   = 5, /* 100% */
149
    FWIDTH_SEMI_EXPANDED  = 6, /* 112.5% */
150
    FWIDTH_EXPANDED   = 7, /* 125% */
151
    FWIDTH_EXTRA_EXPANDED = 8, /* 150% */
152
    FWIDTH_ULTRA_EXPANDED = 9  /* 200% */
153
  };
154
155
  float get_width () const
156
0
  {
157
0
    switch (usWidthClass) {
158
0
    case FWIDTH_ULTRA_CONDENSED:return 50.f;
159
0
    case FWIDTH_EXTRA_CONDENSED:return 62.5f;
160
0
    case FWIDTH_CONDENSED:  return 75.f;
161
0
    case FWIDTH_SEMI_CONDENSED: return 87.5f;
162
0
    default:
163
0
    case FWIDTH_NORMAL:   return 100.f;
164
0
    case FWIDTH_SEMI_EXPANDED:  return 112.5f;
165
0
    case FWIDTH_EXPANDED: return 125.f;
166
0
    case FWIDTH_EXTRA_EXPANDED: return 150.f;
167
0
    case FWIDTH_ULTRA_EXPANDED: return 200.f;
168
0
    }
169
0
  }
170
171
  float map_wdth_to_widthclass(float width) const
172
0
  {
173
0
    if (width < 50) return 1.0f;
174
0
    if (width > 200) return 9.0f;
175
0
176
0
    float ratio = (width - 50) / 12.5f;
177
0
    int a = (int) floorf (ratio);
178
0
    int b = (int) ceilf (ratio);
179
0
180
0
    /* follow this maping:
181
0
     * https://docs.microsoft.com/en-us/typography/opentype/spec/os2#uswidthclass
182
0
     */
183
0
    if (b <= 6) // 50-125
184
0
    {
185
0
      if (a == b) return a + 1.0f;
186
0
    }
187
0
    else if (b == 7) // no mapping for 137.5
188
0
    {
189
0
      a = 6;
190
0
      b = 8;
191
0
    }
192
0
    else if (b == 8)
193
0
    {
194
0
      if (a == b) return 8.0f; // 150
195
0
      a = 6;
196
0
    }
197
0
    else
198
0
    {
199
0
      if (a == b && a == 12) return 9.0f; //200
200
0
      b = 12;
201
0
      a = 8;
202
0
    }
203
0
204
0
    float va = 50 + a * 12.5f;
205
0
    float vb = 50 + b * 12.5f;
206
0
207
0
    float ret =  a + (width - va) / (vb - va);
208
0
    if (a <= 6) ret += 1.0f;
209
0
    return ret;
210
0
  }
211
212
  bool subset (hb_subset_context_t *c) const
213
0
  {
214
0
    TRACE_SUBSET (this);
215
0
    OS2 *os2_prime = c->serializer->embed (this);
216
0
    if (unlikely (!os2_prime)) return_trace (false);
217
0
218
0
#ifndef HB_NO_VAR
219
0
    if (c->plan->normalized_coords)
220
0
    {
221
0
      auto &MVAR = *c->plan->source->table.MVAR;
222
0
      auto *table = os2_prime;
223
0
224
0
      HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER,         sTypoAscender);
225
0
      HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER,        sTypoDescender);
226
0
      HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP,         sTypoLineGap);
227
0
      HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_ASCENT,  usWinAscent);
228
0
      HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_DESCENT, usWinDescent);
229
0
      HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_SIZE,         ySubscriptXSize);
230
0
      HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_SIZE,         ySubscriptYSize);
231
0
      HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_OFFSET,       ySubscriptXOffset);
232
0
      HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_OFFSET,       ySubscriptYOffset);
233
0
      HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_SIZE,       ySuperscriptXSize);
234
0
      HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_SIZE,       ySuperscriptYSize);
235
0
      HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_OFFSET,     ySuperscriptXOffset);
236
0
      HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_OFFSET,     ySuperscriptYOffset);
237
0
      HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_STRIKEOUT_SIZE,              yStrikeoutSize);
238
0
      HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_STRIKEOUT_OFFSET,            yStrikeoutPosition);
239
0
240
0
      if (os2_prime->version >= 2)
241
0
      {
242
0
        auto *table = & const_cast<OS2V2Tail &> (os2_prime->v2 ());
243
0
        HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_X_HEIGHT,                   sxHeight);
244
0
        HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_CAP_HEIGHT,                 sCapHeight);
245
0
      }
246
0
    }
247
0
#endif
248
0
249
0
    if (c->plan->user_axes_location.has (HB_TAG ('w','g','h','t')) &&
250
0
        !c->plan->pinned_at_default)
251
0
    {
252
0
      float weight_class = c->plan->user_axes_location.get (HB_TAG ('w','g','h','t'));
253
0
      if (!c->serializer->check_assign (os2_prime->usWeightClass,
254
0
                                        roundf (hb_clamp (weight_class, 1.0f, 1000.0f)),
255
0
                                        HB_SERIALIZE_ERROR_INT_OVERFLOW))
256
0
        return_trace (false);
257
0
    }
258
0
259
0
    if (c->plan->user_axes_location.has (HB_TAG ('w','d','t','h')) &&
260
0
        !c->plan->pinned_at_default)
261
0
    {
262
0
      float width = c->plan->user_axes_location.get (HB_TAG ('w','d','t','h'));
263
0
      if (!c->serializer->check_assign (os2_prime->usWidthClass,
264
0
                                        roundf (map_wdth_to_widthclass (width)),
265
0
                                        HB_SERIALIZE_ERROR_INT_OVERFLOW))
266
0
        return_trace (false);
267
0
    }
268
0
269
0
    if (c->plan->flags & HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES)
270
0
      return_trace (true);
271
0
272
0
    os2_prime->usFirstCharIndex = hb_min (0xFFFFu, c->plan->unicodes.get_min ());
273
0
    os2_prime->usLastCharIndex  = hb_min (0xFFFFu, c->plan->unicodes.get_max ());
274
0
275
0
    _update_unicode_ranges (&c->plan->unicodes, os2_prime->ulUnicodeRange);
276
0
277
0
    return_trace (true);
278
0
  }
279
280
  void _update_unicode_ranges (const hb_set_t *codepoints,
281
             HBUINT32 ulUnicodeRange[4]) const
282
0
  {
283
0
    HBUINT32 newBits[4];
284
0
    for (unsigned int i = 0; i < 4; i++)
285
0
      newBits[i] = 0;
286
0
287
0
    /* This block doesn't show up in profiles. If it ever did,
288
0
     * we can rewrite it to iterate over OS/2 ranges and use
289
0
     * set iteration to check if the range matches. */
290
0
    for (hb_codepoint_t cp = HB_SET_VALUE_INVALID;
291
0
   codepoints->next (&cp);)
292
0
    {
293
0
      unsigned int bit = _hb_ot_os2_get_unicode_range_bit (cp);
294
0
      if (bit < 128)
295
0
      {
296
0
  unsigned int block = bit / 32;
297
0
  unsigned int bit_in_block = bit % 32;
298
0
  unsigned int mask = 1 << bit_in_block;
299
0
  newBits[block] = newBits[block] | mask;
300
0
      }
301
0
      if (cp >= 0x10000 && cp <= 0x110000)
302
0
      {
303
0
  /* the spec says that bit 57 ("Non Plane 0") implies that there's
304
0
     at least one codepoint beyond the BMP; so I also include all
305
0
     the non-BMP codepoints here */
306
0
  newBits[1] = newBits[1] | (1 << 25);
307
0
      }
308
0
    }
309
0
310
0
    for (unsigned int i = 0; i < 4; i++)
311
0
      ulUnicodeRange[i] = ulUnicodeRange[i] & newBits[i]; // set bits only if set in the original
312
0
  }
313
314
  /* https://github.com/Microsoft/Font-Validator/blob/520aaae/OTFontFileVal/val_OS2.cs#L644-L681
315
   * https://docs.microsoft.com/en-us/typography/legacy/legacy_arabic_fonts */
316
  enum font_page_t
317
  {
318
    FONT_PAGE_NONE    = 0,
319
    FONT_PAGE_HEBREW    = 0xB100, /* Hebrew Windows 3.1 font page */
320
    FONT_PAGE_SIMP_ARABIC = 0xB200, /* Simplified Arabic Windows 3.1 font page */
321
    FONT_PAGE_TRAD_ARABIC = 0xB300, /* Traditional Arabic Windows 3.1 font page */
322
    FONT_PAGE_OEM_ARABIC  = 0xB400, /* OEM Arabic Windows 3.1 font page */
323
    FONT_PAGE_SIMP_FARSI  = 0xBA00, /* Simplified Farsi Windows 3.1 font page */
324
    FONT_PAGE_TRAD_FARSI  = 0xBB00, /* Traditional Farsi Windows 3.1 font page */
325
    FONT_PAGE_THAI    = 0xDE00  /* Thai Windows 3.1 font page */
326
  };
327
  font_page_t get_font_page () const
328
4.72k
  { return (font_page_t) (version == 0 ? fsSelection & 0xFF00 : 0); }
329
330
  unsigned get_size () const
331
0
  {
332
0
    unsigned result = min_size;
333
0
    if (version >= 1) result += v1X.get_size ();
334
0
    if (version >= 2) result += v2X.get_size ();
335
0
    if (version >= 5) result += v5X.get_size ();
336
0
    return result;
337
0
  }
338
339
  bool sanitize (hb_sanitize_context_t *c) const
340
166k
  {
341
166k
    TRACE_SANITIZE (this);
342
166k
    if (unlikely (!c->check_struct (this))) return_trace (false);
343
165k
    if (unlikely (version >= 1 && !v1X.sanitize (c))) return_trace (false);
344
165k
    if (unlikely (version >= 2 && !v2X.sanitize (c))) return_trace (false);
345
162k
    if (unlikely (version >= 5 && !v5X.sanitize (c))) return_trace (false);
346
146k
    return_trace (true);
347
162k
  }
348
349
  public:
350
  HBUINT16  version;
351
  HBINT16 xAvgCharWidth;
352
  HBUINT16  usWeightClass;
353
  HBUINT16  usWidthClass;
354
  HBUINT16  fsType;
355
  HBINT16 ySubscriptXSize;
356
  HBINT16 ySubscriptYSize;
357
  HBINT16 ySubscriptXOffset;
358
  HBINT16 ySubscriptYOffset;
359
  HBINT16 ySuperscriptXSize;
360
  HBINT16 ySuperscriptYSize;
361
  HBINT16 ySuperscriptXOffset;
362
  HBINT16 ySuperscriptYOffset;
363
  HBINT16 yStrikeoutSize;
364
  HBINT16 yStrikeoutPosition;
365
  HBINT16 sFamilyClass;
366
  HBUINT8 panose[10];
367
  HBUINT32  ulUnicodeRange[4];
368
  Tag   achVendID;
369
  HBUINT16  fsSelection;
370
  HBUINT16  usFirstCharIndex;
371
  HBUINT16  usLastCharIndex;
372
  HBINT16 sTypoAscender;
373
  HBINT16 sTypoDescender;
374
  HBINT16 sTypoLineGap;
375
  HBUINT16  usWinAscent;
376
  HBUINT16  usWinDescent;
377
  OS2V1Tail v1X;
378
  OS2V2Tail v2X;
379
  OS2V5Tail v5X;
380
  public:
381
  DEFINE_SIZE_MIN (78);
382
};
383
384
} /* namespace OT */
385
386
387
#endif /* HB_OT_OS2_TABLE_HH */