1 /*
2 * Copyright © 2007,2008,2009 Red Hat, Inc.
3 * Copyright © 2010,2012 Google, Inc.
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 * Red Hat Author(s): Behdad Esfahbod
26 * Google Author(s): Behdad Esfahbod
27 */
28
29 #ifndef HB_OT_LAYOUT_COMMON_HH
30 #define HB_OT_LAYOUT_COMMON_HH
31
32 #include "hb.hh"
33 #include "hb-ot-layout.hh"
34 #include "hb-open-type.hh"
35 #include "hb-set.hh"
36
37
38 #ifndef HB_MAX_NESTING_LEVEL
39 #define HB_MAX_NESTING_LEVEL 6
40 #endif
41 #ifndef HB_MAX_CONTEXT_LENGTH
42 #define HB_MAX_CONTEXT_LENGTH 64
43 #endif
44 #ifndef HB_CLOSURE_MAX_STAGES
45 /*
46 * The maximum number of times a lookup can be applied during shaping.
47 * Used to limit the number of iterations of the closure algorithm.
48 * This must be larger than the number of times add_pause() is
49 * called in a collect_features call of any shaper.
50 */
51 #define HB_CLOSURE_MAX_STAGES 32
52 #endif
53
54 #ifndef HB_MAX_SCRIPTS
55 #define HB_MAX_SCRIPTS 500
56 #endif
57
58 #ifndef HB_MAX_LANGSYS
59 #define HB_MAX_LANGSYS 2000
60 #endif
61
62
63 namespace OT {
64
65
66 #define NOT_COVERED ((unsigned int) -1)
67
68
69 /*
70 *
71 * OpenType Layout Common Table Formats
72 *
73 */
74
75
76 /*
77 * Script, ScriptList, LangSys, Feature, FeatureList, Lookup, LookupList
78 */
79
80 struct Record_sanitize_closure_t {
81 hb_tag_t tag;
82 const void *list_base;
83 };
84
85 template <typename Type>
86 struct Record
87 {
cmpOT::Record88 int cmp (hb_tag_t a) const { return tag.cmp (a); }
89
sanitizeOT::Record90 bool sanitize (hb_sanitize_context_t *c, const void *base) const
91 {
92 TRACE_SANITIZE (this);
93 const Record_sanitize_closure_t closure = {tag, base};
94 return_trace (c->check_struct (this) && offset.sanitize (c, base, &closure));
95 }
96
97 Tag tag; /* 4-byte Tag identifier */
98 OffsetTo<Type>
99 offset; /* Offset from beginning of object holding
100 * the Record */
101 public:
102 DEFINE_SIZE_STATIC (6);
103 };
104
105 template <typename Type>
106 struct RecordArrayOf : SortedArrayOf<Record<Type>>
107 {
get_offsetOT::RecordArrayOf108 const OffsetTo<Type>& get_offset (unsigned int i) const
109 { return (*this)[i].offset; }
get_offsetOT::RecordArrayOf110 OffsetTo<Type>& get_offset (unsigned int i)
111 { return (*this)[i].offset; }
get_tagOT::RecordArrayOf112 const Tag& get_tag (unsigned int i) const
113 { return (*this)[i].tag; }
get_tagsOT::RecordArrayOf114 unsigned int get_tags (unsigned int start_offset,
115 unsigned int *record_count /* IN/OUT */,
116 hb_tag_t *record_tags /* OUT */) const
117 {
118 if (record_count) {
119 const Record<Type> *arr = this->sub_array (start_offset, record_count);
120 unsigned int count = *record_count;
121 for (unsigned int i = 0; i < count; i++)
122 record_tags[i] = arr[i].tag;
123 }
124 return this->len;
125 }
find_indexOT::RecordArrayOf126 bool find_index (hb_tag_t tag, unsigned int *index) const
127 {
128 return this->bfind (tag, index, HB_BFIND_NOT_FOUND_STORE, Index::NOT_FOUND_INDEX);
129 }
130 };
131
132 template <typename Type>
133 struct RecordListOf : RecordArrayOf<Type>
134 {
operator []OT::RecordListOf135 const Type& operator [] (unsigned int i) const
136 { return this+this->get_offset (i); }
137
subsetOT::RecordListOf138 bool subset (hb_subset_context_t *c) const
139 {
140 TRACE_SUBSET (this);
141 auto *out = c->serializer->embed (*this);
142 if (unlikely (!out)) return_trace (false);
143 unsigned int count = this->len;
144 for (unsigned int i = 0; i < count; i++)
145 out->get_offset (i).serialize_subset (c, this->get_offset (i), this, out);
146 return_trace (true);
147 }
148
sanitizeOT::RecordListOf149 bool sanitize (hb_sanitize_context_t *c) const
150 {
151 TRACE_SANITIZE (this);
152 return_trace (RecordArrayOf<Type>::sanitize (c, this));
153 }
154 };
155
156
157 struct RangeRecord
158 {
cmpOT::RangeRecord159 int cmp (hb_codepoint_t g) const
160 { return g < start ? -1 : g <= end ? 0 : +1; }
161
sanitizeOT::RangeRecord162 bool sanitize (hb_sanitize_context_t *c) const
163 {
164 TRACE_SANITIZE (this);
165 return_trace (c->check_struct (this));
166 }
167
intersectsOT::RangeRecord168 bool intersects (const hb_set_t *glyphs) const
169 { return glyphs->intersects (start, end); }
170
171 template <typename set_t>
add_coverageOT::RangeRecord172 bool add_coverage (set_t *glyphs) const
173 { return glyphs->add_range (start, end); }
174
175 GlyphID start; /* First GlyphID in the range */
176 GlyphID end; /* Last GlyphID in the range */
177 HBUINT16 value; /* Value */
178 public:
179 DEFINE_SIZE_STATIC (6);
180 };
181 DECLARE_NULL_NAMESPACE_BYTES (OT, RangeRecord);
182
183
184 struct IndexArray : ArrayOf<Index>
185 {
get_indexesOT::IndexArray186 unsigned int get_indexes (unsigned int start_offset,
187 unsigned int *_count /* IN/OUT */,
188 unsigned int *_indexes /* OUT */) const
189 {
190 if (_count) {
191 const HBUINT16 *arr = this->sub_array (start_offset, _count);
192 unsigned int count = *_count;
193 for (unsigned int i = 0; i < count; i++)
194 _indexes[i] = arr[i];
195 }
196 return this->len;
197 }
198
add_indexes_toOT::IndexArray199 void add_indexes_to (hb_set_t* output /* OUT */) const
200 {
201 output->add_array (arrayZ, len);
202 }
203 };
204
205
206 struct Script;
207 struct LangSys;
208 struct Feature;
209
210
211 struct LangSys
212 {
get_feature_countOT::LangSys213 unsigned int get_feature_count () const
214 { return featureIndex.len; }
get_feature_indexOT::LangSys215 hb_tag_t get_feature_index (unsigned int i) const
216 { return featureIndex[i]; }
get_feature_indexesOT::LangSys217 unsigned int get_feature_indexes (unsigned int start_offset,
218 unsigned int *feature_count /* IN/OUT */,
219 unsigned int *feature_indexes /* OUT */) const
220 { return featureIndex.get_indexes (start_offset, feature_count, feature_indexes); }
add_feature_indexes_toOT::LangSys221 void add_feature_indexes_to (hb_set_t *feature_indexes) const
222 { featureIndex.add_indexes_to (feature_indexes); }
223
has_required_featureOT::LangSys224 bool has_required_feature () const { return reqFeatureIndex != 0xFFFFu; }
get_required_feature_indexOT::LangSys225 unsigned int get_required_feature_index () const
226 {
227 if (reqFeatureIndex == 0xFFFFu)
228 return Index::NOT_FOUND_INDEX;
229 return reqFeatureIndex;
230 }
231
copyOT::LangSys232 LangSys* copy (hb_serialize_context_t *c) const
233 {
234 TRACE_SERIALIZE (this);
235 return_trace (c->embed (*this));
236 }
237
sanitizeOT::LangSys238 bool sanitize (hb_sanitize_context_t *c,
239 const Record_sanitize_closure_t * = nullptr) const
240 {
241 TRACE_SANITIZE (this);
242 return_trace (c->check_struct (this) && featureIndex.sanitize (c));
243 }
244
245 Offset16 lookupOrderZ; /* = Null (reserved for an offset to a
246 * reordering table) */
247 HBUINT16 reqFeatureIndex;/* Index of a feature required for this
248 * language system--if no required features
249 * = 0xFFFFu */
250 IndexArray featureIndex; /* Array of indices into the FeatureList */
251 public:
252 DEFINE_SIZE_ARRAY_SIZED (6, featureIndex);
253 };
254 DECLARE_NULL_NAMESPACE_BYTES (OT, LangSys);
255
256 struct Script
257 {
get_lang_sys_countOT::Script258 unsigned int get_lang_sys_count () const
259 { return langSys.len; }
get_lang_sys_tagOT::Script260 const Tag& get_lang_sys_tag (unsigned int i) const
261 { return langSys.get_tag (i); }
get_lang_sys_tagsOT::Script262 unsigned int get_lang_sys_tags (unsigned int start_offset,
263 unsigned int *lang_sys_count /* IN/OUT */,
264 hb_tag_t *lang_sys_tags /* OUT */) const
265 { return langSys.get_tags (start_offset, lang_sys_count, lang_sys_tags); }
get_lang_sysOT::Script266 const LangSys& get_lang_sys (unsigned int i) const
267 {
268 if (i == Index::NOT_FOUND_INDEX) return get_default_lang_sys ();
269 return this+langSys[i].offset;
270 }
find_lang_sys_indexOT::Script271 bool find_lang_sys_index (hb_tag_t tag, unsigned int *index) const
272 { return langSys.find_index (tag, index); }
273
has_default_lang_sysOT::Script274 bool has_default_lang_sys () const { return defaultLangSys != 0; }
get_default_lang_sysOT::Script275 const LangSys& get_default_lang_sys () const { return this+defaultLangSys; }
276
subsetOT::Script277 bool subset (hb_subset_context_t *c) const
278 {
279 TRACE_SUBSET (this);
280 auto *out = c->serializer->embed (*this);
281 if (unlikely (!out)) return_trace (false);
282 out->defaultLangSys.serialize_copy (c->serializer, defaultLangSys, this, out);
283 unsigned int count = langSys.len;
284 for (unsigned int i = 0; i < count; i++)
285 out->langSys.arrayZ[i].offset.serialize_copy (c->serializer, langSys[i].offset, this, out);
286 return_trace (true);
287 }
288
sanitizeOT::Script289 bool sanitize (hb_sanitize_context_t *c,
290 const Record_sanitize_closure_t * = nullptr) const
291 {
292 TRACE_SANITIZE (this);
293 return_trace (defaultLangSys.sanitize (c, this) && langSys.sanitize (c, this));
294 }
295
296 protected:
297 OffsetTo<LangSys>
298 defaultLangSys; /* Offset to DefaultLangSys table--from
299 * beginning of Script table--may be Null */
300 RecordArrayOf<LangSys>
301 langSys; /* Array of LangSysRecords--listed
302 * alphabetically by LangSysTag */
303 public:
304 DEFINE_SIZE_ARRAY_SIZED (4, langSys);
305 };
306
307 typedef RecordListOf<Script> ScriptList;
308
309
310 /* https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#size */
311 struct FeatureParamsSize
312 {
sanitizeOT::FeatureParamsSize313 bool sanitize (hb_sanitize_context_t *c) const
314 {
315 TRACE_SANITIZE (this);
316 if (unlikely (!c->check_struct (this))) return_trace (false);
317
318 /* This subtable has some "history", if you will. Some earlier versions of
319 * Adobe tools calculated the offset of the FeatureParams sutable from the
320 * beginning of the FeatureList table! Now, that is dealt with in the
321 * Feature implementation. But we still need to be able to tell junk from
322 * real data. Note: We don't check that the nameID actually exists.
323 *
324 * Read Roberts wrote on 9/15/06 on opentype-list@indx.co.uk :
325 *
326 * Yes, it is correct that a new version of the AFDKO (version 2.0) will be
327 * coming out soon, and that the makeotf program will build a font with a
328 * 'size' feature that is correct by the specification.
329 *
330 * The specification for this feature tag is in the "OpenType Layout Tag
331 * Registry". You can see a copy of this at:
332 * https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#tag-size
333 *
334 * Here is one set of rules to determine if the 'size' feature is built
335 * correctly, or as by the older versions of MakeOTF. You may be able to do
336 * better.
337 *
338 * Assume that the offset to the size feature is according to specification,
339 * and make the following value checks. If it fails, assume the size
340 * feature is calculated as versions of MakeOTF before the AFDKO 2.0 built it.
341 * If this fails, reject the 'size' feature. The older makeOTF's calculated the
342 * offset from the beginning of the FeatureList table, rather than from the
343 * beginning of the 'size' Feature table.
344 *
345 * If "design size" == 0:
346 * fails check
347 *
348 * Else if ("subfamily identifier" == 0 and
349 * "range start" == 0 and
350 * "range end" == 0 and
351 * "range start" == 0 and
352 * "menu name ID" == 0)
353 * passes check: this is the format used when there is a design size
354 * specified, but there is no recommended size range.
355 *
356 * Else if ("design size" < "range start" or
357 * "design size" > "range end" or
358 * "range end" <= "range start" or
359 * "menu name ID" < 256 or
360 * "menu name ID" > 32767 or
361 * menu name ID is not a name ID which is actually in the name table)
362 * fails test
363 * Else
364 * passes test.
365 */
366
367 if (!designSize)
368 return_trace (false);
369 else if (subfamilyID == 0 &&
370 subfamilyNameID == 0 &&
371 rangeStart == 0 &&
372 rangeEnd == 0)
373 return_trace (true);
374 else if (designSize < rangeStart ||
375 designSize > rangeEnd ||
376 subfamilyNameID < 256 ||
377 subfamilyNameID > 32767)
378 return_trace (false);
379 else
380 return_trace (true);
381 }
382
383 HBUINT16 designSize; /* Represents the design size in 720/inch
384 * units (decipoints). The design size entry
385 * must be non-zero. When there is a design
386 * size but no recommended size range, the
387 * rest of the array will consist of zeros. */
388 HBUINT16 subfamilyID; /* Has no independent meaning, but serves
389 * as an identifier that associates fonts
390 * in a subfamily. All fonts which share a
391 * Preferred or Font Family name and which
392 * differ only by size range shall have the
393 * same subfamily value, and no fonts which
394 * differ in weight or style shall have the
395 * same subfamily value. If this value is
396 * zero, the remaining fields in the array
397 * will be ignored. */
398 NameID subfamilyNameID;/* If the preceding value is non-zero, this
399 * value must be set in the range 256 - 32767
400 * (inclusive). It records the value of a
401 * field in the name table, which must
402 * contain English-language strings encoded
403 * in Windows Unicode and Macintosh Roman,
404 * and may contain additional strings
405 * localized to other scripts and languages.
406 * Each of these strings is the name an
407 * application should use, in combination
408 * with the family name, to represent the
409 * subfamily in a menu. Applications will
410 * choose the appropriate version based on
411 * their selection criteria. */
412 HBUINT16 rangeStart; /* Large end of the recommended usage range
413 * (inclusive), stored in 720/inch units
414 * (decipoints). */
415 HBUINT16 rangeEnd; /* Small end of the recommended usage range
416 (exclusive), stored in 720/inch units
417 * (decipoints). */
418 public:
419 DEFINE_SIZE_STATIC (10);
420 };
421
422 /* https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#ssxx */
423 struct FeatureParamsStylisticSet
424 {
sanitizeOT::FeatureParamsStylisticSet425 bool sanitize (hb_sanitize_context_t *c) const
426 {
427 TRACE_SANITIZE (this);
428 /* Right now minorVersion is at zero. Which means, any table supports
429 * the uiNameID field. */
430 return_trace (c->check_struct (this));
431 }
432
433 HBUINT16 version; /* (set to 0): This corresponds to a “minor”
434 * version number. Additional data may be
435 * added to the end of this Feature Parameters
436 * table in the future. */
437
438 NameID uiNameID; /* The 'name' table name ID that specifies a
439 * string (or strings, for multiple languages)
440 * for a user-interface label for this
441 * feature. The values of uiLabelNameId and
442 * sampleTextNameId are expected to be in the
443 * font-specific name ID range (256-32767),
444 * though that is not a requirement in this
445 * Feature Parameters specification. The
446 * user-interface label for the feature can
447 * be provided in multiple languages. An
448 * English string should be included as a
449 * fallback. The string should be kept to a
450 * minimal length to fit comfortably with
451 * different application interfaces. */
452 public:
453 DEFINE_SIZE_STATIC (4);
454 };
455
456 /* https://docs.microsoft.com/en-us/typography/opentype/spec/features_ae#cv01-cv99 */
457 struct FeatureParamsCharacterVariants
458 {
sanitizeOT::FeatureParamsCharacterVariants459 bool sanitize (hb_sanitize_context_t *c) const
460 {
461 TRACE_SANITIZE (this);
462 return_trace (c->check_struct (this) &&
463 characters.sanitize (c));
464 }
465
466 HBUINT16 format; /* Format number is set to 0. */
467 NameID featUILableNameID; /* The ‘name’ table name ID that
468 * specifies a string (or strings,
469 * for multiple languages) for a
470 * user-interface label for this
471 * feature. (May be NULL.) */
472 NameID featUITooltipTextNameID;/* The ‘name’ table name ID that
473 * specifies a string (or strings,
474 * for multiple languages) that an
475 * application can use for tooltip
476 * text for this feature. (May be
477 * nullptr.) */
478 NameID sampleTextNameID; /* The ‘name’ table name ID that
479 * specifies sample text that
480 * illustrates the effect of this
481 * feature. (May be NULL.) */
482 HBUINT16 numNamedParameters; /* Number of named parameters. (May
483 * be zero.) */
484 NameID firstParamUILabelNameID;/* The first ‘name’ table name ID
485 * used to specify strings for
486 * user-interface labels for the
487 * feature parameters. (Must be zero
488 * if numParameters is zero.) */
489 ArrayOf<HBUINT24>
490 characters; /* Array of the Unicode Scalar Value
491 * of the characters for which this
492 * feature provides glyph variants.
493 * (May be zero.) */
494 public:
495 DEFINE_SIZE_ARRAY (14, characters);
496 };
497
498 struct FeatureParams
499 {
sanitizeOT::FeatureParams500 bool sanitize (hb_sanitize_context_t *c, hb_tag_t tag) const
501 {
502 TRACE_SANITIZE (this);
503 if (tag == HB_TAG ('s','i','z','e'))
504 return_trace (u.size.sanitize (c));
505 if ((tag & 0xFFFF0000u) == HB_TAG ('s','s','\0','\0')) /* ssXX */
506 return_trace (u.stylisticSet.sanitize (c));
507 if ((tag & 0xFFFF0000u) == HB_TAG ('c','v','\0','\0')) /* cvXX */
508 return_trace (u.characterVariants.sanitize (c));
509 return_trace (true);
510 }
511
get_size_paramsOT::FeatureParams512 const FeatureParamsSize& get_size_params (hb_tag_t tag) const
513 {
514 if (tag == HB_TAG ('s','i','z','e'))
515 return u.size;
516 return Null (FeatureParamsSize);
517 }
518
get_stylistic_set_paramsOT::FeatureParams519 const FeatureParamsStylisticSet& get_stylistic_set_params (hb_tag_t tag) const
520 {
521 if ((tag & 0xFFFF0000u) == HB_TAG ('s','s','\0','\0')) /* ssXX */
522 return u.stylisticSet;
523 return Null (FeatureParamsStylisticSet);
524 }
525
get_character_variants_paramsOT::FeatureParams526 const FeatureParamsCharacterVariants& get_character_variants_params (hb_tag_t tag) const
527 {
528 if ((tag & 0xFFFF0000u) == HB_TAG ('c','v','\0','\0')) /* cvXX */
529 return u.characterVariants;
530 return Null (FeatureParamsCharacterVariants);
531 }
532
533 private:
534 union {
535 FeatureParamsSize size;
536 FeatureParamsStylisticSet stylisticSet;
537 FeatureParamsCharacterVariants characterVariants;
538 } u;
539 public:
540 DEFINE_SIZE_STATIC (17);
541 };
542
543 struct Feature
544 {
get_lookup_countOT::Feature545 unsigned int get_lookup_count () const
546 { return lookupIndex.len; }
get_lookup_indexOT::Feature547 hb_tag_t get_lookup_index (unsigned int i) const
548 { return lookupIndex[i]; }
get_lookup_indexesOT::Feature549 unsigned int get_lookup_indexes (unsigned int start_index,
550 unsigned int *lookup_count /* IN/OUT */,
551 unsigned int *lookup_tags /* OUT */) const
552 { return lookupIndex.get_indexes (start_index, lookup_count, lookup_tags); }
add_lookup_indexes_toOT::Feature553 void add_lookup_indexes_to (hb_set_t *lookup_indexes) const
554 { lookupIndex.add_indexes_to (lookup_indexes); }
555
get_feature_paramsOT::Feature556 const FeatureParams &get_feature_params () const
557 { return this+featureParams; }
558
subsetOT::Feature559 bool subset (hb_subset_context_t *c) const
560 {
561 TRACE_SUBSET (this);
562 auto *out = c->serializer->embed (*this);
563 if (unlikely (!out)) return_trace (false);
564 out->featureParams = 0; /* TODO(subset) FeatureParams. */
565 return_trace (true);
566 }
567
sanitizeOT::Feature568 bool sanitize (hb_sanitize_context_t *c,
569 const Record_sanitize_closure_t *closure = nullptr) const
570 {
571 TRACE_SANITIZE (this);
572 if (unlikely (!(c->check_struct (this) && lookupIndex.sanitize (c))))
573 return_trace (false);
574
575 /* Some earlier versions of Adobe tools calculated the offset of the
576 * FeatureParams subtable from the beginning of the FeatureList table!
577 *
578 * If sanitizing "failed" for the FeatureParams subtable, try it with the
579 * alternative location. We would know sanitize "failed" if old value
580 * of the offset was non-zero, but it's zeroed now.
581 *
582 * Only do this for the 'size' feature, since at the time of the faulty
583 * Adobe tools, only the 'size' feature had FeatureParams defined.
584 */
585
586 if (likely (featureParams.is_null ()))
587 return_trace (true);
588
589 unsigned int orig_offset = featureParams;
590 if (unlikely (!featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE)))
591 return_trace (false);
592
593 if (featureParams == 0 && closure &&
594 closure->tag == HB_TAG ('s','i','z','e') &&
595 closure->list_base && closure->list_base < this)
596 {
597 unsigned int new_offset_int = orig_offset -
598 (((char *) this) - ((char *) closure->list_base));
599
600 OffsetTo<FeatureParams> new_offset;
601 /* Check that it would not overflow. */
602 new_offset = new_offset_int;
603 if (new_offset == new_offset_int &&
604 c->try_set (&featureParams, new_offset_int) &&
605 !featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE))
606 return_trace (false);
607 }
608
609 return_trace (true);
610 }
611
612 OffsetTo<FeatureParams>
613 featureParams; /* Offset to Feature Parameters table (if one
614 * has been defined for the feature), relative
615 * to the beginning of the Feature Table; = Null
616 * if not required */
617 IndexArray lookupIndex; /* Array of LookupList indices */
618 public:
619 DEFINE_SIZE_ARRAY_SIZED (4, lookupIndex);
620 };
621
622 typedef RecordListOf<Feature> FeatureList;
623
624
625 struct LookupFlag : HBUINT16
626 {
627 enum Flags {
628 RightToLeft = 0x0001u,
629 IgnoreBaseGlyphs = 0x0002u,
630 IgnoreLigatures = 0x0004u,
631 IgnoreMarks = 0x0008u,
632 IgnoreFlags = 0x000Eu,
633 UseMarkFilteringSet = 0x0010u,
634 Reserved = 0x00E0u,
635 MarkAttachmentType = 0xFF00u
636 };
637 public:
638 DEFINE_SIZE_STATIC (2);
639 };
640
641 } /* namespace OT */
642 /* This has to be outside the namespace. */
643 HB_MARK_AS_FLAG_T (OT::LookupFlag::Flags);
644 namespace OT {
645
646 struct Lookup
647 {
get_subtable_countOT::Lookup648 unsigned int get_subtable_count () const { return subTable.len; }
649
650 template <typename TSubTable>
get_subtablesOT::Lookup651 const OffsetArrayOf<TSubTable>& get_subtables () const
652 { return CastR<OffsetArrayOf<TSubTable>> (subTable); }
653 template <typename TSubTable>
get_subtablesOT::Lookup654 OffsetArrayOf<TSubTable>& get_subtables ()
655 { return CastR<OffsetArrayOf<TSubTable>> (subTable); }
656
657 template <typename TSubTable>
get_subtableOT::Lookup658 const TSubTable& get_subtable (unsigned int i) const
659 { return this+get_subtables<TSubTable> ()[i]; }
660 template <typename TSubTable>
get_subtableOT::Lookup661 TSubTable& get_subtable (unsigned int i)
662 { return this+get_subtables<TSubTable> ()[i]; }
663
get_sizeOT::Lookup664 unsigned int get_size () const
665 {
666 const HBUINT16 &markFilteringSet = StructAfter<const HBUINT16> (subTable);
667 if (lookupFlag & LookupFlag::UseMarkFilteringSet)
668 return (const char *) &StructAfter<const char> (markFilteringSet) - (const char *) this;
669 return (const char *) &markFilteringSet - (const char *) this;
670 }
671
get_typeOT::Lookup672 unsigned int get_type () const { return lookupType; }
673
674 /* lookup_props is a 32-bit integer where the lower 16-bit is LookupFlag and
675 * higher 16-bit is mark-filtering-set if the lookup uses one.
676 * Not to be confused with glyph_props which is very similar. */
get_propsOT::Lookup677 uint32_t get_props () const
678 {
679 unsigned int flag = lookupFlag;
680 if (unlikely (flag & LookupFlag::UseMarkFilteringSet))
681 {
682 const HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
683 flag += (markFilteringSet << 16);
684 }
685 return flag;
686 }
687
688 template <typename TSubTable, typename context_t, typename ...Ts>
dispatchOT::Lookup689 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
690 {
691 unsigned int lookup_type = get_type ();
692 TRACE_DISPATCH (this, lookup_type);
693 unsigned int count = get_subtable_count ();
694 for (unsigned int i = 0; i < count; i++) {
695 typename context_t::return_t r = get_subtable<TSubTable> (i).dispatch (c, lookup_type, hb_forward<Ts> (ds)...);
696 if (c->stop_sublookup_iteration (r))
697 return_trace (r);
698 }
699 return_trace (c->default_return_value ());
700 }
701
serializeOT::Lookup702 bool serialize (hb_serialize_context_t *c,
703 unsigned int lookup_type,
704 uint32_t lookup_props,
705 unsigned int num_subtables)
706 {
707 TRACE_SERIALIZE (this);
708 if (unlikely (!c->extend_min (*this))) return_trace (false);
709 lookupType = lookup_type;
710 lookupFlag = lookup_props & 0xFFFFu;
711 if (unlikely (!subTable.serialize (c, num_subtables))) return_trace (false);
712 if (lookupFlag & LookupFlag::UseMarkFilteringSet)
713 {
714 if (unlikely (!c->extend (*this))) return_trace (false);
715 HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
716 markFilteringSet = lookup_props >> 16;
717 }
718 return_trace (true);
719 }
720
721 template <typename TSubTable>
subsetOT::Lookup722 bool subset (hb_subset_context_t *c) const
723 {
724 TRACE_SUBSET (this);
725 auto *out = c->serializer->embed (*this);
726 if (unlikely (!out)) return_trace (false);
727
728 /* Subset the actual subtables. */
729 /* TODO Drop empty ones, either by calling intersects() beforehand,
730 * or just dropping null offsets after. */
731 const OffsetArrayOf<TSubTable>& subtables = get_subtables<TSubTable> ();
732 OffsetArrayOf<TSubTable>& out_subtables = out->get_subtables<TSubTable> ();
733 unsigned int count = subTable.len;
734 for (unsigned int i = 0; i < count; i++)
735 out_subtables[i].serialize_subset (c, subtables[i], this, out, get_type ());
736
737 return_trace (true);
738 }
739
740 template <typename TSubTable>
sanitizeOT::Lookup741 bool sanitize (hb_sanitize_context_t *c) const
742 {
743 TRACE_SANITIZE (this);
744 if (!(c->check_struct (this) && subTable.sanitize (c))) return_trace (false);
745 if (lookupFlag & LookupFlag::UseMarkFilteringSet)
746 {
747 const HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
748 if (!markFilteringSet.sanitize (c)) return_trace (false);
749 }
750
751 if (unlikely (!get_subtables<TSubTable> ().sanitize (c, this, get_type ())))
752 return_trace (false);
753
754 if (unlikely (get_type () == TSubTable::Extension && !c->get_edit_count ()))
755 {
756 /* The spec says all subtables of an Extension lookup should
757 * have the same type, which shall not be the Extension type
758 * itself (but we already checked for that).
759 * This is specially important if one has a reverse type!
760 *
761 * We only do this if sanitizer edit_count is zero. Otherwise,
762 * some of the subtables might have become insane after they
763 * were sanity-checked by the edits of subsequent subtables.
764 * https://bugs.chromium.org/p/chromium/issues/detail?id=960331
765 */
766 unsigned int type = get_subtable<TSubTable> (0).u.extension.get_type ();
767 unsigned int count = get_subtable_count ();
768 for (unsigned int i = 1; i < count; i++)
769 if (get_subtable<TSubTable> (i).u.extension.get_type () != type)
770 return_trace (false);
771 }
772 return_trace (true);
773 }
774
775 private:
776 HBUINT16 lookupType; /* Different enumerations for GSUB and GPOS */
777 HBUINT16 lookupFlag; /* Lookup qualifiers */
778 ArrayOf<Offset16>
779 subTable; /* Array of SubTables */
780 /*HBUINT16 markFilteringSetX[VAR];*//* Index (base 0) into GDEF mark glyph sets
781 * structure. This field is only present if bit
782 * UseMarkFilteringSet of lookup flags is set. */
783 public:
784 DEFINE_SIZE_ARRAY (6, subTable);
785 };
786
787 typedef OffsetListOf<Lookup> LookupList;
788
789
790 /*
791 * Coverage Table
792 */
793
794 struct CoverageFormat1
795 {
796 friend struct Coverage;
797
798 private:
get_coverageOT::CoverageFormat1799 unsigned int get_coverage (hb_codepoint_t glyph_id) const
800 {
801 unsigned int i;
802 glyphArray.bfind (glyph_id, &i, HB_BFIND_NOT_FOUND_STORE, NOT_COVERED);
803 return i;
804 }
805
806 template <typename Iterator,
807 hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
serializeOT::CoverageFormat1808 bool serialize (hb_serialize_context_t *c, Iterator glyphs)
809 {
810 TRACE_SERIALIZE (this);
811 return_trace (glyphArray.serialize (c, glyphs));
812 }
813
sanitizeOT::CoverageFormat1814 bool sanitize (hb_sanitize_context_t *c) const
815 {
816 TRACE_SANITIZE (this);
817 return_trace (glyphArray.sanitize (c));
818 }
819
intersectsOT::CoverageFormat1820 bool intersects (const hb_set_t *glyphs) const
821 {
822 /* TODO Speed up, using hb_set_next() and bsearch()? */
823 unsigned int count = glyphArray.len;
824 for (unsigned int i = 0; i < count; i++)
825 if (glyphs->has (glyphArray[i]))
826 return true;
827 return false;
828 }
intersects_coverageOT::CoverageFormat1829 bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
830 { return glyphs->has (glyphArray[index]); }
831
832 template <typename set_t>
add_coverageOT::CoverageFormat1833 bool add_coverage (set_t *glyphs) const
834 { return glyphs->add_sorted_array (glyphArray.arrayZ, glyphArray.len); }
835
836 public:
837 /* Older compilers need this to be public. */
838 struct iter_t
839 {
initOT::CoverageFormat1::iter_t840 void init (const struct CoverageFormat1 &c_) { c = &c_; i = 0; }
finiOT::CoverageFormat1::iter_t841 void fini () {}
moreOT::CoverageFormat1::iter_t842 bool more () const { return i < c->glyphArray.len; }
nextOT::CoverageFormat1::iter_t843 void next () { i++; }
get_glyphOT::CoverageFormat1::iter_t844 hb_codepoint_t get_glyph () const { return c->glyphArray[i]; }
operator !=OT::CoverageFormat1::iter_t845 bool operator != (const iter_t& o) const
846 { return i != o.i || c != o.c; }
847
848 private:
849 const struct CoverageFormat1 *c;
850 unsigned int i;
851 };
852 private:
853
854 protected:
855 HBUINT16 coverageFormat; /* Format identifier--format = 1 */
856 SortedArrayOf<GlyphID>
857 glyphArray; /* Array of GlyphIDs--in numerical order */
858 public:
859 DEFINE_SIZE_ARRAY (4, glyphArray);
860 };
861
862 struct CoverageFormat2
863 {
864 friend struct Coverage;
865
866 private:
get_coverageOT::CoverageFormat2867 unsigned int get_coverage (hb_codepoint_t glyph_id) const
868 {
869 const RangeRecord &range = rangeRecord.bsearch (glyph_id);
870 return likely (range.start <= range.end) ?
871 (unsigned int) range.value + (glyph_id - range.start) :
872 NOT_COVERED;
873 }
874
875 template <typename Iterator,
876 hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
serializeOT::CoverageFormat2877 bool serialize (hb_serialize_context_t *c, Iterator glyphs)
878 {
879 TRACE_SERIALIZE (this);
880 if (unlikely (!c->extend_min (*this))) return_trace (false);
881
882 if (unlikely (!glyphs))
883 {
884 rangeRecord.len = 0;
885 return_trace (true);
886 }
887
888 /* TODO(iter) Write more efficiently? */
889
890 unsigned num_ranges = 0;
891 hb_codepoint_t last = (hb_codepoint_t) -2;
892 for (auto g: glyphs)
893 {
894 if (last + 1 != g)
895 num_ranges++;
896 last = g;
897 }
898
899 if (unlikely (!rangeRecord.serialize (c, num_ranges))) return_trace (false);
900
901 unsigned count = 0;
902 unsigned range = (unsigned) -1;
903 last = (hb_codepoint_t) -2;
904 for (auto g: glyphs)
905 {
906 if (last + 1 != g)
907 {
908 range++;
909 rangeRecord[range].start = g;
910 rangeRecord[range].value = count;
911 }
912 rangeRecord[range].end = g;
913 last = g;
914 count++;
915 }
916
917 return_trace (true);
918 }
919
sanitizeOT::CoverageFormat2920 bool sanitize (hb_sanitize_context_t *c) const
921 {
922 TRACE_SANITIZE (this);
923 return_trace (rangeRecord.sanitize (c));
924 }
925
intersectsOT::CoverageFormat2926 bool intersects (const hb_set_t *glyphs) const
927 {
928 /* TODO Speed up, using hb_set_next() and bsearch()? */
929 unsigned int count = rangeRecord.len;
930 for (unsigned int i = 0; i < count; i++)
931 if (rangeRecord[i].intersects (glyphs))
932 return true;
933 return false;
934 }
intersects_coverageOT::CoverageFormat2935 bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
936 {
937 unsigned int i;
938 unsigned int count = rangeRecord.len;
939 for (i = 0; i < count; i++) {
940 const RangeRecord &range = rangeRecord[i];
941 if (range.value <= index &&
942 index < (unsigned int) range.value + (range.end - range.start) &&
943 range.intersects (glyphs))
944 return true;
945 else if (index < range.value)
946 return false;
947 }
948 return false;
949 }
950
951 template <typename set_t>
add_coverageOT::CoverageFormat2952 bool add_coverage (set_t *glyphs) const
953 {
954 unsigned int count = rangeRecord.len;
955 for (unsigned int i = 0; i < count; i++)
956 if (unlikely (!rangeRecord[i].add_coverage (glyphs)))
957 return false;
958 return true;
959 }
960
961 public:
962 /* Older compilers need this to be public. */
963 struct iter_t
964 {
initOT::CoverageFormat2::iter_t965 void init (const CoverageFormat2 &c_)
966 {
967 c = &c_;
968 coverage = 0;
969 i = 0;
970 j = c->rangeRecord.len ? c->rangeRecord[0].start : 0;
971 if (unlikely (c->rangeRecord[0].start > c->rangeRecord[0].end))
972 {
973 /* Broken table. Skip. */
974 i = c->rangeRecord.len;
975 }
976 }
finiOT::CoverageFormat2::iter_t977 void fini () {}
moreOT::CoverageFormat2::iter_t978 bool more () const { return i < c->rangeRecord.len; }
nextOT::CoverageFormat2::iter_t979 void next ()
980 {
981 if (j >= c->rangeRecord[i].end)
982 {
983 i++;
984 if (more ())
985 {
986 unsigned int old = coverage;
987 j = c->rangeRecord[i].start;
988 coverage = c->rangeRecord[i].value;
989 if (unlikely (coverage != old + 1))
990 {
991 /* Broken table. Skip. Important to avoid DoS.
992 * Also, our callers depend on coverage being
993 * consecutive and monotonically increasing,
994 * ie. iota(). */
995 i = c->rangeRecord.len;
996 return;
997 }
998 }
999 return;
1000 }
1001 coverage++;
1002 j++;
1003 }
get_glyphOT::CoverageFormat2::iter_t1004 hb_codepoint_t get_glyph () const { return j; }
operator !=OT::CoverageFormat2::iter_t1005 bool operator != (const iter_t& o) const
1006 { return i != o.i || j != o.j || c != o.c; }
1007
1008 private:
1009 const struct CoverageFormat2 *c;
1010 unsigned int i, coverage;
1011 hb_codepoint_t j;
1012 };
1013 private:
1014
1015 protected:
1016 HBUINT16 coverageFormat; /* Format identifier--format = 2 */
1017 SortedArrayOf<RangeRecord>
1018 rangeRecord; /* Array of glyph ranges--ordered by
1019 * Start GlyphID. rangeCount entries
1020 * long */
1021 public:
1022 DEFINE_SIZE_ARRAY (4, rangeRecord);
1023 };
1024
1025 struct Coverage
1026 {
1027 /* Has interface. */
1028 static constexpr unsigned SENTINEL = NOT_COVERED;
1029 typedef unsigned int value_t;
operator []OT::Coverage1030 value_t operator [] (hb_codepoint_t k) const { return get (k); }
hasOT::Coverage1031 bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
1032 /* Predicate. */
operator ()OT::Coverage1033 bool operator () (hb_codepoint_t k) const { return has (k); }
1034
getOT::Coverage1035 unsigned int get (hb_codepoint_t k) const { return get_coverage (k); }
get_coverageOT::Coverage1036 unsigned int get_coverage (hb_codepoint_t glyph_id) const
1037 {
1038 switch (u.format) {
1039 case 1: return u.format1.get_coverage (glyph_id);
1040 case 2: return u.format2.get_coverage (glyph_id);
1041 default:return NOT_COVERED;
1042 }
1043 }
1044
1045 template <typename Iterator,
1046 hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
serializeOT::Coverage1047 bool serialize (hb_serialize_context_t *c, Iterator glyphs)
1048 {
1049 TRACE_SERIALIZE (this);
1050 if (unlikely (!c->extend_min (*this))) return_trace (false);
1051
1052 unsigned count = 0;
1053 unsigned num_ranges = 0;
1054 hb_codepoint_t last = (hb_codepoint_t) -2;
1055 for (auto g: glyphs)
1056 {
1057 if (last + 1 != g)
1058 num_ranges++;
1059 last = g;
1060 count++;
1061 }
1062 u.format = count * 2 < num_ranges * 3 ? 1 : 2;
1063
1064 switch (u.format)
1065 {
1066 case 1: return_trace (u.format1.serialize (c, glyphs));
1067 case 2: return_trace (u.format2.serialize (c, glyphs));
1068 default:return_trace (false);
1069 }
1070 }
1071
sanitizeOT::Coverage1072 bool sanitize (hb_sanitize_context_t *c) const
1073 {
1074 TRACE_SANITIZE (this);
1075 if (!u.format.sanitize (c)) return_trace (false);
1076 switch (u.format)
1077 {
1078 case 1: return_trace (u.format1.sanitize (c));
1079 case 2: return_trace (u.format2.sanitize (c));
1080 default:return_trace (true);
1081 }
1082 }
1083
intersectsOT::Coverage1084 bool intersects (const hb_set_t *glyphs) const
1085 {
1086 switch (u.format)
1087 {
1088 case 1: return u.format1.intersects (glyphs);
1089 case 2: return u.format2.intersects (glyphs);
1090 default:return false;
1091 }
1092 }
intersects_coverageOT::Coverage1093 bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
1094 {
1095 switch (u.format)
1096 {
1097 case 1: return u.format1.intersects_coverage (glyphs, index);
1098 case 2: return u.format2.intersects_coverage (glyphs, index);
1099 default:return false;
1100 }
1101 }
1102
1103 /* Might return false if array looks unsorted.
1104 * Used for faster rejection of corrupt data. */
1105 template <typename set_t>
add_coverageOT::Coverage1106 bool add_coverage (set_t *glyphs) const
1107 {
1108 switch (u.format)
1109 {
1110 case 1: return u.format1.add_coverage (glyphs);
1111 case 2: return u.format2.add_coverage (glyphs);
1112 default:return false;
1113 }
1114 }
1115
1116 struct iter_t : hb_iter_with_fallback_t<iter_t, hb_codepoint_t>
1117 {
1118 static constexpr bool is_sorted_iterator = true;
iter_tOT::Coverage::iter_t1119 iter_t (const Coverage &c_ = Null(Coverage))
1120 {
1121 memset (this, 0, sizeof (*this));
1122 format = c_.u.format;
1123 switch (format)
1124 {
1125 case 1: u.format1.init (c_.u.format1); return;
1126 case 2: u.format2.init (c_.u.format2); return;
1127 default: return;
1128 }
1129 }
__more__OT::Coverage::iter_t1130 bool __more__ () const
1131 {
1132 switch (format)
1133 {
1134 case 1: return u.format1.more ();
1135 case 2: return u.format2.more ();
1136 default:return false;
1137 }
1138 }
__next__OT::Coverage::iter_t1139 void __next__ ()
1140 {
1141 switch (format)
1142 {
1143 case 1: u.format1.next (); break;
1144 case 2: u.format2.next (); break;
1145 default: break;
1146 }
1147 }
1148 typedef hb_codepoint_t __item_t__;
__item__OT::Coverage::iter_t1149 __item_t__ __item__ () const { return get_glyph (); }
1150
get_glyphOT::Coverage::iter_t1151 hb_codepoint_t get_glyph () const
1152 {
1153 switch (format)
1154 {
1155 case 1: return u.format1.get_glyph ();
1156 case 2: return u.format2.get_glyph ();
1157 default:return 0;
1158 }
1159 }
operator !=OT::Coverage::iter_t1160 bool operator != (const iter_t& o) const
1161 {
1162 if (format != o.format) return true;
1163 switch (format)
1164 {
1165 case 1: return u.format1 != o.u.format1;
1166 case 2: return u.format2 != o.u.format2;
1167 default:return false;
1168 }
1169 }
1170
1171 private:
1172 unsigned int format;
1173 union {
1174 CoverageFormat2::iter_t format2; /* Put this one first since it's larger; helps shut up compiler. */
1175 CoverageFormat1::iter_t format1;
1176 } u;
1177 };
iterOT::Coverage1178 iter_t iter () const { return iter_t (*this); }
1179
1180 protected:
1181 union {
1182 HBUINT16 format; /* Format identifier */
1183 CoverageFormat1 format1;
1184 CoverageFormat2 format2;
1185 } u;
1186 public:
1187 DEFINE_SIZE_UNION (2, format);
1188 };
1189
1190
1191 /*
1192 * Class Definition Table
1193 */
1194
1195 static inline void ClassDef_serialize (hb_serialize_context_t *c,
1196 hb_array_t<const GlyphID> glyphs,
1197 hb_array_t<const HBUINT16> klasses);
1198
1199 struct ClassDefFormat1
1200 {
1201 friend struct ClassDef;
1202
1203 private:
get_classOT::ClassDefFormat11204 unsigned int get_class (hb_codepoint_t glyph_id) const
1205 {
1206 return classValue[(unsigned int) (glyph_id - startGlyph)];
1207 }
1208
serializeOT::ClassDefFormat11209 bool serialize (hb_serialize_context_t *c,
1210 hb_array_t<const GlyphID> glyphs,
1211 hb_array_t<const HBUINT16> klasses)
1212 {
1213 TRACE_SERIALIZE (this);
1214 if (unlikely (!c->extend_min (*this))) return_trace (false);
1215
1216 if (unlikely (!glyphs))
1217 {
1218 startGlyph = 0;
1219 classValue.len = 0;
1220 return_trace (true);
1221 }
1222
1223 hb_codepoint_t glyph_min = +glyphs | hb_reduce (hb_min, 0xFFFFu);
1224 hb_codepoint_t glyph_max = +glyphs | hb_reduce (hb_max, 0u);
1225
1226 startGlyph = glyph_min;
1227 c->check_assign (classValue.len, glyph_max - glyph_min + 1);
1228 if (unlikely (!c->extend (classValue))) return_trace (false);
1229
1230 for (unsigned int i = 0; i < glyphs.length; i++)
1231 classValue[glyphs[i] - glyph_min] = klasses[i];
1232
1233 return_trace (true);
1234 }
1235
subsetOT::ClassDefFormat11236 bool subset (hb_subset_context_t *c) const
1237 {
1238 TRACE_SUBSET (this);
1239 const hb_set_t &glyphset = *c->plan->glyphset ();
1240 const hb_map_t &glyph_map = *c->plan->glyph_map;
1241 hb_sorted_vector_t<GlyphID> glyphs;
1242 hb_vector_t<HBUINT16> klasses;
1243
1244 hb_codepoint_t start = startGlyph;
1245 hb_codepoint_t end = start + classValue.len;
1246 for (hb_codepoint_t g = start; g < end; g++)
1247 {
1248 if (!glyphset.has (g)) continue;
1249 unsigned int value = classValue[g - start];
1250 if (!value) continue;
1251 glyphs.push(glyph_map[g]);
1252 klasses.push(value);
1253 }
1254 c->serializer->propagate_error (glyphs, klasses);
1255 ClassDef_serialize (c->serializer, glyphs, klasses);
1256 return_trace ((bool) glyphs);
1257 }
1258
sanitizeOT::ClassDefFormat11259 bool sanitize (hb_sanitize_context_t *c) const
1260 {
1261 TRACE_SANITIZE (this);
1262 return_trace (c->check_struct (this) && classValue.sanitize (c));
1263 }
1264
1265 template <typename set_t>
add_coverageOT::ClassDefFormat11266 bool add_coverage (set_t *glyphs) const
1267 {
1268 unsigned int start = 0;
1269 unsigned int count = classValue.len;
1270 for (unsigned int i = 0; i < count; i++)
1271 {
1272 if (classValue[i])
1273 continue;
1274
1275 if (start != i)
1276 if (unlikely (!glyphs->add_range (startGlyph + start, startGlyph + i)))
1277 return false;
1278
1279 start = i + 1;
1280 }
1281 if (start != count)
1282 if (unlikely (!glyphs->add_range (startGlyph + start, startGlyph + count)))
1283 return false;
1284
1285 return true;
1286 }
1287
1288 template <typename set_t>
add_classOT::ClassDefFormat11289 bool add_class (set_t *glyphs, unsigned int klass) const
1290 {
1291 unsigned int count = classValue.len;
1292 for (unsigned int i = 0; i < count; i++)
1293 if (classValue[i] == klass) glyphs->add (startGlyph + i);
1294 return true;
1295 }
1296
intersectsOT::ClassDefFormat11297 bool intersects (const hb_set_t *glyphs) const
1298 {
1299 /* TODO Speed up, using hb_set_next()? */
1300 hb_codepoint_t start = startGlyph;
1301 hb_codepoint_t end = startGlyph + classValue.len;
1302 for (hb_codepoint_t iter = startGlyph - 1;
1303 hb_set_next (glyphs, &iter) && iter < end;)
1304 if (classValue[iter - start]) return true;
1305 return false;
1306 }
intersects_classOT::ClassDefFormat11307 bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const
1308 {
1309 unsigned int count = classValue.len;
1310 if (klass == 0)
1311 {
1312 /* Match if there's any glyph that is not listed! */
1313 hb_codepoint_t g = HB_SET_VALUE_INVALID;
1314 if (!hb_set_next (glyphs, &g)) return false;
1315 if (g < startGlyph) return true;
1316 g = startGlyph + count - 1;
1317 if (hb_set_next (glyphs, &g)) return true;
1318 /* Fall through. */
1319 }
1320 for (unsigned int i = 0; i < count; i++)
1321 if (classValue[i] == klass && glyphs->has (startGlyph + i))
1322 return true;
1323 return false;
1324 }
1325
1326 protected:
1327 HBUINT16 classFormat; /* Format identifier--format = 1 */
1328 GlyphID startGlyph; /* First GlyphID of the classValueArray */
1329 ArrayOf<HBUINT16>
1330 classValue; /* Array of Class Values--one per GlyphID */
1331 public:
1332 DEFINE_SIZE_ARRAY (6, classValue);
1333 };
1334
1335 struct ClassDefFormat2
1336 {
1337 friend struct ClassDef;
1338
1339 private:
get_classOT::ClassDefFormat21340 unsigned int get_class (hb_codepoint_t glyph_id) const
1341 {
1342 return rangeRecord.bsearch (glyph_id).value;
1343 }
1344
serializeOT::ClassDefFormat21345 bool serialize (hb_serialize_context_t *c,
1346 hb_array_t<const GlyphID> glyphs,
1347 hb_array_t<const HBUINT16> klasses)
1348 {
1349 TRACE_SERIALIZE (this);
1350 if (unlikely (!c->extend_min (*this))) return_trace (false);
1351
1352 if (unlikely (!glyphs))
1353 {
1354 rangeRecord.len = 0;
1355 return_trace (true);
1356 }
1357
1358 unsigned int count = glyphs.len ();
1359 unsigned int num_ranges = 1;
1360 for (unsigned int i = 1; i < count; i++)
1361 if (glyphs[i - 1] + 1 != glyphs[i] ||
1362 klasses[i - 1] != klasses[i])
1363 num_ranges++;
1364 rangeRecord.len = num_ranges;
1365 if (unlikely (!c->extend (rangeRecord))) return_trace (false);
1366
1367 unsigned int range = 0;
1368 rangeRecord[range].start = glyphs[0];
1369 rangeRecord[range].value = klasses[0];
1370 for (unsigned int i = 1; i < count; i++)
1371 {
1372 if (glyphs[i - 1] + 1 != glyphs[i] ||
1373 klasses[i - 1] != klasses[i])
1374 {
1375 rangeRecord[range].end = glyphs[i - 1];
1376 range++;
1377 rangeRecord[range].start = glyphs[i];
1378 rangeRecord[range].value = klasses[i];
1379 }
1380 }
1381 rangeRecord[range].end = glyphs[count - 1];
1382 return_trace (true);
1383 }
1384
subsetOT::ClassDefFormat21385 bool subset (hb_subset_context_t *c) const
1386 {
1387 TRACE_SUBSET (this);
1388 const hb_set_t &glyphset = *c->plan->glyphset ();
1389 const hb_map_t &glyph_map = *c->plan->glyph_map;
1390 hb_vector_t<GlyphID> glyphs;
1391 hb_vector_t<HBUINT16> klasses;
1392
1393 unsigned int count = rangeRecord.len;
1394 for (unsigned int i = 0; i < count; i++)
1395 {
1396 unsigned int value = rangeRecord[i].value;
1397 if (!value) continue;
1398 hb_codepoint_t start = rangeRecord[i].start;
1399 hb_codepoint_t end = rangeRecord[i].end + 1;
1400 for (hb_codepoint_t g = start; g < end; g++)
1401 {
1402 if (!glyphset.has (g)) continue;
1403 glyphs.push (glyph_map[g]);
1404 klasses.push (value);
1405 }
1406 }
1407 c->serializer->propagate_error (glyphs, klasses);
1408 ClassDef_serialize (c->serializer, glyphs, klasses);
1409 return_trace ((bool) glyphs);
1410 }
1411
sanitizeOT::ClassDefFormat21412 bool sanitize (hb_sanitize_context_t *c) const
1413 {
1414 TRACE_SANITIZE (this);
1415 return_trace (rangeRecord.sanitize (c));
1416 }
1417
1418 template <typename set_t>
add_coverageOT::ClassDefFormat21419 bool add_coverage (set_t *glyphs) const
1420 {
1421 unsigned int count = rangeRecord.len;
1422 for (unsigned int i = 0; i < count; i++)
1423 if (rangeRecord[i].value)
1424 if (unlikely (!rangeRecord[i].add_coverage (glyphs)))
1425 return false;
1426 return true;
1427 }
1428
1429 template <typename set_t>
add_classOT::ClassDefFormat21430 bool add_class (set_t *glyphs, unsigned int klass) const
1431 {
1432 unsigned int count = rangeRecord.len;
1433 for (unsigned int i = 0; i < count; i++)
1434 {
1435 if (rangeRecord[i].value == klass)
1436 if (unlikely (!rangeRecord[i].add_coverage (glyphs)))
1437 return false;
1438 }
1439 return true;
1440 }
1441
intersectsOT::ClassDefFormat21442 bool intersects (const hb_set_t *glyphs) const
1443 {
1444 /* TODO Speed up, using hb_set_next() and bsearch()? */
1445 unsigned int count = rangeRecord.len;
1446 for (unsigned int i = 0; i < count; i++)
1447 if (rangeRecord[i].intersects (glyphs))
1448 return true;
1449 return false;
1450 }
intersects_classOT::ClassDefFormat21451 bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const
1452 {
1453 unsigned int count = rangeRecord.len;
1454 if (klass == 0)
1455 {
1456 /* Match if there's any glyph that is not listed! */
1457 hb_codepoint_t g = HB_SET_VALUE_INVALID;
1458 for (unsigned int i = 0; i < count; i++)
1459 {
1460 if (!hb_set_next (glyphs, &g))
1461 break;
1462 if (g < rangeRecord[i].start)
1463 return true;
1464 g = rangeRecord[i].end;
1465 }
1466 if (g != HB_SET_VALUE_INVALID && hb_set_next (glyphs, &g))
1467 return true;
1468 /* Fall through. */
1469 }
1470 for (unsigned int i = 0; i < count; i++)
1471 if (rangeRecord[i].value == klass && rangeRecord[i].intersects (glyphs))
1472 return true;
1473 return false;
1474 }
1475
1476 protected:
1477 HBUINT16 classFormat; /* Format identifier--format = 2 */
1478 SortedArrayOf<RangeRecord>
1479 rangeRecord; /* Array of glyph ranges--ordered by
1480 * Start GlyphID */
1481 public:
1482 DEFINE_SIZE_ARRAY (4, rangeRecord);
1483 };
1484
1485 struct ClassDef
1486 {
1487 /* Has interface. */
1488 static constexpr unsigned SENTINEL = 0;
1489 typedef unsigned int value_t;
operator []OT::ClassDef1490 value_t operator [] (hb_codepoint_t k) const { return get (k); }
hasOT::ClassDef1491 bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
1492 /* Projection. */
operator ()OT::ClassDef1493 hb_codepoint_t operator () (hb_codepoint_t k) const { return get (k); }
1494
getOT::ClassDef1495 unsigned int get (hb_codepoint_t k) const { return get_class (k); }
get_classOT::ClassDef1496 unsigned int get_class (hb_codepoint_t glyph_id) const
1497 {
1498 switch (u.format) {
1499 case 1: return u.format1.get_class (glyph_id);
1500 case 2: return u.format2.get_class (glyph_id);
1501 default:return 0;
1502 }
1503 }
1504
serializeOT::ClassDef1505 bool serialize (hb_serialize_context_t *c,
1506 hb_array_t<const GlyphID> glyphs,
1507 hb_array_t<const HBUINT16> klasses)
1508 {
1509 TRACE_SERIALIZE (this);
1510 if (unlikely (!c->extend_min (*this))) return_trace (false);
1511
1512 unsigned int format = 2;
1513 if (likely (glyphs))
1514 {
1515 hb_codepoint_t glyph_min = +glyphs | hb_reduce (hb_min, 0xFFFFu);
1516 hb_codepoint_t glyph_max = +glyphs | hb_reduce (hb_max, 0u);
1517
1518 unsigned int count = glyphs.len ();
1519 unsigned int num_ranges = 1;
1520 for (unsigned int i = 1; i < count; i++)
1521 if (glyphs[i - 1] + 1 != glyphs[i] ||
1522 klasses[i - 1] != klasses[i])
1523 num_ranges++;
1524
1525 if (1 + (glyph_max - glyph_min + 1) < num_ranges * 3)
1526 format = 1;
1527 }
1528 u.format = format;
1529
1530 switch (u.format)
1531 {
1532 case 1: return_trace (u.format1.serialize (c, glyphs, klasses));
1533 case 2: return_trace (u.format2.serialize (c, glyphs, klasses));
1534 default:return_trace (false);
1535 }
1536 }
1537
subsetOT::ClassDef1538 bool subset (hb_subset_context_t *c) const
1539 {
1540 TRACE_SUBSET (this);
1541 switch (u.format) {
1542 case 1: return_trace (u.format1.subset (c));
1543 case 2: return_trace (u.format2.subset (c));
1544 default:return_trace (false);
1545 }
1546 }
1547
sanitizeOT::ClassDef1548 bool sanitize (hb_sanitize_context_t *c) const
1549 {
1550 TRACE_SANITIZE (this);
1551 if (!u.format.sanitize (c)) return_trace (false);
1552 switch (u.format) {
1553 case 1: return_trace (u.format1.sanitize (c));
1554 case 2: return_trace (u.format2.sanitize (c));
1555 default:return_trace (true);
1556 }
1557 }
1558
1559 /* Might return false if array looks unsorted.
1560 * Used for faster rejection of corrupt data. */
1561 template <typename set_t>
add_coverageOT::ClassDef1562 bool add_coverage (set_t *glyphs) const
1563 {
1564 switch (u.format) {
1565 case 1: return u.format1.add_coverage (glyphs);
1566 case 2: return u.format2.add_coverage (glyphs);
1567 default:return false;
1568 }
1569 }
1570
1571 /* Might return false if array looks unsorted.
1572 * Used for faster rejection of corrupt data. */
1573 template <typename set_t>
add_classOT::ClassDef1574 bool add_class (set_t *glyphs, unsigned int klass) const
1575 {
1576 switch (u.format) {
1577 case 1: return u.format1.add_class (glyphs, klass);
1578 case 2: return u.format2.add_class (glyphs, klass);
1579 default:return false;
1580 }
1581 }
1582
intersectsOT::ClassDef1583 bool intersects (const hb_set_t *glyphs) const
1584 {
1585 switch (u.format) {
1586 case 1: return u.format1.intersects (glyphs);
1587 case 2: return u.format2.intersects (glyphs);
1588 default:return false;
1589 }
1590 }
intersects_classOT::ClassDef1591 bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const
1592 {
1593 switch (u.format) {
1594 case 1: return u.format1.intersects_class (glyphs, klass);
1595 case 2: return u.format2.intersects_class (glyphs, klass);
1596 default:return false;
1597 }
1598 }
1599
1600 protected:
1601 union {
1602 HBUINT16 format; /* Format identifier */
1603 ClassDefFormat1 format1;
1604 ClassDefFormat2 format2;
1605 } u;
1606 public:
1607 DEFINE_SIZE_UNION (2, format);
1608 };
1609
ClassDef_serialize(hb_serialize_context_t * c,hb_array_t<const GlyphID> glyphs,hb_array_t<const HBUINT16> klasses)1610 static inline void ClassDef_serialize (hb_serialize_context_t *c,
1611 hb_array_t<const GlyphID> glyphs,
1612 hb_array_t<const HBUINT16> klasses)
1613 { c->start_embed<ClassDef> ()->serialize (c, glyphs, klasses); }
1614
1615
1616 /*
1617 * Item Variation Store
1618 */
1619
1620 struct VarRegionAxis
1621 {
evaluateOT::VarRegionAxis1622 float evaluate (int coord) const
1623 {
1624 int start = startCoord, peak = peakCoord, end = endCoord;
1625
1626 /* TODO Move these to sanitize(). */
1627 if (unlikely (start > peak || peak > end))
1628 return 1.;
1629 if (unlikely (start < 0 && end > 0 && peak != 0))
1630 return 1.;
1631
1632 if (peak == 0 || coord == peak)
1633 return 1.;
1634
1635 if (coord <= start || end <= coord)
1636 return 0.;
1637
1638 /* Interpolate */
1639 if (coord < peak)
1640 return float (coord - start) / (peak - start);
1641 else
1642 return float (end - coord) / (end - peak);
1643 }
1644
sanitizeOT::VarRegionAxis1645 bool sanitize (hb_sanitize_context_t *c) const
1646 {
1647 TRACE_SANITIZE (this);
1648 return_trace (c->check_struct (this));
1649 /* TODO Handle invalid start/peak/end configs, so we don't
1650 * have to do that at runtime. */
1651 }
1652
1653 public:
1654 F2DOT14 startCoord;
1655 F2DOT14 peakCoord;
1656 F2DOT14 endCoord;
1657 public:
1658 DEFINE_SIZE_STATIC (6);
1659 };
1660
1661 struct VarRegionList
1662 {
evaluateOT::VarRegionList1663 float evaluate (unsigned int region_index,
1664 const int *coords, unsigned int coord_len) const
1665 {
1666 if (unlikely (region_index >= regionCount))
1667 return 0.;
1668
1669 const VarRegionAxis *axes = axesZ.arrayZ + (region_index * axisCount);
1670
1671 float v = 1.;
1672 unsigned int count = axisCount;
1673 for (unsigned int i = 0; i < count; i++)
1674 {
1675 int coord = i < coord_len ? coords[i] : 0;
1676 float factor = axes[i].evaluate (coord);
1677 if (factor == 0.f)
1678 return 0.;
1679 v *= factor;
1680 }
1681 return v;
1682 }
1683
sanitizeOT::VarRegionList1684 bool sanitize (hb_sanitize_context_t *c) const
1685 {
1686 TRACE_SANITIZE (this);
1687 return_trace (c->check_struct (this) &&
1688 axesZ.sanitize (c, (unsigned int) axisCount * (unsigned int) regionCount));
1689 }
1690
get_region_countOT::VarRegionList1691 unsigned int get_region_count () const { return regionCount; }
1692
1693 protected:
1694 HBUINT16 axisCount;
1695 HBUINT16 regionCount;
1696 UnsizedArrayOf<VarRegionAxis>
1697 axesZ;
1698 public:
1699 DEFINE_SIZE_ARRAY (4, axesZ);
1700 };
1701
1702 struct VarData
1703 {
get_region_index_countOT::VarData1704 unsigned int get_region_index_count () const
1705 { return regionIndices.len; }
1706
get_row_sizeOT::VarData1707 unsigned int get_row_size () const
1708 { return shortCount + regionIndices.len; }
1709
get_sizeOT::VarData1710 unsigned int get_size () const
1711 { return itemCount * get_row_size (); }
1712
get_deltaOT::VarData1713 float get_delta (unsigned int inner,
1714 const int *coords, unsigned int coord_count,
1715 const VarRegionList ®ions) const
1716 {
1717 if (unlikely (inner >= itemCount))
1718 return 0.;
1719
1720 unsigned int count = regionIndices.len;
1721 unsigned int scount = shortCount;
1722
1723 const HBUINT8 *bytes = &StructAfter<HBUINT8> (regionIndices);
1724 const HBUINT8 *row = bytes + inner * (scount + count);
1725
1726 float delta = 0.;
1727 unsigned int i = 0;
1728
1729 const HBINT16 *scursor = reinterpret_cast<const HBINT16 *> (row);
1730 for (; i < scount; i++)
1731 {
1732 float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count);
1733 delta += scalar * *scursor++;
1734 }
1735 const HBINT8 *bcursor = reinterpret_cast<const HBINT8 *> (scursor);
1736 for (; i < count; i++)
1737 {
1738 float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count);
1739 delta += scalar * *bcursor++;
1740 }
1741
1742 return delta;
1743 }
1744
get_scalarsOT::VarData1745 void get_scalars (int *coords, unsigned int coord_count,
1746 const VarRegionList ®ions,
1747 float *scalars /*OUT */,
1748 unsigned int num_scalars) const
1749 {
1750 assert (num_scalars == regionIndices.len);
1751 for (unsigned int i = 0; i < num_scalars; i++)
1752 {
1753 scalars[i] = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count);
1754 }
1755 }
1756
sanitizeOT::VarData1757 bool sanitize (hb_sanitize_context_t *c) const
1758 {
1759 TRACE_SANITIZE (this);
1760 return_trace (c->check_struct (this) &&
1761 regionIndices.sanitize (c) &&
1762 shortCount <= regionIndices.len &&
1763 c->check_range (&StructAfter<HBUINT8> (regionIndices),
1764 itemCount,
1765 get_row_size ()));
1766 }
1767
1768 protected:
1769 HBUINT16 itemCount;
1770 HBUINT16 shortCount;
1771 ArrayOf<HBUINT16> regionIndices;
1772 /*UnsizedArrayOf<HBUINT8>bytesX;*/
1773 public:
1774 DEFINE_SIZE_ARRAY (6, regionIndices);
1775 };
1776
1777 struct VariationStore
1778 {
get_deltaOT::VariationStore1779 float get_delta (unsigned int outer, unsigned int inner,
1780 const int *coords, unsigned int coord_count) const
1781 {
1782 if (unlikely (outer >= dataSets.len))
1783 return 0.;
1784
1785 return (this+dataSets[outer]).get_delta (inner,
1786 coords, coord_count,
1787 this+regions);
1788 }
1789
get_deltaOT::VariationStore1790 float get_delta (unsigned int index,
1791 const int *coords, unsigned int coord_count) const
1792 {
1793 unsigned int outer = index >> 16;
1794 unsigned int inner = index & 0xFFFF;
1795 return get_delta (outer, inner, coords, coord_count);
1796 }
1797
sanitizeOT::VariationStore1798 bool sanitize (hb_sanitize_context_t *c) const
1799 {
1800 TRACE_SANITIZE (this);
1801 return_trace (c->check_struct (this) &&
1802 format == 1 &&
1803 regions.sanitize (c, this) &&
1804 dataSets.sanitize (c, this));
1805 }
1806
get_region_index_countOT::VariationStore1807 unsigned int get_region_index_count (unsigned int ivs) const
1808 { return (this+dataSets[ivs]).get_region_index_count (); }
1809
get_scalarsOT::VariationStore1810 void get_scalars (unsigned int ivs,
1811 int *coords, unsigned int coord_count,
1812 float *scalars /*OUT*/,
1813 unsigned int num_scalars) const
1814 {
1815 (this+dataSets[ivs]).get_scalars (coords, coord_count, this+regions,
1816 &scalars[0], num_scalars);
1817 }
1818
1819 protected:
1820 HBUINT16 format;
1821 LOffsetTo<VarRegionList> regions;
1822 LOffsetArrayOf<VarData> dataSets;
1823 public:
1824 DEFINE_SIZE_ARRAY (8, dataSets);
1825 };
1826
1827 /*
1828 * Feature Variations
1829 */
1830
1831 struct ConditionFormat1
1832 {
1833 friend struct Condition;
1834
1835 private:
evaluateOT::ConditionFormat11836 bool evaluate (const int *coords, unsigned int coord_len) const
1837 {
1838 int coord = axisIndex < coord_len ? coords[axisIndex] : 0;
1839 return filterRangeMinValue <= coord && coord <= filterRangeMaxValue;
1840 }
1841
sanitizeOT::ConditionFormat11842 bool sanitize (hb_sanitize_context_t *c) const
1843 {
1844 TRACE_SANITIZE (this);
1845 return_trace (c->check_struct (this));
1846 }
1847
1848 protected:
1849 HBUINT16 format; /* Format identifier--format = 1 */
1850 HBUINT16 axisIndex;
1851 F2DOT14 filterRangeMinValue;
1852 F2DOT14 filterRangeMaxValue;
1853 public:
1854 DEFINE_SIZE_STATIC (8);
1855 };
1856
1857 struct Condition
1858 {
evaluateOT::Condition1859 bool evaluate (const int *coords, unsigned int coord_len) const
1860 {
1861 switch (u.format) {
1862 case 1: return u.format1.evaluate (coords, coord_len);
1863 default:return false;
1864 }
1865 }
1866
sanitizeOT::Condition1867 bool sanitize (hb_sanitize_context_t *c) const
1868 {
1869 TRACE_SANITIZE (this);
1870 if (!u.format.sanitize (c)) return_trace (false);
1871 switch (u.format) {
1872 case 1: return_trace (u.format1.sanitize (c));
1873 default:return_trace (true);
1874 }
1875 }
1876
1877 protected:
1878 union {
1879 HBUINT16 format; /* Format identifier */
1880 ConditionFormat1 format1;
1881 } u;
1882 public:
1883 DEFINE_SIZE_UNION (2, format);
1884 };
1885
1886 struct ConditionSet
1887 {
evaluateOT::ConditionSet1888 bool evaluate (const int *coords, unsigned int coord_len) const
1889 {
1890 unsigned int count = conditions.len;
1891 for (unsigned int i = 0; i < count; i++)
1892 if (!(this+conditions.arrayZ[i]).evaluate (coords, coord_len))
1893 return false;
1894 return true;
1895 }
1896
sanitizeOT::ConditionSet1897 bool sanitize (hb_sanitize_context_t *c) const
1898 {
1899 TRACE_SANITIZE (this);
1900 return_trace (conditions.sanitize (c, this));
1901 }
1902
1903 protected:
1904 LOffsetArrayOf<Condition> conditions;
1905 public:
1906 DEFINE_SIZE_ARRAY (2, conditions);
1907 };
1908
1909 struct FeatureTableSubstitutionRecord
1910 {
1911 friend struct FeatureTableSubstitution;
1912
sanitizeOT::FeatureTableSubstitutionRecord1913 bool sanitize (hb_sanitize_context_t *c, const void *base) const
1914 {
1915 TRACE_SANITIZE (this);
1916 return_trace (c->check_struct (this) && feature.sanitize (c, base));
1917 }
1918
1919 protected:
1920 HBUINT16 featureIndex;
1921 LOffsetTo<Feature> feature;
1922 public:
1923 DEFINE_SIZE_STATIC (6);
1924 };
1925
1926 struct FeatureTableSubstitution
1927 {
find_substituteOT::FeatureTableSubstitution1928 const Feature *find_substitute (unsigned int feature_index) const
1929 {
1930 unsigned int count = substitutions.len;
1931 for (unsigned int i = 0; i < count; i++)
1932 {
1933 const FeatureTableSubstitutionRecord &record = substitutions.arrayZ[i];
1934 if (record.featureIndex == feature_index)
1935 return &(this+record.feature);
1936 }
1937 return nullptr;
1938 }
1939
sanitizeOT::FeatureTableSubstitution1940 bool sanitize (hb_sanitize_context_t *c) const
1941 {
1942 TRACE_SANITIZE (this);
1943 return_trace (version.sanitize (c) &&
1944 likely (version.major == 1) &&
1945 substitutions.sanitize (c, this));
1946 }
1947
1948 protected:
1949 FixedVersion<> version; /* Version--0x00010000u */
1950 ArrayOf<FeatureTableSubstitutionRecord>
1951 substitutions;
1952 public:
1953 DEFINE_SIZE_ARRAY (6, substitutions);
1954 };
1955
1956 struct FeatureVariationRecord
1957 {
1958 friend struct FeatureVariations;
1959
sanitizeOT::FeatureVariationRecord1960 bool sanitize (hb_sanitize_context_t *c, const void *base) const
1961 {
1962 TRACE_SANITIZE (this);
1963 return_trace (conditions.sanitize (c, base) &&
1964 substitutions.sanitize (c, base));
1965 }
1966
1967 protected:
1968 LOffsetTo<ConditionSet>
1969 conditions;
1970 LOffsetTo<FeatureTableSubstitution>
1971 substitutions;
1972 public:
1973 DEFINE_SIZE_STATIC (8);
1974 };
1975
1976 struct FeatureVariations
1977 {
1978 static constexpr unsigned NOT_FOUND_INDEX = 0xFFFFFFFFu;
1979
find_indexOT::FeatureVariations1980 bool find_index (const int *coords, unsigned int coord_len,
1981 unsigned int *index) const
1982 {
1983 unsigned int count = varRecords.len;
1984 for (unsigned int i = 0; i < count; i++)
1985 {
1986 const FeatureVariationRecord &record = varRecords.arrayZ[i];
1987 if ((this+record.conditions).evaluate (coords, coord_len))
1988 {
1989 *index = i;
1990 return true;
1991 }
1992 }
1993 *index = NOT_FOUND_INDEX;
1994 return false;
1995 }
1996
find_substituteOT::FeatureVariations1997 const Feature *find_substitute (unsigned int variations_index,
1998 unsigned int feature_index) const
1999 {
2000 const FeatureVariationRecord &record = varRecords[variations_index];
2001 return (this+record.substitutions).find_substitute (feature_index);
2002 }
2003
copyOT::FeatureVariations2004 FeatureVariations* copy (hb_serialize_context_t *c) const
2005 {
2006 TRACE_SERIALIZE (this);
2007 return_trace (c->embed (*this));
2008 }
2009
sanitizeOT::FeatureVariations2010 bool sanitize (hb_sanitize_context_t *c) const
2011 {
2012 TRACE_SANITIZE (this);
2013 return_trace (version.sanitize (c) &&
2014 likely (version.major == 1) &&
2015 varRecords.sanitize (c, this));
2016 }
2017
2018 protected:
2019 FixedVersion<> version; /* Version--0x00010000u */
2020 LArrayOf<FeatureVariationRecord>
2021 varRecords;
2022 public:
2023 DEFINE_SIZE_ARRAY_SIZED (8, varRecords);
2024 };
2025
2026
2027 /*
2028 * Device Tables
2029 */
2030
2031 struct HintingDevice
2032 {
2033 friend struct Device;
2034
2035 private:
2036
get_x_deltaOT::HintingDevice2037 hb_position_t get_x_delta (hb_font_t *font) const
2038 { return get_delta (font->x_ppem, font->x_scale); }
2039
get_y_deltaOT::HintingDevice2040 hb_position_t get_y_delta (hb_font_t *font) const
2041 { return get_delta (font->y_ppem, font->y_scale); }
2042
get_sizeOT::HintingDevice2043 unsigned int get_size () const
2044 {
2045 unsigned int f = deltaFormat;
2046 if (unlikely (f < 1 || f > 3 || startSize > endSize)) return 3 * HBUINT16::static_size;
2047 return HBUINT16::static_size * (4 + ((endSize - startSize) >> (4 - f)));
2048 }
2049
sanitizeOT::HintingDevice2050 bool sanitize (hb_sanitize_context_t *c) const
2051 {
2052 TRACE_SANITIZE (this);
2053 return_trace (c->check_struct (this) && c->check_range (this, this->get_size ()));
2054 }
2055
2056 private:
2057
get_deltaOT::HintingDevice2058 int get_delta (unsigned int ppem, int scale) const
2059 {
2060 if (!ppem) return 0;
2061
2062 int pixels = get_delta_pixels (ppem);
2063
2064 if (!pixels) return 0;
2065
2066 return (int) (pixels * (int64_t) scale / ppem);
2067 }
get_delta_pixelsOT::HintingDevice2068 int get_delta_pixels (unsigned int ppem_size) const
2069 {
2070 unsigned int f = deltaFormat;
2071 if (unlikely (f < 1 || f > 3))
2072 return 0;
2073
2074 if (ppem_size < startSize || ppem_size > endSize)
2075 return 0;
2076
2077 unsigned int s = ppem_size - startSize;
2078
2079 unsigned int byte = deltaValueZ[s >> (4 - f)];
2080 unsigned int bits = (byte >> (16 - (((s & ((1 << (4 - f)) - 1)) + 1) << f)));
2081 unsigned int mask = (0xFFFFu >> (16 - (1 << f)));
2082
2083 int delta = bits & mask;
2084
2085 if ((unsigned int) delta >= ((mask + 1) >> 1))
2086 delta -= mask + 1;
2087
2088 return delta;
2089 }
2090
2091 protected:
2092 HBUINT16 startSize; /* Smallest size to correct--in ppem */
2093 HBUINT16 endSize; /* Largest size to correct--in ppem */
2094 HBUINT16 deltaFormat; /* Format of DeltaValue array data: 1, 2, or 3
2095 * 1 Signed 2-bit value, 8 values per uint16
2096 * 2 Signed 4-bit value, 4 values per uint16
2097 * 3 Signed 8-bit value, 2 values per uint16
2098 */
2099 UnsizedArrayOf<HBUINT16>
2100 deltaValueZ; /* Array of compressed data */
2101 public:
2102 DEFINE_SIZE_ARRAY (6, deltaValueZ);
2103 };
2104
2105 struct VariationDevice
2106 {
2107 friend struct Device;
2108
2109 private:
2110
get_x_deltaOT::VariationDevice2111 hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store) const
2112 { return font->em_scalef_x (get_delta (font, store)); }
2113
get_y_deltaOT::VariationDevice2114 hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store) const
2115 { return font->em_scalef_y (get_delta (font, store)); }
2116
sanitizeOT::VariationDevice2117 bool sanitize (hb_sanitize_context_t *c) const
2118 {
2119 TRACE_SANITIZE (this);
2120 return_trace (c->check_struct (this));
2121 }
2122
2123 private:
2124
get_deltaOT::VariationDevice2125 float get_delta (hb_font_t *font, const VariationStore &store) const
2126 {
2127 return store.get_delta (outerIndex, innerIndex, font->coords, font->num_coords);
2128 }
2129
2130 protected:
2131 HBUINT16 outerIndex;
2132 HBUINT16 innerIndex;
2133 HBUINT16 deltaFormat; /* Format identifier for this table: 0x0x8000 */
2134 public:
2135 DEFINE_SIZE_STATIC (6);
2136 };
2137
2138 struct DeviceHeader
2139 {
2140 protected:
2141 HBUINT16 reserved1;
2142 HBUINT16 reserved2;
2143 public:
2144 HBUINT16 format; /* Format identifier */
2145 public:
2146 DEFINE_SIZE_STATIC (6);
2147 };
2148
2149 struct Device
2150 {
get_x_deltaOT::Device2151 hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store=Null (VariationStore)) const
2152 {
2153 switch (u.b.format)
2154 {
2155 case 1: case 2: case 3:
2156 return u.hinting.get_x_delta (font);
2157 case 0x8000:
2158 return u.variation.get_x_delta (font, store);
2159 default:
2160 return 0;
2161 }
2162 }
get_y_deltaOT::Device2163 hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store=Null (VariationStore)) const
2164 {
2165 switch (u.b.format)
2166 {
2167 case 1: case 2: case 3:
2168 return u.hinting.get_y_delta (font);
2169 case 0x8000:
2170 return u.variation.get_y_delta (font, store);
2171 default:
2172 return 0;
2173 }
2174 }
2175
sanitizeOT::Device2176 bool sanitize (hb_sanitize_context_t *c) const
2177 {
2178 TRACE_SANITIZE (this);
2179 if (!u.b.format.sanitize (c)) return_trace (false);
2180 switch (u.b.format) {
2181 case 1: case 2: case 3:
2182 return_trace (u.hinting.sanitize (c));
2183 case 0x8000:
2184 return_trace (u.variation.sanitize (c));
2185 default:
2186 return_trace (true);
2187 }
2188 }
2189
2190 protected:
2191 union {
2192 DeviceHeader b;
2193 HintingDevice hinting;
2194 VariationDevice variation;
2195 } u;
2196 public:
2197 DEFINE_SIZE_UNION (6, b);
2198 };
2199
2200
2201 } /* namespace OT */
2202
2203
2204 #endif /* HB_OT_LAYOUT_COMMON_HH */
2205