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_PRIVATE_HH
30 #define HB_OT_LAYOUT_COMMON_PRIVATE_HH
31 
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"
37 
38 
39 #ifndef HB_MAX_NESTING_LEVEL
40 #define HB_MAX_NESTING_LEVEL	6
41 #endif
42 #ifndef HB_MAX_CONTEXT_LENGTH
43 #define HB_MAX_CONTEXT_LENGTH	64
44 #endif
45 
46 
47 namespace OT {
48 
49 
50 #define NOT_COVERED		((unsigned int) -1)
51 
52 
53 
54 /*
55  *
56  * OpenType Layout Common Table Formats
57  *
58  */
59 
60 
61 /*
62  * Script, ScriptList, LangSys, Feature, FeatureList, Lookup, LookupList
63  */
64 
65 template <typename Type>
66 struct Record
67 {
cmpOT::Record68   inline int cmp (hb_tag_t a) const {
69     return tag.cmp (a);
70   }
71 
72   struct sanitize_closure_t {
73     hb_tag_t tag;
74     const void *list_base;
75   };
sanitizeOT::Record76   inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
77   {
78     TRACE_SANITIZE (this);
79     const sanitize_closure_t closure = {tag, base};
80     return_trace (c->check_struct (this) && offset.sanitize (c, base, &closure));
81   }
82 
83   Tag		tag;		/* 4-byte Tag identifier */
84   OffsetTo<Type>
85 		offset;		/* Offset from beginning of object holding
86 				 * the Record */
87   public:
88   DEFINE_SIZE_STATIC (6);
89 };
90 
91 template <typename Type>
92 struct RecordArrayOf : SortedArrayOf<Record<Type> > {
get_tagOT::RecordArrayOf93   inline const Tag& get_tag (unsigned int i) const
94   {
95     /* We cheat slightly and don't define separate Null objects
96      * for Record types.  Instead, we return the correct Null(Tag)
97      * here. */
98     if (unlikely (i >= this->len)) return Null(Tag);
99     return (*this)[i].tag;
100   }
get_tagsOT::RecordArrayOf101   inline unsigned int get_tags (unsigned int start_offset,
102 				unsigned int *record_count /* IN/OUT */,
103 				hb_tag_t     *record_tags /* OUT */) const
104   {
105     if (record_count) {
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;
110     }
111     return this->len;
112   }
find_indexOT::RecordArrayOf113   inline bool find_index (hb_tag_t tag, unsigned int *index) const
114   {
115     /* If we want to allow non-sorted data, we can lsearch(). */
116     int i = this->/*lsearch*/bsearch (tag);
117     if (i != -1) {
118         if (index) *index = i;
119         return true;
120     } else {
121       if (index) *index = Index::NOT_FOUND_INDEX;
122       return false;
123     }
124   }
125 };
126 
127 template <typename Type>
128 struct RecordListOf : RecordArrayOf<Type>
129 {
operator []OT::RecordListOf130   inline const Type& operator [] (unsigned int i) const
131   { return this+RecordArrayOf<Type>::operator [](i).offset; }
132 
sanitizeOT::RecordListOf133   inline bool sanitize (hb_sanitize_context_t *c) const
134   {
135     TRACE_SANITIZE (this);
136     return_trace (RecordArrayOf<Type>::sanitize (c, this));
137   }
138 };
139 
140 
141 struct RangeRecord
142 {
cmpOT::RangeRecord143   inline int cmp (hb_codepoint_t g) const {
144     return g < start ? -1 : g <= end ? 0 : +1 ;
145   }
146 
sanitizeOT::RangeRecord147   inline bool sanitize (hb_sanitize_context_t *c) const
148   {
149     TRACE_SANITIZE (this);
150     return_trace (c->check_struct (this));
151   }
152 
intersectsOT::RangeRecord153   inline bool intersects (const hb_set_t *glyphs) const {
154     return glyphs->intersects (start, end);
155   }
156 
157   template <typename set_t>
add_coverageOT::RangeRecord158   inline bool add_coverage (set_t *glyphs) const {
159     return glyphs->add_range (start, end);
160   }
161 
162   GlyphID	start;		/* First GlyphID in the range */
163   GlyphID	end;		/* Last GlyphID in the range */
164   UINT16	value;		/* Value */
165   public:
166   DEFINE_SIZE_STATIC (6);
167 };
168 DEFINE_NULL_DATA (RangeRecord, "\000\001");
169 
170 
171 struct IndexArray : ArrayOf<Index>
172 {
get_indexesOT::IndexArray173   inline unsigned int get_indexes (unsigned int start_offset,
174 				   unsigned int *_count /* IN/OUT */,
175 				   unsigned int *_indexes /* OUT */) const
176   {
177     if (_count) {
178       const UINT16 *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];
182     }
183     return this->len;
184   }
185 };
186 
187 
188 struct Script;
189 struct LangSys;
190 struct Feature;
191 
192 
193 struct LangSys
194 {
get_feature_countOT::LangSys195   inline unsigned int get_feature_count (void) const
196   { return featureIndex.len; }
get_feature_indexOT::LangSys197   inline hb_tag_t get_feature_index (unsigned int i) const
198   { return featureIndex[i]; }
get_feature_indexesOT::LangSys199   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); }
203 
has_required_featureOT::LangSys204   inline bool has_required_feature (void) const { return reqFeatureIndex != 0xFFFFu; }
get_required_feature_indexOT::LangSys205   inline unsigned int get_required_feature_index (void) const
206   {
207     if (reqFeatureIndex == 0xFFFFu)
208       return Index::NOT_FOUND_INDEX;
209    return reqFeatureIndex;;
210   }
211 
sanitizeOT::LangSys212   inline bool sanitize (hb_sanitize_context_t *c,
213 			const Record<LangSys>::sanitize_closure_t * = nullptr) const
214   {
215     TRACE_SANITIZE (this);
216     return_trace (c->check_struct (this) && featureIndex.sanitize (c));
217   }
218 
219   Offset16	lookupOrderZ;	/* = Null (reserved for an offset to a
220 				 * reordering table) */
221   UINT16	reqFeatureIndex;/* Index of a feature required for this
222 				 * language system--if no required features
223 				 * = 0xFFFFu */
224   IndexArray	featureIndex;	/* Array of indices into the FeatureList */
225   public:
226   DEFINE_SIZE_ARRAY (6, featureIndex);
227 };
228 DEFINE_NULL_DATA (LangSys, "\0\0\xFF\xFF");
229 
230 
231 struct Script
232 {
get_lang_sys_countOT::Script233   inline unsigned int get_lang_sys_count (void) const
234   { return langSys.len; }
get_lang_sys_tagOT::Script235   inline const Tag& get_lang_sys_tag (unsigned int i) const
236   { return langSys.get_tag (i); }
get_lang_sys_tagsOT::Script237   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); }
get_lang_sysOT::Script241   inline const LangSys& get_lang_sys (unsigned int i) const
242   {
243     if (i == Index::NOT_FOUND_INDEX) return get_default_lang_sys ();
244     return this+langSys[i].offset;
245   }
find_lang_sys_indexOT::Script246   inline bool find_lang_sys_index (hb_tag_t tag, unsigned int *index) const
247   { return langSys.find_index (tag, index); }
248 
has_default_lang_sysOT::Script249   inline bool has_default_lang_sys (void) const { return defaultLangSys != 0; }
get_default_lang_sysOT::Script250   inline const LangSys& get_default_lang_sys (void) const { return this+defaultLangSys; }
251 
sanitizeOT::Script252   inline bool sanitize (hb_sanitize_context_t *c,
253 			const Record<Script>::sanitize_closure_t * = nullptr) const
254   {
255     TRACE_SANITIZE (this);
256     return_trace (defaultLangSys.sanitize (c, this) && langSys.sanitize (c, this));
257   }
258 
259   protected:
260   OffsetTo<LangSys>
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 */
266   public:
267   DEFINE_SIZE_ARRAY (4, langSys);
268 };
269 
270 typedef RecordListOf<Script> ScriptList;
271 
272 
273 /* http://www.microsoft.com/typography/otspec/features_pt.htm#size */
274 struct FeatureParamsSize
275 {
sanitizeOT::FeatureParamsSize276   inline bool sanitize (hb_sanitize_context_t *c) const
277   {
278     TRACE_SANITIZE (this);
279     if (unlikely (!c->check_struct (this))) return_trace (false);
280 
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.
286      *
287      * Read Roberts wrote on 9/15/06 on opentype-list@indx.co.uk :
288      *
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.
292      *
293      * The specification for this feature tag is in the "OpenType Layout Tag
294      * Registry". You can see a copy of this at:
295      * http://partners.adobe.com/public/developer/opentype/index_tag8.html#size
296      *
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
299      * better.
300      *
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 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.
307      *
308      * If "design size" == 0:
309      *     fails check
310      *
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.
318      *
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)
325      *     fails test
326      * Else
327      *     passes test.
328      */
329 
330     if (!designSize)
331       return_trace (false);
332     else if (subfamilyID == 0 &&
333 	     subfamilyNameID == 0 &&
334 	     rangeStart == 0 &&
335 	     rangeEnd == 0)
336       return_trace (true);
337     else if (designSize < rangeStart ||
338 	     designSize > rangeEnd ||
339 	     subfamilyNameID < 256 ||
340 	     subfamilyNameID > 32767)
341       return_trace (false);
342     else
343       return_trace (true);
344   }
345 
346   UINT16	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   UINT16	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   UINT16	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   UINT16	rangeStart;	/* Large end of the recommended usage range
376 				 * (inclusive), stored in 720/inch units
377 				 * (decipoints). */
378   UINT16	rangeEnd;	/* Small end of the recommended usage range
379 				   (exclusive), stored in 720/inch units
380 				 * (decipoints). */
381   public:
382   DEFINE_SIZE_STATIC (10);
383 };
384 
385 /* http://www.microsoft.com/typography/otspec/features_pt.htm#ssxx */
386 struct FeatureParamsStylisticSet
387 {
sanitizeOT::FeatureParamsStylisticSet388   inline bool sanitize (hb_sanitize_context_t *c) const
389   {
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));
394   }
395 
396   UINT16	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. */
400 
401   UINT16	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. */
415   public:
416   DEFINE_SIZE_STATIC (4);
417 };
418 
419 /* http://www.microsoft.com/typography/otspec/features_ae.htm#cv01-cv99 */
420 struct FeatureParamsCharacterVariants
421 {
sanitizeOT::FeatureParamsCharacterVariants422   inline bool sanitize (hb_sanitize_context_t *c) const
423   {
424     TRACE_SANITIZE (this);
425     return_trace (c->check_struct (this) &&
426 		  characters.sanitize (c));
427   }
428 
429   UINT16	format;			/* Format number is set to 0. */
430   UINT16	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   UINT16	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
440 					 * nullptr.) */
441   UINT16	sampleTextNameID;	/* The ‘name’ table name ID that
442 					 * specifies sample text that
443 					 * illustrates the effect of this
444 					 * feature. (May be nullptr.) */
445   UINT16	numNamedParameters;	/* Number of named parameters. (May
446 					 * be zero.) */
447   UINT16	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.) */
452   ArrayOf<UINT24>
453 		characters;		/* Array of the Unicode Scalar Value
454 					 * of the characters for which this
455 					 * feature provides glyph variants.
456 					 * (May be zero.) */
457   public:
458   DEFINE_SIZE_ARRAY (14, characters);
459 };
460 
461 struct FeatureParams
462 {
sanitizeOT::FeatureParams463   inline bool sanitize (hb_sanitize_context_t *c, hb_tag_t tag) const
464   {
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));
472     return_trace (true);
473   }
474 
get_size_paramsOT::FeatureParams475   inline const FeatureParamsSize& get_size_params (hb_tag_t tag) const
476   {
477     if (tag == HB_TAG ('s','i','z','e'))
478       return u.size;
479     return Null(FeatureParamsSize);
480   }
481 
482   private:
483   union {
484   FeatureParamsSize			size;
485   FeatureParamsStylisticSet		stylisticSet;
486   FeatureParamsCharacterVariants	characterVariants;
487   } u;
488   DEFINE_SIZE_STATIC (17);
489 };
490 
491 struct Feature
492 {
get_lookup_countOT::Feature493   inline unsigned int get_lookup_count (void) const
494   { return lookupIndex.len; }
get_lookup_indexOT::Feature495   inline hb_tag_t get_lookup_index (unsigned int i) const
496   { return lookupIndex[i]; }
get_lookup_indexesOT::Feature497   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); }
501 
get_feature_paramsOT::Feature502   inline const FeatureParams &get_feature_params (void) const
503   { return this+featureParams; }
504 
sanitizeOT::Feature505   inline bool sanitize (hb_sanitize_context_t *c,
506 			const Record<Feature>::sanitize_closure_t *closure = nullptr) const
507   {
508     TRACE_SANITIZE (this);
509     if (unlikely (!(c->check_struct (this) && lookupIndex.sanitize (c))))
510       return_trace (false);
511 
512     /* Some earlier versions of Adobe tools calculated the offset of the
513      * FeatureParams subtable from the beginning of the FeatureList table!
514      *
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.
518      *
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.
521      */
522 
523     OffsetTo<FeatureParams> orig_offset = featureParams;
524     if (unlikely (!featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE)))
525       return_trace (false);
526 
527     if (likely (orig_offset.is_null ()))
528       return_trace (true);
529 
530     if (featureParams == 0 && closure &&
531 	closure->tag == HB_TAG ('s','i','z','e') &&
532 	closure->list_base && closure->list_base < this)
533     {
534       unsigned int new_offset_int = (unsigned int) orig_offset -
535 				    (((char *) this) - ((char *) closure->list_base));
536 
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);
544 
545       if (c->edit_count > 1)
546         c->edit_count--; /* This was a "legitimate" edit; don't contribute to error count. */
547     }
548 
549     return_trace (true);
550   }
551 
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
556 				 * if not required */
557   IndexArray	 lookupIndex;	/* Array of LookupList indices */
558   public:
559   DEFINE_SIZE_ARRAY (4, lookupIndex);
560 };
561 
562 typedef RecordListOf<Feature> FeatureList;
563 
564 
565 struct LookupFlag : UINT16
566 {
567   enum Flags {
568     RightToLeft		= 0x0001u,
569     IgnoreBaseGlyphs	= 0x0002u,
570     IgnoreLigatures	= 0x0004u,
571     IgnoreMarks		= 0x0008u,
572     IgnoreFlags		= 0x000Eu,
573     UseMarkFilteringSet	= 0x0010u,
574     Reserved		= 0x00E0u,
575     MarkAttachmentType	= 0xFF00u
576   };
577   public:
578   DEFINE_SIZE_STATIC (2);
579 };
580 
581 } /* namespace OT */
582 /* This has to be outside the namespace. */
583 HB_MARK_AS_FLAG_T (OT::LookupFlag::Flags);
584 namespace OT {
585 
586 struct Lookup
587 {
get_subtable_countOT::Lookup588   inline unsigned int get_subtable_count (void) const { return subTable.len; }
589 
590   template <typename SubTableType>
get_subtableOT::Lookup591   inline const SubTableType& get_subtable (unsigned int i) const
592   { return this+CastR<OffsetArrayOf<SubTableType> > (subTable)[i]; }
593 
594   template <typename SubTableType>
get_subtablesOT::Lookup595   inline const OffsetArrayOf<SubTableType>& get_subtables (void) const
596   { return CastR<OffsetArrayOf<SubTableType> > (subTable); }
597   template <typename SubTableType>
get_subtablesOT::Lookup598   inline OffsetArrayOf<SubTableType>& get_subtables (void)
599   { return CastR<OffsetArrayOf<SubTableType> > (subTable); }
600 
get_typeOT::Lookup601   inline unsigned int get_type (void) const { return lookupType; }
602 
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. */
get_propsOT::Lookup606   inline uint32_t get_props (void) const
607   {
608     unsigned int flag = lookupFlag;
609     if (unlikely (flag & LookupFlag::UseMarkFilteringSet))
610     {
611       const UINT16 &markFilteringSet = StructAfter<UINT16> (subTable);
612       flag += (markFilteringSet << 16);
613     }
614     return flag;
615   }
616 
617   template <typename SubTableType, typename context_t>
dispatchOT::Lookup618   inline typename context_t::return_t dispatch (context_t *c) const
619   {
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))
626         return_trace (r);
627     }
628     return_trace (c->default_return_value ());
629   }
630 
serializeOT::Lookup631   inline bool serialize (hb_serialize_context_t *c,
632 			 unsigned int lookup_type,
633 			 uint32_t lookup_props,
634 			 unsigned int num_subtables)
635   {
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)
642     {
643       UINT16 &markFilteringSet = StructAfter<UINT16> (subTable);
644       markFilteringSet.set (lookup_props >> 16);
645     }
646     return_trace (true);
647   }
648 
sanitizeOT::Lookup649   inline bool sanitize (hb_sanitize_context_t *c) const
650   {
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)
655     {
656       const UINT16 &markFilteringSet = StructAfter<UINT16> (subTable);
657       if (!markFilteringSet.sanitize (c)) return_trace (false);
658     }
659     return_trace (true);
660   }
661 
662   private:
663   UINT16	lookupType;		/* Different enumerations for GSUB and GPOS */
664   UINT16	lookupFlag;		/* Lookup qualifiers */
665   ArrayOf<Offset16>
666 		subTable;		/* Array of SubTables */
667   UINT16	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. */
670   public:
671   DEFINE_SIZE_ARRAY2 (6, subTable, markFilteringSetX);
672 };
673 
674 typedef OffsetListOf<Lookup> LookupList;
675 
676 
677 /*
678  * Coverage Table
679  */
680 
681 struct CoverageFormat1
682 {
683   friend struct Coverage;
684 
685   private:
get_coverageOT::CoverageFormat1686   inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
687   {
688     int i = glyphArray.bsearch (glyph_id);
689     static_assert ((((unsigned int) -1) == NOT_COVERED), "");
690     return i;
691   }
692 
serializeOT::CoverageFormat1693   inline bool serialize (hb_serialize_context_t *c,
694 			 Supplier<GlyphID> &glyphs,
695 			 unsigned int num_glyphs)
696   {
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.advance (num_glyphs);
704     return_trace (true);
705   }
706 
sanitizeOT::CoverageFormat1707   inline bool sanitize (hb_sanitize_context_t *c) const
708   {
709     TRACE_SANITIZE (this);
710     return_trace (glyphArray.sanitize (c));
711   }
712 
intersects_coverageOT::CoverageFormat1713   inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const {
714     return glyphs->has (glyphArray[index]);
715   }
716 
717   template <typename set_t>
add_coverageOT::CoverageFormat1718   inline bool add_coverage (set_t *glyphs) const {
719     return glyphs->add_sorted_array (glyphArray.array, glyphArray.len);
720   }
721 
722   public:
723   /* Older compilers need this to be public. */
724   struct Iter {
initOT::CoverageFormat1::Iter725     inline void init (const struct CoverageFormat1 &c_) { c = &c_; i = 0; };
moreOT::CoverageFormat1::Iter726     inline bool more (void) { return i < c->glyphArray.len; }
nextOT::CoverageFormat1::Iter727     inline void next (void) { i++; }
get_glyphOT::CoverageFormat1::Iter728     inline hb_codepoint_t get_glyph (void) { return c->glyphArray[i]; }
get_coverageOT::CoverageFormat1::Iter729     inline unsigned int get_coverage (void) { return i; }
730 
731     private:
732     const struct CoverageFormat1 *c;
733     unsigned int i;
734   };
735   private:
736 
737   protected:
738   UINT16	coverageFormat;	/* Format identifier--format = 1 */
739   SortedArrayOf<GlyphID>
740 		glyphArray;	/* Array of GlyphIDs--in numerical order */
741   public:
742   DEFINE_SIZE_ARRAY (4, glyphArray);
743 };
744 
745 struct CoverageFormat2
746 {
747   friend struct Coverage;
748 
749   private:
get_coverageOT::CoverageFormat2750   inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
751   {
752     int i = rangeRecord.bsearch (glyph_id);
753     if (i != -1) {
754       const RangeRecord &range = rangeRecord[i];
755       return (unsigned int) range.value + (glyph_id - range.start);
756     }
757     return NOT_COVERED;
758   }
759 
serializeOT::CoverageFormat2760   inline bool serialize (hb_serialize_context_t *c,
761 			 Supplier<GlyphID> &glyphs,
762 			 unsigned int num_glyphs)
763   {
764     TRACE_SERIALIZE (this);
765     if (unlikely (!c->extend_min (*this))) return_trace (false);
766 
767     if (unlikely (!num_glyphs))
768     {
769       rangeRecord.len.set (0);
770       return_trace (true);
771     }
772 
773     unsigned int num_ranges = 1;
774     for (unsigned int i = 1; i < num_glyphs; i++)
775       if (glyphs[i - 1] + 1 != glyphs[i])
776         num_ranges++;
777     rangeRecord.len.set (num_ranges);
778     if (unlikely (!c->extend (rangeRecord))) return_trace (false);
779 
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]) {
785 	range++;
786 	rangeRecord[range].start = glyphs[i];
787 	rangeRecord[range].value.set (i);
788         rangeRecord[range].end = glyphs[i];
789       } else {
790         rangeRecord[range].end = glyphs[i];
791       }
792     glyphs.advance (num_glyphs);
793     return_trace (true);
794   }
795 
sanitizeOT::CoverageFormat2796   inline bool sanitize (hb_sanitize_context_t *c) const
797   {
798     TRACE_SANITIZE (this);
799     return_trace (rangeRecord.sanitize (c));
800   }
801 
intersects_coverageOT::CoverageFormat2802   inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const {
803     unsigned int i;
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))
810         return true;
811       else if (index < range.value)
812         return false;
813     }
814     return false;
815   }
816 
817   template <typename set_t>
add_coverageOT::CoverageFormat2818   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)))
822         return false;
823     return true;
824   }
825 
826   public:
827   /* Older compilers need this to be public. */
828   struct Iter
829   {
initOT::CoverageFormat2::Iter830     inline void init (const CoverageFormat2 &c_)
831     {
832       c = &c_;
833       coverage = 0;
834       i = 0;
835       j = c->rangeRecord.len ? c_.rangeRecord[0].start : 0;
836     }
moreOT::CoverageFormat2::Iter837     inline bool more (void) { return i < c->rangeRecord.len; }
nextOT::CoverageFormat2::Iter838     inline void next (void)
839     {
840       if (j >= c->rangeRecord[i].end)
841       {
842         i++;
843 	if (more ())
844 	{
845 	  j = c->rangeRecord[i].start;
846 	  coverage = c->rangeRecord[i].value;
847 	}
848 	return;
849       }
850       coverage++;
851       j++;
852     }
get_glyphOT::CoverageFormat2::Iter853     inline hb_codepoint_t get_glyph (void) { return j; }
get_coverageOT::CoverageFormat2::Iter854     inline unsigned int get_coverage (void) { return coverage; }
855 
856     private:
857     const struct CoverageFormat2 *c;
858     unsigned int i, j, coverage;
859   };
860   private:
861 
862   protected:
863   UINT16	coverageFormat;	/* Format identifier--format = 2 */
864   SortedArrayOf<RangeRecord>
865 		rangeRecord;	/* Array of glyph ranges--ordered by
866 				 * Start GlyphID. rangeCount entries
867 				 * long */
868   public:
869   DEFINE_SIZE_ARRAY (4, rangeRecord);
870 };
871 
872 struct Coverage
873 {
get_coverageOT::Coverage874   inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
875   {
876     switch (u.format) {
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;
880     }
881   }
882 
serializeOT::Coverage883   inline bool serialize (hb_serialize_context_t *c,
884 			 Supplier<GlyphID> &glyphs,
885 			 unsigned int num_glyphs)
886   {
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])
892         num_ranges++;
893     u.format.set (num_glyphs * 2 < num_ranges * 3 ? 1 : 2);
894     switch (u.format) {
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);
898     }
899   }
900 
sanitizeOT::Coverage901   inline bool sanitize (hb_sanitize_context_t *c) const
902   {
903     TRACE_SANITIZE (this);
904     if (!u.format.sanitize (c)) return_trace (false);
905     switch (u.format) {
906     case 1: return_trace (u.format1.sanitize (c));
907     case 2: return_trace (u.format2.sanitize (c));
908     default:return_trace (true);
909     }
910   }
911 
intersectsOT::Coverage912   inline bool intersects (const hb_set_t *glyphs) const {
913     /* TODO speed this up */
914     Coverage::Iter iter;
915     for (iter.init (*this); iter.more (); iter.next ()) {
916       if (glyphs->has (iter.get_glyph ()))
917         return true;
918     }
919     return false;
920   }
921 
intersects_coverageOT::Coverage922   inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const {
923     switch (u.format) {
924     case 1: return u.format1.intersects_coverage (glyphs, index);
925     case 2: return u.format2.intersects_coverage (glyphs, index);
926     default:return false;
927     }
928   }
929 
930   /* Might return false if array looks unsorted.
931    * Used for faster rejection of corrupt data. */
932   template <typename set_t>
add_coverageOT::Coverage933   inline bool add_coverage (set_t *glyphs) const {
934     switch (u.format) {
935     case 1: return u.format1.add_coverage (glyphs);
936     case 2: return u.format2.add_coverage (glyphs);
937     default:return false;
938     }
939   }
940 
941   struct Iter {
IterOT::Coverage::Iter942     Iter (void) : format (0), u () {};
initOT::Coverage::Iter943     inline void init (const Coverage &c_) {
944       format = c_.u.format;
945       switch (format) {
946       case 1: u.format1.init (c_.u.format1); return;
947       case 2: u.format2.init (c_.u.format2); return;
948       default:                               return;
949       }
950     }
moreOT::Coverage::Iter951     inline bool more (void) {
952       switch (format) {
953       case 1: return u.format1.more ();
954       case 2: return u.format2.more ();
955       default:return false;
956       }
957     }
nextOT::Coverage::Iter958     inline void next (void) {
959       switch (format) {
960       case 1: u.format1.next (); break;
961       case 2: u.format2.next (); break;
962       default:                   break;
963       }
964     }
get_glyphOT::Coverage::Iter965     inline hb_codepoint_t get_glyph (void) {
966       switch (format) {
967       case 1: return u.format1.get_glyph ();
968       case 2: return u.format2.get_glyph ();
969       default:return 0;
970       }
971     }
get_coverageOT::Coverage::Iter972     inline unsigned int get_coverage (void) {
973       switch (format) {
974       case 1: return u.format1.get_coverage ();
975       case 2: return u.format2.get_coverage ();
976       default:return -1;
977       }
978     }
979 
980     private:
981     unsigned int format;
982     union {
983     CoverageFormat2::Iter	format2; /* Put this one first since it's larger; helps shut up compiler. */
984     CoverageFormat1::Iter	format1;
985     } u;
986   };
987 
988   protected:
989   union {
990   UINT16		format;		/* Format identifier */
991   CoverageFormat1	format1;
992   CoverageFormat2	format2;
993   } u;
994   public:
995   DEFINE_SIZE_UNION (2, format);
996 };
997 
998 
999 /*
1000  * Class Definition Table
1001  */
1002 
1003 struct ClassDefFormat1
1004 {
1005   friend struct ClassDef;
1006 
1007   private:
get_classOT::ClassDefFormat11008   inline unsigned int get_class (hb_codepoint_t glyph_id) const
1009   {
1010     unsigned int i = (unsigned int) (glyph_id - startGlyph);
1011     if (unlikely (i < classValue.len))
1012       return classValue[i];
1013     return 0;
1014   }
1015 
sanitizeOT::ClassDefFormat11016   inline bool sanitize (hb_sanitize_context_t *c) const
1017   {
1018     TRACE_SANITIZE (this);
1019     return_trace (c->check_struct (this) && classValue.sanitize (c));
1020   }
1021 
1022   template <typename set_t>
add_coverageOT::ClassDefFormat11023   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++)
1027     {
1028       if (classValue[i])
1029         continue;
1030 
1031       if (start != i)
1032 	if (unlikely (!glyphs->add_range (startGlyph + start, startGlyph + i)))
1033 	  return false;
1034 
1035       start = i + 1;
1036     }
1037     if (start != count)
1038       if (unlikely (!glyphs->add_range (startGlyph + start, startGlyph + count)))
1039 	return false;
1040 
1041     return true;
1042   }
1043 
1044   template <typename set_t>
add_classOT::ClassDefFormat11045   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++)
1048     {
1049       if (classValue[i] == klass)
1050         glyphs->add (startGlyph + i);
1051     }
1052     return true;
1053   }
1054 
intersects_classOT::ClassDefFormat11055   inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
1056     unsigned int count = classValue.len;
1057     if (klass == 0)
1058     {
1059       /* Match if there's any glyph that is not listed! */
1060       hb_codepoint_t g = -1;
1061       if (!hb_set_next (glyphs, &g))
1062         return false;
1063       if (g < startGlyph)
1064         return true;
1065       g = startGlyph + count - 1;
1066       if (hb_set_next (glyphs, &g))
1067         return true;
1068       /* Fall through. */
1069     }
1070     for (unsigned int i = 0; i < count; i++)
1071       if (classValue[i] == klass && glyphs->has (startGlyph + i))
1072         return true;
1073     return false;
1074   }
1075 
1076   protected:
1077   UINT16	classFormat;		/* Format identifier--format = 1 */
1078   GlyphID	startGlyph;		/* First GlyphID of the classValueArray */
1079   ArrayOf<UINT16>
1080 		classValue;		/* Array of Class Values--one per GlyphID */
1081   public:
1082   DEFINE_SIZE_ARRAY (6, classValue);
1083 };
1084 
1085 struct ClassDefFormat2
1086 {
1087   friend struct ClassDef;
1088 
1089   private:
get_classOT::ClassDefFormat21090   inline unsigned int get_class (hb_codepoint_t glyph_id) const
1091   {
1092     int i = rangeRecord.bsearch (glyph_id);
1093     if (unlikely (i != -1))
1094       return rangeRecord[i].value;
1095     return 0;
1096   }
1097 
sanitizeOT::ClassDefFormat21098   inline bool sanitize (hb_sanitize_context_t *c) const
1099   {
1100     TRACE_SANITIZE (this);
1101     return_trace (rangeRecord.sanitize (c));
1102   }
1103 
1104   template <typename set_t>
add_coverageOT::ClassDefFormat21105   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)))
1110 	  return false;
1111     return true;
1112   }
1113 
1114   template <typename set_t>
add_classOT::ClassDefFormat21115   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++)
1118     {
1119       if (rangeRecord[i].value == klass)
1120         if (unlikely (!rangeRecord[i].add_coverage (glyphs)))
1121 	  return false;
1122     }
1123     return true;
1124   }
1125 
intersects_classOT::ClassDefFormat21126   inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
1127     unsigned int count = rangeRecord.len;
1128     if (klass == 0)
1129     {
1130       /* Match if there's any glyph that is not listed! */
1131       hb_codepoint_t g = (hb_codepoint_t) -1;
1132       for (unsigned int i = 0; i < count; i++)
1133       {
1134 	if (!hb_set_next (glyphs, &g))
1135 	  break;
1136 	if (g < rangeRecord[i].start)
1137 	  return true;
1138 	g = rangeRecord[i].end;
1139       }
1140       if (g != (hb_codepoint_t) -1 && hb_set_next (glyphs, &g))
1141         return true;
1142       /* Fall through. */
1143     }
1144     for (unsigned int i = 0; i < count; i++)
1145       if (rangeRecord[i].value == klass && rangeRecord[i].intersects (glyphs))
1146         return true;
1147     return false;
1148   }
1149 
1150   protected:
1151   UINT16	classFormat;	/* Format identifier--format = 2 */
1152   SortedArrayOf<RangeRecord>
1153 		rangeRecord;	/* Array of glyph ranges--ordered by
1154 				 * Start GlyphID */
1155   public:
1156   DEFINE_SIZE_ARRAY (4, rangeRecord);
1157 };
1158 
1159 struct ClassDef
1160 {
get_classOT::ClassDef1161   inline unsigned int get_class (hb_codepoint_t glyph_id) const
1162   {
1163     switch (u.format) {
1164     case 1: return u.format1.get_class(glyph_id);
1165     case 2: return u.format2.get_class(glyph_id);
1166     default:return 0;
1167     }
1168   }
1169 
sanitizeOT::ClassDef1170   inline bool sanitize (hb_sanitize_context_t *c) const
1171   {
1172     TRACE_SANITIZE (this);
1173     if (!u.format.sanitize (c)) return_trace (false);
1174     switch (u.format) {
1175     case 1: return_trace (u.format1.sanitize (c));
1176     case 2: return_trace (u.format2.sanitize (c));
1177     default:return_trace (true);
1178     }
1179   }
1180 
1181   /* Might return false if array looks unsorted.
1182    * Used for faster rejection of corrupt data. */
1183   template <typename set_t>
add_coverageOT::ClassDef1184   inline bool add_coverage (set_t *glyphs) const {
1185     switch (u.format) {
1186     case 1: return u.format1.add_coverage (glyphs);
1187     case 2: return u.format2.add_coverage (glyphs);
1188     default:return false;
1189     }
1190   }
1191 
1192   /* Might return false if array looks unsorted.
1193    * Used for faster rejection of corrupt data. */
1194   template <typename set_t>
add_classOT::ClassDef1195   inline bool add_class (set_t *glyphs, unsigned int klass) const {
1196     switch (u.format) {
1197     case 1: return u.format1.add_class (glyphs, klass);
1198     case 2: return u.format2.add_class (glyphs, klass);
1199     default:return false;
1200     }
1201   }
1202 
intersects_classOT::ClassDef1203   inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
1204     switch (u.format) {
1205     case 1: return u.format1.intersects_class (glyphs, klass);
1206     case 2: return u.format2.intersects_class (glyphs, klass);
1207     default:return false;
1208     }
1209   }
1210 
1211   protected:
1212   union {
1213   UINT16		format;		/* Format identifier */
1214   ClassDefFormat1	format1;
1215   ClassDefFormat2	format2;
1216   } u;
1217   public:
1218   DEFINE_SIZE_UNION (2, format);
1219 };
1220 
1221 
1222 /*
1223  * Item Variation Store
1224  */
1225 
1226 struct VarRegionAxis
1227 {
evaluateOT::VarRegionAxis1228   inline float evaluate (int coord) const
1229   {
1230     int start = startCoord, peak = peakCoord, end = endCoord;
1231 
1232     /* TODO Move these to sanitize(). */
1233     if (unlikely (start > peak || peak > end))
1234       return 1.;
1235     if (unlikely (start < 0 && end > 0 && peak != 0))
1236       return 1.;
1237 
1238     if (peak == 0 || coord == peak)
1239       return 1.;
1240 
1241     if (coord <= start || end <= coord)
1242       return 0.;
1243 
1244     /* Interpolate */
1245     if (coord < peak)
1246       return float (coord - start) / (peak - start);
1247     else
1248       return float (end - coord) / (end - peak);
1249   }
1250 
sanitizeOT::VarRegionAxis1251   inline bool sanitize (hb_sanitize_context_t *c) const
1252   {
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. */
1257   }
1258 
1259   public:
1260   F2DOT14	startCoord;
1261   F2DOT14	peakCoord;
1262   F2DOT14	endCoord;
1263   public:
1264   DEFINE_SIZE_STATIC (6);
1265 };
1266 
1267 struct VarRegionList
1268 {
evaluateOT::VarRegionList1269   inline float evaluate (unsigned int region_index,
1270 			 int *coords, unsigned int coord_len) const
1271   {
1272     if (unlikely (region_index >= regionCount))
1273       return 0.;
1274 
1275     const VarRegionAxis *axes = axesZ + (region_index * axisCount);
1276 
1277     float v = 1.;
1278     unsigned int count = MIN (coord_len, (unsigned int) axisCount);
1279     for (unsigned int i = 0; i < count; i++)
1280     {
1281       float factor = axes[i].evaluate (coords[i]);
1282       if (factor == 0.)
1283         return 0.;
1284       v *= factor;
1285     }
1286     return v;
1287   }
1288 
sanitizeOT::VarRegionList1289   inline bool sanitize (hb_sanitize_context_t *c) const
1290   {
1291     TRACE_SANITIZE (this);
1292     return_trace (c->check_struct (this) &&
1293 		  c->check_array (axesZ, axesZ[0].static_size,
1294 				  (unsigned int) axisCount * (unsigned int) regionCount));
1295   }
1296 
1297   protected:
1298   UINT16	axisCount;
1299   UINT16	regionCount;
1300   VarRegionAxis	axesZ[VAR];
1301   public:
1302   DEFINE_SIZE_ARRAY (4, axesZ);
1303 };
1304 
1305 struct VarData
1306 {
get_row_sizeOT::VarData1307   inline unsigned int get_row_size (void) const
1308   { return shortCount + regionIndices.len; }
1309 
get_sizeOT::VarData1310   inline unsigned int get_size (void) const
1311   { return itemCount * get_row_size (); }
1312 
get_deltaOT::VarData1313   inline float get_delta (unsigned int inner,
1314 			  int *coords, unsigned int coord_count,
1315 			  const VarRegionList &regions) const
1316   {
1317     if (unlikely (inner >= itemCount))
1318       return 0.;
1319 
1320    unsigned int count = regionIndices.len;
1321    unsigned int scount = shortCount;
1322 
1323    const UINT8 *bytes = &StructAfter<UINT8> (regionIndices);
1324    const UINT8 *row = bytes + inner * (scount + count);
1325 
1326    float delta = 0.;
1327    unsigned int i = 0;
1328 
1329    const INT16 *scursor = reinterpret_cast<const INT16 *> (row);
1330    for (; i < scount; i++)
1331    {
1332      float scalar = regions.evaluate (regionIndices.array[i], coords, coord_count);
1333      delta += scalar * *scursor++;
1334    }
1335    const INT8 *bcursor = reinterpret_cast<const INT8 *> (scursor);
1336    for (; i < count; i++)
1337    {
1338      float scalar = regions.evaluate (regionIndices.array[i], coords, coord_count);
1339      delta += scalar * *bcursor++;
1340    }
1341 
1342    return delta;
1343   }
1344 
sanitizeOT::VarData1345   inline bool sanitize (hb_sanitize_context_t *c) const
1346   {
1347     TRACE_SANITIZE (this);
1348     return_trace (c->check_struct (this) &&
1349 		  regionIndices.sanitize(c) &&
1350 		  shortCount <= regionIndices.len &&
1351 		  c->check_array (&StructAfter<UINT8> (regionIndices),
1352 				  get_row_size (), itemCount));
1353   }
1354 
1355   protected:
1356   UINT16		itemCount;
1357   UINT16		shortCount;
1358   ArrayOf<UINT16>	regionIndices;
1359   UINT8			bytesX[VAR];
1360   public:
1361   DEFINE_SIZE_ARRAY2 (6, regionIndices, bytesX);
1362 };
1363 
1364 struct VariationStore
1365 {
get_deltaOT::VariationStore1366   inline float get_delta (unsigned int outer, unsigned int inner,
1367 			  int *coords, unsigned int coord_count) const
1368   {
1369     if (unlikely (outer >= dataSets.len))
1370       return 0.;
1371 
1372     return (this+dataSets[outer]).get_delta (inner,
1373 					     coords, coord_count,
1374 					     this+regions);
1375   }
1376 
get_deltaOT::VariationStore1377   inline float get_delta (unsigned int index,
1378 			  int *coords, unsigned int coord_count) const
1379   {
1380     unsigned int outer = index >> 16;
1381     unsigned int inner = index & 0xFFFF;
1382     return get_delta (outer, inner, coords, coord_count);
1383   }
1384 
sanitizeOT::VariationStore1385   inline bool sanitize (hb_sanitize_context_t *c) const
1386   {
1387     TRACE_SANITIZE (this);
1388     return_trace (c->check_struct (this) &&
1389 		  format == 1 &&
1390 		  regions.sanitize (c, this) &&
1391 		  dataSets.sanitize (c, this));
1392   }
1393 
1394   protected:
1395   UINT16				format;
1396   LOffsetTo<VarRegionList>		regions;
1397   OffsetArrayOf<VarData, UINT32>		dataSets;
1398   public:
1399   DEFINE_SIZE_ARRAY (8, dataSets);
1400 };
1401 
1402 /*
1403  * Feature Variations
1404  */
1405 
1406 struct ConditionFormat1
1407 {
1408   friend struct Condition;
1409 
1410   private:
evaluateOT::ConditionFormat11411   inline bool evaluate (const int *coords, unsigned int coord_len) const
1412   {
1413     int coord = axisIndex < coord_len ? coords[axisIndex] : 0;
1414     return filterRangeMinValue <= coord && coord <= filterRangeMaxValue;
1415   }
1416 
sanitizeOT::ConditionFormat11417   inline bool sanitize (hb_sanitize_context_t *c) const
1418   {
1419     TRACE_SANITIZE (this);
1420     return_trace (c->check_struct (this));
1421   }
1422 
1423   protected:
1424   UINT16	format;		/* Format identifier--format = 1 */
1425   UINT16	axisIndex;
1426   F2DOT14	filterRangeMinValue;
1427   F2DOT14	filterRangeMaxValue;
1428   public:
1429   DEFINE_SIZE_STATIC (8);
1430 };
1431 
1432 struct Condition
1433 {
evaluateOT::Condition1434   inline bool evaluate (const int *coords, unsigned int coord_len) const
1435   {
1436     switch (u.format) {
1437     case 1: return u.format1.evaluate (coords, coord_len);
1438     default:return false;
1439     }
1440   }
1441 
sanitizeOT::Condition1442   inline bool sanitize (hb_sanitize_context_t *c) const
1443   {
1444     TRACE_SANITIZE (this);
1445     if (!u.format.sanitize (c)) return_trace (false);
1446     switch (u.format) {
1447     case 1: return_trace (u.format1.sanitize (c));
1448     default:return_trace (true);
1449     }
1450   }
1451 
1452   protected:
1453   union {
1454   UINT16		format;		/* Format identifier */
1455   ConditionFormat1	format1;
1456   } u;
1457   public:
1458   DEFINE_SIZE_UNION (2, format);
1459 };
1460 
1461 struct ConditionSet
1462 {
evaluateOT::ConditionSet1463   inline bool evaluate (const int *coords, unsigned int coord_len) const
1464   {
1465     unsigned int count = conditions.len;
1466     for (unsigned int i = 0; i < count; i++)
1467       if (!(this+conditions.array[i]).evaluate (coords, coord_len))
1468         return false;
1469     return true;
1470   }
1471 
sanitizeOT::ConditionSet1472   inline bool sanitize (hb_sanitize_context_t *c) const
1473   {
1474     TRACE_SANITIZE (this);
1475     return_trace (conditions.sanitize (c, this));
1476   }
1477 
1478   protected:
1479   OffsetArrayOf<Condition, UINT32> conditions;
1480   public:
1481   DEFINE_SIZE_ARRAY (2, conditions);
1482 };
1483 
1484 struct FeatureTableSubstitutionRecord
1485 {
1486   friend struct FeatureTableSubstitution;
1487 
sanitizeOT::FeatureTableSubstitutionRecord1488   inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
1489   {
1490     TRACE_SANITIZE (this);
1491     return_trace (c->check_struct (this) && feature.sanitize (c, base));
1492   }
1493 
1494   protected:
1495   UINT16		featureIndex;
1496   LOffsetTo<Feature>	feature;
1497   public:
1498   DEFINE_SIZE_STATIC (6);
1499 };
1500 
1501 struct FeatureTableSubstitution
1502 {
find_substituteOT::FeatureTableSubstitution1503   inline const Feature *find_substitute (unsigned int feature_index) const
1504   {
1505     unsigned int count = substitutions.len;
1506     for (unsigned int i = 0; i < count; i++)
1507     {
1508       const FeatureTableSubstitutionRecord &record = substitutions.array[i];
1509       if (record.featureIndex == feature_index)
1510 	return &(this+record.feature);
1511     }
1512     return nullptr;
1513   }
1514 
sanitizeOT::FeatureTableSubstitution1515   inline bool sanitize (hb_sanitize_context_t *c) const
1516   {
1517     TRACE_SANITIZE (this);
1518     return_trace (version.sanitize (c) &&
1519 		  likely (version.major == 1) &&
1520 		  substitutions.sanitize (c, this));
1521   }
1522 
1523   protected:
1524   FixedVersion<>	version;	/* Version--0x00010000u */
1525   ArrayOf<FeatureTableSubstitutionRecord>
1526 			substitutions;
1527   public:
1528   DEFINE_SIZE_ARRAY (6, substitutions);
1529 };
1530 
1531 struct FeatureVariationRecord
1532 {
1533   friend struct FeatureVariations;
1534 
sanitizeOT::FeatureVariationRecord1535   inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
1536   {
1537     TRACE_SANITIZE (this);
1538     return_trace (conditions.sanitize (c, base) &&
1539 		  substitutions.sanitize (c, base));
1540   }
1541 
1542   protected:
1543   LOffsetTo<ConditionSet>
1544 			conditions;
1545   LOffsetTo<FeatureTableSubstitution>
1546 			substitutions;
1547   public:
1548   DEFINE_SIZE_STATIC (8);
1549 };
1550 
1551 struct FeatureVariations
1552 {
1553   static const unsigned int NOT_FOUND_INDEX = 0xFFFFFFFFu;
1554 
find_indexOT::FeatureVariations1555   inline bool find_index (const int *coords, unsigned int coord_len,
1556 			  unsigned int *index) const
1557   {
1558     unsigned int count = varRecords.len;
1559     for (unsigned int i = 0; i < count; i++)
1560     {
1561       const FeatureVariationRecord &record = varRecords.array[i];
1562       if ((this+record.conditions).evaluate (coords, coord_len))
1563       {
1564 	*index = i;
1565 	return true;
1566       }
1567     }
1568     *index = NOT_FOUND_INDEX;
1569     return false;
1570   }
1571 
find_substituteOT::FeatureVariations1572   inline const Feature *find_substitute (unsigned int variations_index,
1573 					 unsigned int feature_index) const
1574   {
1575     const FeatureVariationRecord &record = varRecords[variations_index];
1576     return (this+record.substitutions).find_substitute (feature_index);
1577   }
1578 
sanitizeOT::FeatureVariations1579   inline bool sanitize (hb_sanitize_context_t *c) const
1580   {
1581     TRACE_SANITIZE (this);
1582     return_trace (version.sanitize (c) &&
1583 		  likely (version.major == 1) &&
1584 		  varRecords.sanitize (c, this));
1585   }
1586 
1587   protected:
1588   FixedVersion<>	version;	/* Version--0x00010000u */
1589   LArrayOf<FeatureVariationRecord>
1590 			varRecords;
1591   public:
1592   DEFINE_SIZE_ARRAY (8, varRecords);
1593 };
1594 
1595 
1596 /*
1597  * Device Tables
1598  */
1599 
1600 struct HintingDevice
1601 {
1602   friend struct Device;
1603 
1604   private:
1605 
get_x_deltaOT::HintingDevice1606   inline hb_position_t get_x_delta (hb_font_t *font) const
1607   { return get_delta (font->x_ppem, font->x_scale); }
1608 
get_y_deltaOT::HintingDevice1609   inline hb_position_t get_y_delta (hb_font_t *font) const
1610   { return get_delta (font->y_ppem, font->y_scale); }
1611 
get_sizeOT::HintingDevice1612   inline unsigned int get_size (void) const
1613   {
1614     unsigned int f = deltaFormat;
1615     if (unlikely (f < 1 || f > 3 || startSize > endSize)) return 3 * UINT16::static_size;
1616     return UINT16::static_size * (4 + ((endSize - startSize) >> (4 - f)));
1617   }
1618 
sanitizeOT::HintingDevice1619   inline bool sanitize (hb_sanitize_context_t *c) const
1620   {
1621     TRACE_SANITIZE (this);
1622     return_trace (c->check_struct (this) && c->check_range (this, this->get_size ()));
1623   }
1624 
1625   private:
1626 
get_deltaOT::HintingDevice1627   inline int get_delta (unsigned int ppem, int scale) const
1628   {
1629     if (!ppem) return 0;
1630 
1631     int pixels = get_delta_pixels (ppem);
1632 
1633     if (!pixels) return 0;
1634 
1635     return (int) (pixels * (int64_t) scale / ppem);
1636   }
get_delta_pixelsOT::HintingDevice1637   inline int get_delta_pixels (unsigned int ppem_size) const
1638   {
1639     unsigned int f = deltaFormat;
1640     if (unlikely (f < 1 || f > 3))
1641       return 0;
1642 
1643     if (ppem_size < startSize || ppem_size > endSize)
1644       return 0;
1645 
1646     unsigned int s = ppem_size - startSize;
1647 
1648     unsigned int byte = deltaValue[s >> (4 - f)];
1649     unsigned int bits = (byte >> (16 - (((s & ((1 << (4 - f)) - 1)) + 1) << f)));
1650     unsigned int mask = (0xFFFFu >> (16 - (1 << f)));
1651 
1652     int delta = bits & mask;
1653 
1654     if ((unsigned int) delta >= ((mask + 1) >> 1))
1655       delta -= mask + 1;
1656 
1657     return delta;
1658   }
1659 
1660   protected:
1661   UINT16	startSize;		/* Smallest size to correct--in ppem */
1662   UINT16	endSize;		/* Largest size to correct--in ppem */
1663   UINT16	deltaFormat;		/* Format of DeltaValue array data: 1, 2, or 3
1664 					 * 1	Signed 2-bit value, 8 values per uint16
1665 					 * 2	Signed 4-bit value, 4 values per uint16
1666 					 * 3	Signed 8-bit value, 2 values per uint16
1667 					 */
1668   UINT16	deltaValue[VAR];	/* Array of compressed data */
1669   public:
1670   DEFINE_SIZE_ARRAY (6, deltaValue);
1671 };
1672 
1673 struct VariationDevice
1674 {
1675   friend struct Device;
1676 
1677   private:
1678 
get_x_deltaOT::VariationDevice1679   inline hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store) const
1680   { return font->em_scalef_x (get_delta (font, store)); }
1681 
get_y_deltaOT::VariationDevice1682   inline hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store) const
1683   { return font->em_scalef_y (get_delta (font, store)); }
1684 
sanitizeOT::VariationDevice1685   inline bool sanitize (hb_sanitize_context_t *c) const
1686   {
1687     TRACE_SANITIZE (this);
1688     return_trace (c->check_struct (this));
1689   }
1690 
1691   private:
1692 
get_deltaOT::VariationDevice1693   inline float get_delta (hb_font_t *font, const VariationStore &store) const
1694   {
1695     return store.get_delta (outerIndex, innerIndex, font->coords, font->num_coords);
1696   }
1697 
1698   protected:
1699   UINT16	outerIndex;
1700   UINT16	innerIndex;
1701   UINT16	deltaFormat;	/* Format identifier for this table: 0x0x8000 */
1702   public:
1703   DEFINE_SIZE_STATIC (6);
1704 };
1705 
1706 struct DeviceHeader
1707 {
1708   protected:
1709   UINT16		reserved1;
1710   UINT16		reserved2;
1711   public:
1712   UINT16		format;		/* Format identifier */
1713   public:
1714   DEFINE_SIZE_STATIC (6);
1715 };
1716 
1717 struct Device
1718 {
get_x_deltaOT::Device1719   inline hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store=Null(VariationStore)) const
1720   {
1721     switch (u.b.format)
1722     {
1723     case 1: case 2: case 3:
1724       return u.hinting.get_x_delta (font);
1725     case 0x8000:
1726       return u.variation.get_x_delta (font, store);
1727     default:
1728       return 0;
1729     }
1730   }
get_y_deltaOT::Device1731   inline hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store=Null(VariationStore)) const
1732   {
1733     switch (u.b.format)
1734     {
1735     case 1: case 2: case 3:
1736       return u.hinting.get_y_delta (font);
1737     case 0x8000:
1738       return u.variation.get_y_delta (font, store);
1739     default:
1740       return 0;
1741     }
1742   }
1743 
sanitizeOT::Device1744   inline bool sanitize (hb_sanitize_context_t *c) const
1745   {
1746     TRACE_SANITIZE (this);
1747     if (!u.b.format.sanitize (c)) return_trace (false);
1748     switch (u.b.format) {
1749     case 1: case 2: case 3:
1750       return_trace (u.hinting.sanitize (c));
1751     case 0x8000:
1752       return_trace (u.variation.sanitize (c));
1753     default:
1754       return_trace (true);
1755     }
1756   }
1757 
1758   protected:
1759   union {
1760   DeviceHeader		b;
1761   HintingDevice		hinting;
1762   VariationDevice	variation;
1763   } u;
1764   public:
1765   DEFINE_SIZE_UNION (6, b);
1766 };
1767 
1768 
1769 } /* namespace OT */
1770 
1771 
1772 #endif /* HB_OT_LAYOUT_COMMON_PRIVATE_HH */
1773