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
47namespace 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
65template <typename Type>
66struct Record
67{
68  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  };
76  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
91template <typename Type>
92struct RecordArrayOf : SortedArrayOf<Record<Type> > {
93  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  }
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
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  }
113  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
127template <typename Type>
128struct RecordListOf : RecordArrayOf<Type>
129{
130  inline const Type& operator [] (unsigned int i) const
131  { return this+RecordArrayOf<Type>::operator [](i).offset; }
132
133  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
141struct RangeRecord
142{
143  inline int cmp (hb_codepoint_t g) const {
144    return g < start ? -1 : g <= end ? 0 : +1 ;
145  }
146
147  inline bool sanitize (hb_sanitize_context_t *c) const
148  {
149    TRACE_SANITIZE (this);
150    return_trace (c->check_struct (this));
151  }
152
153  inline bool intersects (const hb_set_t *glyphs) const {
154    return glyphs->intersects (start, end);
155  }
156
157  template <typename set_t>
158  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};
168DEFINE_NULL_DATA (RangeRecord, "\000\001");
169
170
171struct IndexArray : ArrayOf<Index>
172{
173  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
188struct Script;
189struct LangSys;
190struct Feature;
191
192
193struct LangSys
194{
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); }
203
204  inline bool has_required_feature (void) const { return reqFeatureIndex != 0xFFFFu; }
205  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
212  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};
228DEFINE_NULL_DATA (LangSys, "\0\0\xFF\xFF");
229
230
231struct Script
232{
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
242  {
243    if (i == Index::NOT_FOUND_INDEX) return get_default_lang_sys ();
244    return this+langSys[i].offset;
245  }
246  inline bool find_lang_sys_index (hb_tag_t tag, unsigned int *index) const
247  { return langSys.find_index (tag, index); }
248
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; }
251
252  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
270typedef RecordListOf<Script> ScriptList;
271
272
273/* http://www.microsoft.com/typography/otspec/features_pt.htm#size */
274struct FeatureParamsSize
275{
276  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 */
386struct FeatureParamsStylisticSet
387{
388  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 */
420struct FeatureParamsCharacterVariants
421{
422  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
461struct FeatureParams
462{
463  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
475  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
491struct Feature
492{
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); }
501
502  inline const FeatureParams &get_feature_params (void) const
503  { return this+featureParams; }
504
505  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
562typedef RecordListOf<Feature> FeatureList;
563
564
565struct 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. */
583HB_MARK_AS_FLAG_T (OT::LookupFlag::Flags);
584namespace OT {
585
586struct Lookup
587{
588  inline unsigned int get_subtable_count (void) const { return subTable.len; }
589
590  template <typename SubTableType>
591  inline const SubTableType& get_subtable (unsigned int i) const
592  { return this+CastR<OffsetArrayOf<SubTableType> > (subTable)[i]; }
593
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); }
600
601  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. */
606  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>
618  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
631  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
649  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
674typedef OffsetListOf<Lookup> LookupList;
675
676
677/*
678 * Coverage Table
679 */
680
681struct CoverageFormat1
682{
683  friend struct Coverage;
684
685  private:
686  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
693  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
707  inline bool sanitize (hb_sanitize_context_t *c) const
708  {
709    TRACE_SANITIZE (this);
710    return_trace (glyphArray.sanitize (c));
711  }
712
713  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>
718  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 {
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; }
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
745struct CoverageFormat2
746{
747  friend struct Coverage;
748
749  private:
750  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
760  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
796  inline bool sanitize (hb_sanitize_context_t *c) const
797  {
798    TRACE_SANITIZE (this);
799    return_trace (rangeRecord.sanitize (c));
800  }
801
802  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>
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)))
822        return false;
823    return true;
824  }
825
826  public:
827  /* Older compilers need this to be public. */
828  struct Iter
829  {
830    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    }
837    inline bool more (void) { return i < c->rangeRecord.len; }
838    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    }
853    inline hb_codepoint_t get_glyph (void) { return j; }
854    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
872struct Coverage
873{
874  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
883  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
901  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
912  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
922  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>
933  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 {
942    Iter (void) : format (0), u () {};
943    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    }
951    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    }
958    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    }
965    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    }
972    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
1003struct ClassDefFormat1
1004{
1005  friend struct ClassDef;
1006
1007  private:
1008  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
1016  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>
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++)
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>
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++)
1048    {
1049      if (classValue[i] == klass)
1050        glyphs->add (startGlyph + i);
1051    }
1052    return true;
1053  }
1054
1055  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
1085struct ClassDefFormat2
1086{
1087  friend struct ClassDef;
1088
1089  private:
1090  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
1098  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>
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)))
1110	  return false;
1111    return true;
1112  }
1113
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++)
1118    {
1119      if (rangeRecord[i].value == klass)
1120        if (unlikely (!rangeRecord[i].add_coverage (glyphs)))
1121	  return false;
1122    }
1123    return true;
1124  }
1125
1126  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
1159struct ClassDef
1160{
1161  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
1170  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>
1184  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>
1195  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
1203  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
1226struct VarRegionAxis
1227{
1228  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
1251  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
1267struct VarRegionList
1268{
1269  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
1289  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
1305struct VarData
1306{
1307  inline unsigned int get_row_size (void) const
1308  { return shortCount + regionIndices.len; }
1309
1310  inline unsigned int get_size (void) const
1311  { return itemCount * get_row_size (); }
1312
1313  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
1345  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
1364struct VariationStore
1365{
1366  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
1377  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
1385  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
1406struct ConditionFormat1
1407{
1408  friend struct Condition;
1409
1410  private:
1411  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
1417  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
1432struct Condition
1433{
1434  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
1442  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
1461struct ConditionSet
1462{
1463  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
1472  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
1484struct FeatureTableSubstitutionRecord
1485{
1486  friend struct FeatureTableSubstitution;
1487
1488  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
1501struct FeatureTableSubstitution
1502{
1503  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
1515  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
1531struct FeatureVariationRecord
1532{
1533  friend struct FeatureVariations;
1534
1535  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
1551struct FeatureVariations
1552{
1553  static const unsigned int NOT_FOUND_INDEX = 0xFFFFFFFFu;
1554
1555  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
1572  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
1579  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
1600struct HintingDevice
1601{
1602  friend struct Device;
1603
1604  private:
1605
1606  inline hb_position_t get_x_delta (hb_font_t *font) const
1607  { return get_delta (font->x_ppem, font->x_scale); }
1608
1609  inline hb_position_t get_y_delta (hb_font_t *font) const
1610  { return get_delta (font->y_ppem, font->y_scale); }
1611
1612  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
1619  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
1627  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  }
1637  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
1673struct VariationDevice
1674{
1675  friend struct Device;
1676
1677  private:
1678
1679  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
1682  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
1685  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
1693  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
1706struct 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
1717struct Device
1718{
1719  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  }
1731  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
1744  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