2 * Copyright © 2007,2008,2009 Red Hat, Inc.
3 * Copyright © 2010,2012 Google, Inc.
5 * This is part of HarfBuzz, a text shaping library.
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.
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
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.
25 * Red Hat Author(s): Behdad Esfahbod
26 * Google Author(s): Behdad Esfahbod
29 #ifndef HB_OT_LAYOUT_COMMON_PRIVATE_HH
30 #define HB_OT_LAYOUT_COMMON_PRIVATE_HH
32 #include "hb-private.hh"
33 #include "hb-debug.hh"
34 #include "hb-ot-layout-private.hh"
35 #include "hb-open-type-private.hh"
36 #include "hb-set-private.hh"
39 #ifndef HB_MAX_NESTING_LEVEL
40 #define HB_MAX_NESTING_LEVEL 6
42 #ifndef HB_MAX_CONTEXT_LENGTH
43 #define HB_MAX_CONTEXT_LENGTH 64
50 #define NOT_COVERED ((unsigned int) -1)
56 * OpenType Layout Common Table Formats
62 * Script, ScriptList, LangSys, Feature, FeatureList, Lookup, LookupList
65 template <typename Type>
68 inline int cmp (hb_tag_t a) const {
72 struct sanitize_closure_t {
74 const void *list_base;
76 inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
78 TRACE_SANITIZE (this);
79 const sanitize_closure_t closure = {tag, base};
80 return_trace (c->check_struct (this) && offset.sanitize (c, base, &closure));
83 Tag tag; /* 4-byte Tag identifier */
85 offset; /* Offset from beginning of object holding
88 DEFINE_SIZE_STATIC (6);
91 template <typename Type>
92 struct RecordArrayOf : SortedArrayOf<Record<Type> > {
93 inline const Tag& get_tag (unsigned int i) const
95 /* We cheat slightly and don't define separate Null objects
96 * for Record types. Instead, we return the correct Null(Tag)
98 if (unlikely (i >= this->len)) return Null(Tag);
99 return (*this)[i].tag;
101 inline unsigned int get_tags (unsigned int start_offset,
102 unsigned int *record_count /* IN/OUT */,
103 hb_tag_t *record_tags /* OUT */) const
106 const Record<Type> *arr = this->sub_array (start_offset, record_count);
107 unsigned int count = *record_count;
108 for (unsigned int i = 0; i < count; i++)
109 record_tags[i] = arr[i].tag;
113 inline bool find_index (hb_tag_t tag, unsigned int *index) const
115 /* If we want to allow non-sorted data, we can lsearch(). */
116 int i = this->/*lsearch*/bsearch (tag);
118 if (index) *index = i;
121 if (index) *index = Index::NOT_FOUND_INDEX;
127 template <typename Type>
128 struct RecordListOf : RecordArrayOf<Type>
130 inline const Type& operator [] (unsigned int i) const
131 { return this+RecordArrayOf<Type>::operator [](i).offset; }
133 inline bool sanitize (hb_sanitize_context_t *c) const
135 TRACE_SANITIZE (this);
136 return_trace (RecordArrayOf<Type>::sanitize (c, this));
143 inline int cmp (hb_codepoint_t g) const {
144 return g < start ? -1 : g <= end ? 0 : +1 ;
147 inline bool sanitize (hb_sanitize_context_t *c) const
149 TRACE_SANITIZE (this);
150 return_trace (c->check_struct (this));
153 inline bool intersects (const hb_set_t *glyphs) const {
154 return glyphs->intersects (start, end);
157 template <typename set_t>
158 inline bool add_coverage (set_t *glyphs) const {
159 return glyphs->add_range (start, end);
162 GlyphID start; /* First GlyphID in the range */
163 GlyphID end; /* Last GlyphID in the range */
164 HBUINT16 value; /* Value */
166 DEFINE_SIZE_STATIC (6);
168 DEFINE_NULL_DATA (OT, RangeRecord, "\000\001");
171 struct IndexArray : ArrayOf<Index>
173 inline unsigned int get_indexes (unsigned int start_offset,
174 unsigned int *_count /* IN/OUT */,
175 unsigned int *_indexes /* OUT */) const
178 const HBUINT16 *arr = this->sub_array (start_offset, _count);
179 unsigned int count = *_count;
180 for (unsigned int i = 0; i < count; i++)
181 _indexes[i] = arr[i];
195 inline unsigned int get_feature_count (void) const
196 { return featureIndex.len; }
197 inline hb_tag_t get_feature_index (unsigned int i) const
198 { return featureIndex[i]; }
199 inline unsigned int get_feature_indexes (unsigned int start_offset,
200 unsigned int *feature_count /* IN/OUT */,
201 unsigned int *feature_indexes /* OUT */) const
202 { return featureIndex.get_indexes (start_offset, feature_count, feature_indexes); }
204 inline bool has_required_feature (void) const { return reqFeatureIndex != 0xFFFFu; }
205 inline unsigned int get_required_feature_index (void) const
207 if (reqFeatureIndex == 0xFFFFu)
208 return Index::NOT_FOUND_INDEX;
209 return reqFeatureIndex;;
212 inline bool sanitize (hb_sanitize_context_t *c,
213 const Record<LangSys>::sanitize_closure_t * = nullptr) const
215 TRACE_SANITIZE (this);
216 return_trace (c->check_struct (this) && featureIndex.sanitize (c));
219 Offset16 lookupOrderZ; /* = Null (reserved for an offset to a
220 * reordering table) */
221 HBUINT16 reqFeatureIndex;/* Index of a feature required for this
222 * language system--if no required features
224 IndexArray featureIndex; /* Array of indices into the FeatureList */
226 DEFINE_SIZE_ARRAY (6, featureIndex);
228 DEFINE_NULL_DATA (OT, LangSys, "\0\0\xFF\xFF");
233 inline unsigned int get_lang_sys_count (void) const
234 { return langSys.len; }
235 inline const Tag& get_lang_sys_tag (unsigned int i) const
236 { return langSys.get_tag (i); }
237 inline unsigned int get_lang_sys_tags (unsigned int start_offset,
238 unsigned int *lang_sys_count /* IN/OUT */,
239 hb_tag_t *lang_sys_tags /* OUT */) const
240 { return langSys.get_tags (start_offset, lang_sys_count, lang_sys_tags); }
241 inline const LangSys& get_lang_sys (unsigned int i) const
243 if (i == Index::NOT_FOUND_INDEX) return get_default_lang_sys ();
244 return this+langSys[i].offset;
246 inline bool find_lang_sys_index (hb_tag_t tag, unsigned int *index) const
247 { return langSys.find_index (tag, index); }
249 inline bool has_default_lang_sys (void) const { return defaultLangSys != 0; }
250 inline const LangSys& get_default_lang_sys (void) const { return this+defaultLangSys; }
252 inline bool sanitize (hb_sanitize_context_t *c,
253 const Record<Script>::sanitize_closure_t * = nullptr) const
255 TRACE_SANITIZE (this);
256 return_trace (defaultLangSys.sanitize (c, this) && langSys.sanitize (c, this));
261 defaultLangSys; /* Offset to DefaultLangSys table--from
262 * beginning of Script table--may be Null */
263 RecordArrayOf<LangSys>
264 langSys; /* Array of LangSysRecords--listed
265 * alphabetically by LangSysTag */
267 DEFINE_SIZE_ARRAY (4, langSys);
270 typedef RecordListOf<Script> ScriptList;
273 /* https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#size */
274 struct FeatureParamsSize
276 inline bool sanitize (hb_sanitize_context_t *c) const
278 TRACE_SANITIZE (this);
279 if (unlikely (!c->check_struct (this))) return_trace (false);
281 /* This subtable has some "history", if you will. Some earlier versions of
282 * Adobe tools calculated the offset of the FeatureParams sutable from the
283 * beginning of the FeatureList table! Now, that is dealt with in the
284 * Feature implementation. But we still need to be able to tell junk from
285 * real data. Note: We don't check that the nameID actually exists.
287 * Read Roberts wrote on 9/15/06 on opentype-list@indx.co.uk :
289 * Yes, it is correct that a new version of the AFDKO (version 2.0) will be
290 * coming out soon, and that the makeotf program will build a font with a
291 * 'size' feature that is correct by the specification.
293 * The specification for this feature tag is in the "OpenType Layout Tag
294 * Registry". You can see a copy of this at:
295 * https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#tag-size
297 * Here is one set of rules to determine if the 'size' feature is built
298 * correctly, or as by the older versions of MakeOTF. You may be able to do
301 * Assume that the offset to the size feature is according to specification,
302 * and make the following value checks. If it fails, assume the size
303 * feature is calculated as versions of MakeOTF before the AFDKO 2.0 built it.
304 * If this fails, reject the 'size' feature. The older makeOTF's calculated the
305 * offset from the beginning of the FeatureList table, rather than from the
306 * beginning of the 'size' Feature table.
308 * If "design size" == 0:
311 * Else if ("subfamily identifier" == 0 and
312 * "range start" == 0 and
313 * "range end" == 0 and
314 * "range start" == 0 and
315 * "menu name ID" == 0)
316 * passes check: this is the format used when there is a design size
317 * specified, but there is no recommended size range.
319 * Else if ("design size" < "range start" or
320 * "design size" > "range end" or
321 * "range end" <= "range start" or
322 * "menu name ID" < 256 or
323 * "menu name ID" > 32767 or
324 * menu name ID is not a name ID which is actually in the name table)
331 return_trace (false);
332 else if (subfamilyID == 0 &&
333 subfamilyNameID == 0 &&
337 else if (designSize < rangeStart ||
338 designSize > rangeEnd ||
339 subfamilyNameID < 256 ||
340 subfamilyNameID > 32767)
341 return_trace (false);
346 HBUINT16 designSize; /* Represents the design size in 720/inch
347 * units (decipoints). The design size entry
348 * must be non-zero. When there is a design
349 * size but no recommended size range, the
350 * rest of the array will consist of zeros. */
351 HBUINT16 subfamilyID; /* Has no independent meaning, but serves
352 * as an identifier that associates fonts
353 * in a subfamily. All fonts which share a
354 * Preferred or Font Family name and which
355 * differ only by size range shall have the
356 * same subfamily value, and no fonts which
357 * differ in weight or style shall have the
358 * same subfamily value. If this value is
359 * zero, the remaining fields in the array
360 * will be ignored. */
361 HBUINT16 subfamilyNameID;/* If the preceding value is non-zero, this
362 * value must be set in the range 256 - 32767
363 * (inclusive). It records the value of a
364 * field in the name table, which must
365 * contain English-language strings encoded
366 * in Windows Unicode and Macintosh Roman,
367 * and may contain additional strings
368 * localized to other scripts and languages.
369 * Each of these strings is the name an
370 * application should use, in combination
371 * with the family name, to represent the
372 * subfamily in a menu. Applications will
373 * choose the appropriate version based on
374 * their selection criteria. */
375 HBUINT16 rangeStart; /* Large end of the recommended usage range
376 * (inclusive), stored in 720/inch units
378 HBUINT16 rangeEnd; /* Small end of the recommended usage range
379 (exclusive), stored in 720/inch units
382 DEFINE_SIZE_STATIC (10);
385 /* https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#ssxx */
386 struct FeatureParamsStylisticSet
388 inline bool sanitize (hb_sanitize_context_t *c) const
390 TRACE_SANITIZE (this);
391 /* Right now minorVersion is at zero. Which means, any table supports
392 * the uiNameID field. */
393 return_trace (c->check_struct (this));
396 HBUINT16 version; /* (set to 0): This corresponds to a “minor”
397 * version number. Additional data may be
398 * added to the end of this Feature Parameters
399 * table in the future. */
401 NameID uiNameID; /* The 'name' table name ID that specifies a
402 * string (or strings, for multiple languages)
403 * for a user-interface label for this
404 * feature. The values of uiLabelNameId and
405 * sampleTextNameId are expected to be in the
406 * font-specific name ID range (256-32767),
407 * though that is not a requirement in this
408 * Feature Parameters specification. The
409 * user-interface label for the feature can
410 * be provided in multiple languages. An
411 * English string should be included as a
412 * fallback. The string should be kept to a
413 * minimal length to fit comfortably with
414 * different application interfaces. */
416 DEFINE_SIZE_STATIC (4);
419 /* https://docs.microsoft.com/en-us/typography/opentype/spec/features_ae#cv01-cv99 */
420 struct FeatureParamsCharacterVariants
422 inline bool sanitize (hb_sanitize_context_t *c) const
424 TRACE_SANITIZE (this);
425 return_trace (c->check_struct (this) &&
426 characters.sanitize (c));
429 HBUINT16 format; /* Format number is set to 0. */
430 NameID featUILableNameID; /* The ‘name’ table name ID that
431 * specifies a string (or strings,
432 * for multiple languages) for a
433 * user-interface label for this
434 * feature. (May be nullptr.) */
435 NameID featUITooltipTextNameID;/* The ‘name’ table name ID that
436 * specifies a string (or strings,
437 * for multiple languages) that an
438 * application can use for tooltip
439 * text for this feature. (May be
441 NameID sampleTextNameID; /* The ‘name’ table name ID that
442 * specifies sample text that
443 * illustrates the effect of this
444 * feature. (May be nullptr.) */
445 HBUINT16 numNamedParameters; /* Number of named parameters. (May
447 NameID firstParamUILabelNameID;/* The first ‘name’ table name ID
448 * used to specify strings for
449 * user-interface labels for the
450 * feature parameters. (Must be zero
451 * if numParameters is zero.) */
453 characters; /* Array of the Unicode Scalar Value
454 * of the characters for which this
455 * feature provides glyph variants.
458 DEFINE_SIZE_ARRAY (14, characters);
463 inline bool sanitize (hb_sanitize_context_t *c, hb_tag_t tag) const
465 TRACE_SANITIZE (this);
466 if (tag == HB_TAG ('s','i','z','e'))
467 return_trace (u.size.sanitize (c));
468 if ((tag & 0xFFFF0000u) == HB_TAG ('s','s','\0','\0')) /* ssXX */
469 return_trace (u.stylisticSet.sanitize (c));
470 if ((tag & 0xFFFF0000u) == HB_TAG ('c','v','\0','\0')) /* cvXX */
471 return_trace (u.characterVariants.sanitize (c));
475 inline const FeatureParamsSize& get_size_params (hb_tag_t tag) const
477 if (tag == HB_TAG ('s','i','z','e'))
479 return Null(FeatureParamsSize);
484 FeatureParamsSize size;
485 FeatureParamsStylisticSet stylisticSet;
486 FeatureParamsCharacterVariants characterVariants;
488 DEFINE_SIZE_STATIC (17);
493 inline unsigned int get_lookup_count (void) const
494 { return lookupIndex.len; }
495 inline hb_tag_t get_lookup_index (unsigned int i) const
496 { return lookupIndex[i]; }
497 inline unsigned int get_lookup_indexes (unsigned int start_index,
498 unsigned int *lookup_count /* IN/OUT */,
499 unsigned int *lookup_tags /* OUT */) const
500 { return lookupIndex.get_indexes (start_index, lookup_count, lookup_tags); }
502 inline const FeatureParams &get_feature_params (void) const
503 { return this+featureParams; }
505 inline bool sanitize (hb_sanitize_context_t *c,
506 const Record<Feature>::sanitize_closure_t *closure = nullptr) const
508 TRACE_SANITIZE (this);
509 if (unlikely (!(c->check_struct (this) && lookupIndex.sanitize (c))))
510 return_trace (false);
512 /* Some earlier versions of Adobe tools calculated the offset of the
513 * FeatureParams subtable from the beginning of the FeatureList table!
515 * If sanitizing "failed" for the FeatureParams subtable, try it with the
516 * alternative location. We would know sanitize "failed" if old value
517 * of the offset was non-zero, but it's zeroed now.
519 * Only do this for the 'size' feature, since at the time of the faulty
520 * Adobe tools, only the 'size' feature had FeatureParams defined.
523 OffsetTo<FeatureParams> orig_offset = featureParams;
524 if (unlikely (!featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE)))
525 return_trace (false);
527 if (likely (orig_offset.is_null ()))
530 if (featureParams == 0 && closure &&
531 closure->tag == HB_TAG ('s','i','z','e') &&
532 closure->list_base && closure->list_base < this)
534 unsigned int new_offset_int = (unsigned int) orig_offset -
535 (((char *) this) - ((char *) closure->list_base));
537 OffsetTo<FeatureParams> new_offset;
538 /* Check that it did not overflow. */
539 new_offset.set (new_offset_int);
540 if (new_offset == new_offset_int &&
541 c->try_set (&featureParams, new_offset) &&
542 !featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE))
543 return_trace (false);
545 if (c->edit_count > 1)
546 c->edit_count--; /* This was a "legitimate" edit; don't contribute to error count. */
552 OffsetTo<FeatureParams>
553 featureParams; /* Offset to Feature Parameters table (if one
554 * has been defined for the feature), relative
555 * to the beginning of the Feature Table; = Null
557 IndexArray lookupIndex; /* Array of LookupList indices */
559 DEFINE_SIZE_ARRAY (4, lookupIndex);
562 typedef RecordListOf<Feature> FeatureList;
565 struct LookupFlag : HBUINT16
568 RightToLeft = 0x0001u,
569 IgnoreBaseGlyphs = 0x0002u,
570 IgnoreLigatures = 0x0004u,
571 IgnoreMarks = 0x0008u,
572 IgnoreFlags = 0x000Eu,
573 UseMarkFilteringSet = 0x0010u,
575 MarkAttachmentType = 0xFF00u
578 DEFINE_SIZE_STATIC (2);
582 /* This has to be outside the namespace. */
583 HB_MARK_AS_FLAG_T (OT::LookupFlag::Flags);
588 inline unsigned int get_subtable_count (void) const { return subTable.len; }
590 template <typename SubTableType>
591 inline const SubTableType& get_subtable (unsigned int i) const
592 { return this+CastR<OffsetArrayOf<SubTableType> > (subTable)[i]; }
594 template <typename SubTableType>
595 inline const OffsetArrayOf<SubTableType>& get_subtables (void) const
596 { return CastR<OffsetArrayOf<SubTableType> > (subTable); }
597 template <typename SubTableType>
598 inline OffsetArrayOf<SubTableType>& get_subtables (void)
599 { return CastR<OffsetArrayOf<SubTableType> > (subTable); }
601 inline unsigned int get_type (void) const { return lookupType; }
603 /* lookup_props is a 32-bit integer where the lower 16-bit is LookupFlag and
604 * higher 16-bit is mark-filtering-set if the lookup uses one.
605 * Not to be confused with glyph_props which is very similar. */
606 inline uint32_t get_props (void) const
608 unsigned int flag = lookupFlag;
609 if (unlikely (flag & LookupFlag::UseMarkFilteringSet))
611 const HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
612 flag += (markFilteringSet << 16);
617 template <typename SubTableType, typename context_t>
618 inline typename context_t::return_t dispatch (context_t *c) const
620 unsigned int lookup_type = get_type ();
621 TRACE_DISPATCH (this, lookup_type);
622 unsigned int count = get_subtable_count ();
623 for (unsigned int i = 0; i < count; i++) {
624 typename context_t::return_t r = get_subtable<SubTableType> (i).dispatch (c, lookup_type);
625 if (c->stop_sublookup_iteration (r))
628 return_trace (c->default_return_value ());
631 inline bool serialize (hb_serialize_context_t *c,
632 unsigned int lookup_type,
633 uint32_t lookup_props,
634 unsigned int num_subtables)
636 TRACE_SERIALIZE (this);
637 if (unlikely (!c->extend_min (*this))) return_trace (false);
638 lookupType.set (lookup_type);
639 lookupFlag.set (lookup_props & 0xFFFFu);
640 if (unlikely (!subTable.serialize (c, num_subtables))) return_trace (false);
641 if (lookupFlag & LookupFlag::UseMarkFilteringSet)
643 HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
644 markFilteringSet.set (lookup_props >> 16);
649 inline bool sanitize (hb_sanitize_context_t *c) const
651 TRACE_SANITIZE (this);
652 /* Real sanitize of the subtables is done by GSUB/GPOS/... */
653 if (!(c->check_struct (this) && subTable.sanitize (c))) return_trace (false);
654 if (lookupFlag & LookupFlag::UseMarkFilteringSet)
656 const HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
657 if (!markFilteringSet.sanitize (c)) return_trace (false);
663 HBUINT16 lookupType; /* Different enumerations for GSUB and GPOS */
664 HBUINT16 lookupFlag; /* Lookup qualifiers */
666 subTable; /* Array of SubTables */
667 HBUINT16 markFilteringSetX[VAR]; /* Index (base 0) into GDEF mark glyph sets
668 * structure. This field is only present if bit
669 * UseMarkFilteringSet of lookup flags is set. */
671 DEFINE_SIZE_ARRAY2 (6, subTable, markFilteringSetX);
674 typedef OffsetListOf<Lookup> LookupList;
681 struct CoverageFormat1
683 friend struct Coverage;
686 inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
688 int i = glyphArray.bsearch (glyph_id);
689 static_assert ((((unsigned int) -1) == NOT_COVERED), "");
693 inline bool serialize (hb_serialize_context_t *c,
694 Supplier<GlyphID> &glyphs,
695 unsigned int num_glyphs)
697 TRACE_SERIALIZE (this);
698 if (unlikely (!c->extend_min (*this))) return_trace (false);
699 glyphArray.len.set (num_glyphs);
700 if (unlikely (!c->extend (glyphArray))) return_trace (false);
701 for (unsigned int i = 0; i < num_glyphs; i++)
702 glyphArray[i] = glyphs[i];
703 glyphs += num_glyphs;
707 inline bool sanitize (hb_sanitize_context_t *c) const
709 TRACE_SANITIZE (this);
710 return_trace (glyphArray.sanitize (c));
713 inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const {
714 return glyphs->has (glyphArray[index]);
717 template <typename set_t>
718 inline bool add_coverage (set_t *glyphs) const {
719 return glyphs->add_sorted_array (glyphArray.arrayZ, glyphArray.len);
723 /* Older compilers need this to be public. */
725 inline void init (const struct CoverageFormat1 &c_) { c = &c_; i = 0; };
726 inline bool more (void) { return i < c->glyphArray.len; }
727 inline void next (void) { i++; }
728 inline hb_codepoint_t get_glyph (void) { return c->glyphArray[i]; }
729 inline unsigned int get_coverage (void) { return i; }
732 const struct CoverageFormat1 *c;
738 HBUINT16 coverageFormat; /* Format identifier--format = 1 */
739 SortedArrayOf<GlyphID>
740 glyphArray; /* Array of GlyphIDs--in numerical order */
742 DEFINE_SIZE_ARRAY (4, glyphArray);
745 struct CoverageFormat2
747 friend struct Coverage;
750 inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
752 int i = rangeRecord.bsearch (glyph_id);
754 const RangeRecord &range = rangeRecord[i];
755 return (unsigned int) range.value + (glyph_id - range.start);
760 inline bool serialize (hb_serialize_context_t *c,
761 Supplier<GlyphID> &glyphs,
762 unsigned int num_glyphs)
764 TRACE_SERIALIZE (this);
765 if (unlikely (!c->extend_min (*this))) return_trace (false);
767 if (unlikely (!num_glyphs))
769 rangeRecord.len.set (0);
773 unsigned int num_ranges = 1;
774 for (unsigned int i = 1; i < num_glyphs; i++)
775 if (glyphs[i - 1] + 1 != glyphs[i])
777 rangeRecord.len.set (num_ranges);
778 if (unlikely (!c->extend (rangeRecord))) return_trace (false);
780 unsigned int range = 0;
781 rangeRecord[range].start = glyphs[0];
782 rangeRecord[range].value.set (0);
783 for (unsigned int i = 1; i < num_glyphs; i++)
784 if (glyphs[i - 1] + 1 != glyphs[i]) {
786 rangeRecord[range].start = glyphs[i];
787 rangeRecord[range].value.set (i);
788 rangeRecord[range].end = glyphs[i];
790 rangeRecord[range].end = glyphs[i];
792 glyphs += num_glyphs;
796 inline bool sanitize (hb_sanitize_context_t *c) const
798 TRACE_SANITIZE (this);
799 return_trace (rangeRecord.sanitize (c));
802 inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const {
804 unsigned int count = rangeRecord.len;
805 for (i = 0; i < count; i++) {
806 const RangeRecord &range = rangeRecord[i];
807 if (range.value <= index &&
808 index < (unsigned int) range.value + (range.end - range.start) &&
809 range.intersects (glyphs))
811 else if (index < range.value)
817 template <typename set_t>
818 inline bool add_coverage (set_t *glyphs) const {
819 unsigned int count = rangeRecord.len;
820 for (unsigned int i = 0; i < count; i++)
821 if (unlikely (!rangeRecord[i].add_coverage (glyphs)))
827 /* Older compilers need this to be public. */
830 inline void init (const CoverageFormat2 &c_)
835 j = c->rangeRecord.len ? c_.rangeRecord[0].start : 0;
837 inline bool more (void) { return i < c->rangeRecord.len; }
838 inline void next (void)
840 if (j >= c->rangeRecord[i].end)
845 j = c->rangeRecord[i].start;
846 coverage = c->rangeRecord[i].value;
853 inline hb_codepoint_t get_glyph (void) { return j; }
854 inline unsigned int get_coverage (void) { return coverage; }
857 const struct CoverageFormat2 *c;
858 unsigned int i, j, coverage;
863 HBUINT16 coverageFormat; /* Format identifier--format = 2 */
864 SortedArrayOf<RangeRecord>
865 rangeRecord; /* Array of glyph ranges--ordered by
866 * Start GlyphID. rangeCount entries
869 DEFINE_SIZE_ARRAY (4, rangeRecord);
874 inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
877 case 1: return u.format1.get_coverage (glyph_id);
878 case 2: return u.format2.get_coverage (glyph_id);
879 default:return NOT_COVERED;
883 inline bool serialize (hb_serialize_context_t *c,
884 Supplier<GlyphID> &glyphs,
885 unsigned int num_glyphs)
887 TRACE_SERIALIZE (this);
888 if (unlikely (!c->extend_min (*this))) return_trace (false);
889 unsigned int num_ranges = 1;
890 for (unsigned int i = 1; i < num_glyphs; i++)
891 if (glyphs[i - 1] + 1 != glyphs[i])
893 u.format.set (num_glyphs * 2 < num_ranges * 3 ? 1 : 2);
895 case 1: return_trace (u.format1.serialize (c, glyphs, num_glyphs));
896 case 2: return_trace (u.format2.serialize (c, glyphs, num_glyphs));
897 default:return_trace (false);
901 inline bool sanitize (hb_sanitize_context_t *c) const
903 TRACE_SANITIZE (this);
904 if (!u.format.sanitize (c)) return_trace (false);
906 case 1: return_trace (u.format1.sanitize (c));
907 case 2: return_trace (u.format2.sanitize (c));
908 default:return_trace (true);
912 inline bool intersects (const hb_set_t *glyphs) const {
913 /* TODO speed this up */
915 for (iter.init (*this); iter.more (); iter.next ()) {
916 if (glyphs->has (iter.get_glyph ()))
922 inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const {
924 case 1: return u.format1.intersects_coverage (glyphs, index);
925 case 2: return u.format2.intersects_coverage (glyphs, index);
926 default:return false;
930 /* Might return false if array looks unsorted.
931 * Used for faster rejection of corrupt data. */
932 template <typename set_t>
933 inline bool add_coverage (set_t *glyphs) const {
935 case 1: return u.format1.add_coverage (glyphs);
936 case 2: return u.format2.add_coverage (glyphs);
937 default:return false;
942 Iter (void) : format (0), u () {};
943 inline void init (const Coverage &c_) {
944 format = c_.u.format;
946 case 1: u.format1.init (c_.u.format1); return;
947 case 2: u.format2.init (c_.u.format2); return;
951 inline bool more (void) {
953 case 1: return u.format1.more ();
954 case 2: return u.format2.more ();
955 default:return false;
958 inline void next (void) {
960 case 1: u.format1.next (); break;
961 case 2: u.format2.next (); break;
965 inline hb_codepoint_t get_glyph (void) {
967 case 1: return u.format1.get_glyph ();
968 case 2: return u.format2.get_glyph ();
972 inline unsigned int get_coverage (void) {
974 case 1: return u.format1.get_coverage ();
975 case 2: return u.format2.get_coverage ();
983 CoverageFormat2::Iter format2; /* Put this one first since it's larger; helps shut up compiler. */
984 CoverageFormat1::Iter format1;
990 HBUINT16 format; /* Format identifier */
991 CoverageFormat1 format1;
992 CoverageFormat2 format2;
995 DEFINE_SIZE_UNION (2, format);
1000 * Class Definition Table
1003 struct ClassDefFormat1
1005 friend struct ClassDef;
1008 inline unsigned int get_class (hb_codepoint_t glyph_id) const
1010 unsigned int i = (unsigned int) (glyph_id - startGlyph);
1011 if (unlikely (i < classValue.len))
1012 return classValue[i];
1016 inline bool sanitize (hb_sanitize_context_t *c) const
1018 TRACE_SANITIZE (this);
1019 return_trace (c->check_struct (this) && classValue.sanitize (c));
1022 template <typename set_t>
1023 inline bool add_coverage (set_t *glyphs) const {
1024 unsigned int start = 0;
1025 unsigned int count = classValue.len;
1026 for (unsigned int i = 0; i < count; i++)
1032 if (unlikely (!glyphs->add_range (startGlyph + start, startGlyph + i)))
1038 if (unlikely (!glyphs->add_range (startGlyph + start, startGlyph + count)))
1044 template <typename set_t>
1045 inline bool add_class (set_t *glyphs, unsigned int klass) const {
1046 unsigned int count = classValue.len;
1047 for (unsigned int i = 0; i < count; i++)
1049 if (classValue[i] == klass)
1050 glyphs->add (startGlyph + i);
1055 inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
1056 unsigned int count = classValue.len;
1059 /* Match if there's any glyph that is not listed! */
1060 hb_codepoint_t g = HB_SET_VALUE_INVALID;
1061 if (!hb_set_next (glyphs, &g))
1065 g = startGlyph + count - 1;
1066 if (hb_set_next (glyphs, &g))
1070 for (unsigned int i = 0; i < count; i++)
1071 if (classValue[i] == klass && glyphs->has (startGlyph + i))
1077 HBUINT16 classFormat; /* Format identifier--format = 1 */
1078 GlyphID startGlyph; /* First GlyphID of the classValueArray */
1080 classValue; /* Array of Class Values--one per GlyphID */
1082 DEFINE_SIZE_ARRAY (6, classValue);
1085 struct ClassDefFormat2
1087 friend struct ClassDef;
1090 inline unsigned int get_class (hb_codepoint_t glyph_id) const
1092 int i = rangeRecord.bsearch (glyph_id);
1093 if (unlikely (i != -1))
1094 return rangeRecord[i].value;
1098 inline bool sanitize (hb_sanitize_context_t *c) const
1100 TRACE_SANITIZE (this);
1101 return_trace (rangeRecord.sanitize (c));
1104 template <typename set_t>
1105 inline bool add_coverage (set_t *glyphs) const {
1106 unsigned int count = rangeRecord.len;
1107 for (unsigned int i = 0; i < count; i++)
1108 if (rangeRecord[i].value)
1109 if (unlikely (!rangeRecord[i].add_coverage (glyphs)))
1114 template <typename set_t>
1115 inline bool add_class (set_t *glyphs, unsigned int klass) const {
1116 unsigned int count = rangeRecord.len;
1117 for (unsigned int i = 0; i < count; i++)
1119 if (rangeRecord[i].value == klass)
1120 if (unlikely (!rangeRecord[i].add_coverage (glyphs)))
1126 inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
1127 unsigned int count = rangeRecord.len;
1130 /* Match if there's any glyph that is not listed! */
1131 hb_codepoint_t g = HB_SET_VALUE_INVALID;
1132 for (unsigned int i = 0; i < count; i++)
1134 if (!hb_set_next (glyphs, &g))
1136 if (g < rangeRecord[i].start)
1138 g = rangeRecord[i].end;
1140 if (g != HB_SET_VALUE_INVALID && hb_set_next (glyphs, &g))
1144 for (unsigned int i = 0; i < count; i++)
1145 if (rangeRecord[i].value == klass && rangeRecord[i].intersects (glyphs))
1151 HBUINT16 classFormat; /* Format identifier--format = 2 */
1152 SortedArrayOf<RangeRecord>
1153 rangeRecord; /* Array of glyph ranges--ordered by
1156 DEFINE_SIZE_ARRAY (4, rangeRecord);
1161 inline unsigned int get_class (hb_codepoint_t glyph_id) const
1164 case 1: return u.format1.get_class (glyph_id);
1165 case 2: return u.format2.get_class (glyph_id);
1170 inline bool sanitize (hb_sanitize_context_t *c) const
1172 TRACE_SANITIZE (this);
1173 if (!u.format.sanitize (c)) return_trace (false);
1175 case 1: return_trace (u.format1.sanitize (c));
1176 case 2: return_trace (u.format2.sanitize (c));
1177 default:return_trace (true);
1181 /* Might return false if array looks unsorted.
1182 * Used for faster rejection of corrupt data. */
1183 template <typename set_t>
1184 inline bool add_coverage (set_t *glyphs) const {
1186 case 1: return u.format1.add_coverage (glyphs);
1187 case 2: return u.format2.add_coverage (glyphs);
1188 default:return false;
1192 /* Might return false if array looks unsorted.
1193 * Used for faster rejection of corrupt data. */
1194 template <typename set_t>
1195 inline bool add_class (set_t *glyphs, unsigned int klass) const {
1197 case 1: return u.format1.add_class (glyphs, klass);
1198 case 2: return u.format2.add_class (glyphs, klass);
1199 default:return false;
1203 inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
1205 case 1: return u.format1.intersects_class (glyphs, klass);
1206 case 2: return u.format2.intersects_class (glyphs, klass);
1207 default:return false;
1213 HBUINT16 format; /* Format identifier */
1214 ClassDefFormat1 format1;
1215 ClassDefFormat2 format2;
1218 DEFINE_SIZE_UNION (2, format);
1223 * Item Variation Store
1226 struct VarRegionAxis
1228 inline float evaluate (int coord) const
1230 int start = startCoord, peak = peakCoord, end = endCoord;
1232 /* TODO Move these to sanitize(). */
1233 if (unlikely (start > peak || peak > end))
1235 if (unlikely (start < 0 && end > 0 && peak != 0))
1238 if (peak == 0 || coord == peak)
1241 if (coord <= start || end <= coord)
1246 return float (coord - start) / (peak - start);
1248 return float (end - coord) / (end - peak);
1251 inline bool sanitize (hb_sanitize_context_t *c) const
1253 TRACE_SANITIZE (this);
1254 return_trace (c->check_struct (this));
1255 /* TODO Handle invalid start/peak/end configs, so we don't
1256 * have to do that at runtime. */
1264 DEFINE_SIZE_STATIC (6);
1267 struct VarRegionList
1269 inline float evaluate (unsigned int region_index,
1270 int *coords, unsigned int coord_len) const
1272 if (unlikely (region_index >= regionCount))
1275 const VarRegionAxis *axes = axesZ.arrayZ + (region_index * axisCount);
1278 unsigned int count = axisCount;
1279 for (unsigned int i = 0; i < count; i++)
1281 int coord = i < coord_len ? coords[i] : 0;
1282 float factor = axes[i].evaluate (coord);
1290 inline bool sanitize (hb_sanitize_context_t *c) const
1292 TRACE_SANITIZE (this);
1293 return_trace (c->check_struct (this) &&
1294 axesZ.sanitize (c, (unsigned int) axisCount * (unsigned int) regionCount));
1299 HBUINT16 regionCount;
1300 UnsizedArrayOf<VarRegionAxis>
1303 DEFINE_SIZE_ARRAY (4, axesZ);
1308 inline unsigned int get_row_size (void) const
1309 { return shortCount + regionIndices.len; }
1311 inline unsigned int get_size (void) const
1312 { return itemCount * get_row_size (); }
1314 inline float get_delta (unsigned int inner,
1315 int *coords, unsigned int coord_count,
1316 const VarRegionList ®ions) const
1318 if (unlikely (inner >= itemCount))
1321 unsigned int count = regionIndices.len;
1322 unsigned int scount = shortCount;
1324 const HBUINT8 *bytes = &StructAfter<HBUINT8> (regionIndices);
1325 const HBUINT8 *row = bytes + inner * (scount + count);
1330 const HBINT16 *scursor = reinterpret_cast<const HBINT16 *> (row);
1331 for (; i < scount; i++)
1333 float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count);
1334 delta += scalar * *scursor++;
1336 const HBINT8 *bcursor = reinterpret_cast<const HBINT8 *> (scursor);
1337 for (; i < count; i++)
1339 float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count);
1340 delta += scalar * *bcursor++;
1346 inline bool sanitize (hb_sanitize_context_t *c) const
1348 TRACE_SANITIZE (this);
1349 return_trace (c->check_struct (this) &&
1350 regionIndices.sanitize(c) &&
1351 shortCount <= regionIndices.len &&
1352 c->check_array (&StructAfter<HBUINT8> (regionIndices),
1353 get_row_size (), itemCount));
1358 HBUINT16 shortCount;
1359 ArrayOf<HBUINT16> regionIndices;
1360 HBUINT8 bytesX[VAR];
1362 DEFINE_SIZE_ARRAY2 (6, regionIndices, bytesX);
1365 struct VariationStore
1367 inline float get_delta (unsigned int outer, unsigned int inner,
1368 int *coords, unsigned int coord_count) const
1370 if (unlikely (outer >= dataSets.len))
1373 return (this+dataSets[outer]).get_delta (inner,
1374 coords, coord_count,
1378 inline float get_delta (unsigned int index,
1379 int *coords, unsigned int coord_count) const
1381 unsigned int outer = index >> 16;
1382 unsigned int inner = index & 0xFFFF;
1383 return get_delta (outer, inner, coords, coord_count);
1386 inline bool sanitize (hb_sanitize_context_t *c) const
1388 TRACE_SANITIZE (this);
1389 return_trace (c->check_struct (this) &&
1391 regions.sanitize (c, this) &&
1392 dataSets.sanitize (c, this));
1397 LOffsetTo<VarRegionList> regions;
1398 OffsetArrayOf<VarData, HBUINT32> dataSets;
1400 DEFINE_SIZE_ARRAY (8, dataSets);
1404 * Feature Variations
1407 struct ConditionFormat1
1409 friend struct Condition;
1412 inline bool evaluate (const int *coords, unsigned int coord_len) const
1414 int coord = axisIndex < coord_len ? coords[axisIndex] : 0;
1415 return filterRangeMinValue <= coord && coord <= filterRangeMaxValue;
1418 inline bool sanitize (hb_sanitize_context_t *c) const
1420 TRACE_SANITIZE (this);
1421 return_trace (c->check_struct (this));
1425 HBUINT16 format; /* Format identifier--format = 1 */
1427 F2DOT14 filterRangeMinValue;
1428 F2DOT14 filterRangeMaxValue;
1430 DEFINE_SIZE_STATIC (8);
1435 inline bool evaluate (const int *coords, unsigned int coord_len) const
1438 case 1: return u.format1.evaluate (coords, coord_len);
1439 default:return false;
1443 inline bool sanitize (hb_sanitize_context_t *c) const
1445 TRACE_SANITIZE (this);
1446 if (!u.format.sanitize (c)) return_trace (false);
1448 case 1: return_trace (u.format1.sanitize (c));
1449 default:return_trace (true);
1455 HBUINT16 format; /* Format identifier */
1456 ConditionFormat1 format1;
1459 DEFINE_SIZE_UNION (2, format);
1464 inline bool evaluate (const int *coords, unsigned int coord_len) const
1466 unsigned int count = conditions.len;
1467 for (unsigned int i = 0; i < count; i++)
1468 if (!(this+conditions.arrayZ[i]).evaluate (coords, coord_len))
1473 inline bool sanitize (hb_sanitize_context_t *c) const
1475 TRACE_SANITIZE (this);
1476 return_trace (conditions.sanitize (c, this));
1480 OffsetArrayOf<Condition, HBUINT32> conditions;
1482 DEFINE_SIZE_ARRAY (2, conditions);
1485 struct FeatureTableSubstitutionRecord
1487 friend struct FeatureTableSubstitution;
1489 inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
1491 TRACE_SANITIZE (this);
1492 return_trace (c->check_struct (this) && feature.sanitize (c, base));
1496 HBUINT16 featureIndex;
1497 LOffsetTo<Feature> feature;
1499 DEFINE_SIZE_STATIC (6);
1502 struct FeatureTableSubstitution
1504 inline const Feature *find_substitute (unsigned int feature_index) const
1506 unsigned int count = substitutions.len;
1507 for (unsigned int i = 0; i < count; i++)
1509 const FeatureTableSubstitutionRecord &record = substitutions.arrayZ[i];
1510 if (record.featureIndex == feature_index)
1511 return &(this+record.feature);
1516 inline bool sanitize (hb_sanitize_context_t *c) const
1518 TRACE_SANITIZE (this);
1519 return_trace (version.sanitize (c) &&
1520 likely (version.major == 1) &&
1521 substitutions.sanitize (c, this));
1525 FixedVersion<> version; /* Version--0x00010000u */
1526 ArrayOf<FeatureTableSubstitutionRecord>
1529 DEFINE_SIZE_ARRAY (6, substitutions);
1532 struct FeatureVariationRecord
1534 friend struct FeatureVariations;
1536 inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
1538 TRACE_SANITIZE (this);
1539 return_trace (conditions.sanitize (c, base) &&
1540 substitutions.sanitize (c, base));
1544 LOffsetTo<ConditionSet>
1546 LOffsetTo<FeatureTableSubstitution>
1549 DEFINE_SIZE_STATIC (8);
1552 struct FeatureVariations
1554 static const unsigned int NOT_FOUND_INDEX = 0xFFFFFFFFu;
1556 inline bool find_index (const int *coords, unsigned int coord_len,
1557 unsigned int *index) const
1559 unsigned int count = varRecords.len;
1560 for (unsigned int i = 0; i < count; i++)
1562 const FeatureVariationRecord &record = varRecords.arrayZ[i];
1563 if ((this+record.conditions).evaluate (coords, coord_len))
1569 *index = NOT_FOUND_INDEX;
1573 inline const Feature *find_substitute (unsigned int variations_index,
1574 unsigned int feature_index) const
1576 const FeatureVariationRecord &record = varRecords[variations_index];
1577 return (this+record.substitutions).find_substitute (feature_index);
1580 inline bool sanitize (hb_sanitize_context_t *c) const
1582 TRACE_SANITIZE (this);
1583 return_trace (version.sanitize (c) &&
1584 likely (version.major == 1) &&
1585 varRecords.sanitize (c, this));
1589 FixedVersion<> version; /* Version--0x00010000u */
1590 LArrayOf<FeatureVariationRecord>
1593 DEFINE_SIZE_ARRAY (8, varRecords);
1601 struct HintingDevice
1603 friend struct Device;
1607 inline hb_position_t get_x_delta (hb_font_t *font) const
1608 { return get_delta (font->x_ppem, font->x_scale); }
1610 inline hb_position_t get_y_delta (hb_font_t *font) const
1611 { return get_delta (font->y_ppem, font->y_scale); }
1613 inline unsigned int get_size (void) const
1615 unsigned int f = deltaFormat;
1616 if (unlikely (f < 1 || f > 3 || startSize > endSize)) return 3 * HBUINT16::static_size;
1617 return HBUINT16::static_size * (4 + ((endSize - startSize) >> (4 - f)));
1620 inline bool sanitize (hb_sanitize_context_t *c) const
1622 TRACE_SANITIZE (this);
1623 return_trace (c->check_struct (this) && c->check_range (this, this->get_size ()));
1628 inline int get_delta (unsigned int ppem, int scale) const
1630 if (!ppem) return 0;
1632 int pixels = get_delta_pixels (ppem);
1634 if (!pixels) return 0;
1636 return (int) (pixels * (int64_t) scale / ppem);
1638 inline int get_delta_pixels (unsigned int ppem_size) const
1640 unsigned int f = deltaFormat;
1641 if (unlikely (f < 1 || f > 3))
1644 if (ppem_size < startSize || ppem_size > endSize)
1647 unsigned int s = ppem_size - startSize;
1649 unsigned int byte = deltaValue[s >> (4 - f)];
1650 unsigned int bits = (byte >> (16 - (((s & ((1 << (4 - f)) - 1)) + 1) << f)));
1651 unsigned int mask = (0xFFFFu >> (16 - (1 << f)));
1653 int delta = bits & mask;
1655 if ((unsigned int) delta >= ((mask + 1) >> 1))
1662 HBUINT16 startSize; /* Smallest size to correct--in ppem */
1663 HBUINT16 endSize; /* Largest size to correct--in ppem */
1664 HBUINT16 deltaFormat; /* Format of DeltaValue array data: 1, 2, or 3
1665 * 1 Signed 2-bit value, 8 values per uint16
1666 * 2 Signed 4-bit value, 4 values per uint16
1667 * 3 Signed 8-bit value, 2 values per uint16
1669 HBUINT16 deltaValue[VAR]; /* Array of compressed data */
1671 DEFINE_SIZE_ARRAY (6, deltaValue);
1674 struct VariationDevice
1676 friend struct Device;
1680 inline hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store) const
1681 { return font->em_scalef_x (get_delta (font, store)); }
1683 inline hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store) const
1684 { return font->em_scalef_y (get_delta (font, store)); }
1686 inline bool sanitize (hb_sanitize_context_t *c) const
1688 TRACE_SANITIZE (this);
1689 return_trace (c->check_struct (this));
1694 inline float get_delta (hb_font_t *font, const VariationStore &store) const
1696 return store.get_delta (outerIndex, innerIndex, font->coords, font->num_coords);
1700 HBUINT16 outerIndex;
1701 HBUINT16 innerIndex;
1702 HBUINT16 deltaFormat; /* Format identifier for this table: 0x0x8000 */
1704 DEFINE_SIZE_STATIC (6);
1713 HBUINT16 format; /* Format identifier */
1715 DEFINE_SIZE_STATIC (6);
1720 inline hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store=Null(VariationStore)) const
1724 case 1: case 2: case 3:
1725 return u.hinting.get_x_delta (font);
1727 return u.variation.get_x_delta (font, store);
1732 inline hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store=Null(VariationStore)) const
1736 case 1: case 2: case 3:
1737 return u.hinting.get_y_delta (font);
1739 return u.variation.get_y_delta (font, store);
1745 inline bool sanitize (hb_sanitize_context_t *c) const
1747 TRACE_SANITIZE (this);
1748 if (!u.b.format.sanitize (c)) return_trace (false);
1749 switch (u.b.format) {
1750 case 1: case 2: case 3:
1751 return_trace (u.hinting.sanitize (c));
1753 return_trace (u.variation.sanitize (c));
1755 return_trace (true);
1762 HintingDevice hinting;
1763 VariationDevice variation;
1766 DEFINE_SIZE_UNION (6, b);
1770 } /* namespace OT */
1773 #endif /* HB_OT_LAYOUT_COMMON_PRIVATE_HH */