• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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-ot-layout-private.hh"
33 #include "hb-open-type-private.hh"
34 #include "hb-set-private.hh"
35 
36 
37 namespace OT {
38 
39 
40 #define NOT_COVERED		((unsigned int) -1)
41 #define MAX_NESTING_LEVEL	8
42 
43 
44 
45 /*
46  *
47  * OpenType Layout Common Table Formats
48  *
49  */
50 
51 
52 /*
53  * Script, ScriptList, LangSys, Feature, FeatureList, Lookup, LookupList
54  */
55 
56 template <typename Type>
57 struct Record
58 {
cmpOT::Record59   inline int cmp (hb_tag_t a) const {
60     return tag.cmp (a);
61   }
62 
63   struct sanitize_closure_t {
64     hb_tag_t tag;
65     void *list_base;
66   };
sanitizeOT::Record67   inline bool sanitize (hb_sanitize_context_t *c, void *base) {
68     TRACE_SANITIZE (this);
69     const sanitize_closure_t closure = {tag, base};
70     return TRACE_RETURN (c->check_struct (this) && offset.sanitize (c, base, &closure));
71   }
72 
73   Tag		tag;		/* 4-byte Tag identifier */
74   OffsetTo<Type>
75 		offset;		/* Offset from beginning of object holding
76 				 * the Record */
77   public:
78   DEFINE_SIZE_STATIC (6);
79 };
80 
81 template <typename Type>
82 struct RecordArrayOf : SortedArrayOf<Record<Type> > {
get_tagOT::RecordArrayOf83   inline const Tag& get_tag (unsigned int i) const
84   {
85     /* We cheat slightly and don't define separate Null objects
86      * for Record types.  Instead, we return the correct Null(Tag)
87      * here. */
88     if (unlikely (i >= this->len)) return Null(Tag);
89     return (*this)[i].tag;
90   }
get_tagsOT::RecordArrayOf91   inline unsigned int get_tags (unsigned int start_offset,
92 				unsigned int *record_count /* IN/OUT */,
93 				hb_tag_t     *record_tags /* OUT */) const
94   {
95     if (record_count) {
96       const Record<Type> *arr = this->sub_array (start_offset, record_count);
97       unsigned int count = *record_count;
98       for (unsigned int i = 0; i < count; i++)
99 	record_tags[i] = arr[i].tag;
100     }
101     return this->len;
102   }
find_indexOT::RecordArrayOf103   inline bool find_index (hb_tag_t tag, unsigned int *index) const
104   {
105     int i = this->search (tag);
106     if (i != -1) {
107         if (index) *index = i;
108         return true;
109     } else {
110       if (index) *index = Index::NOT_FOUND_INDEX;
111       return false;
112     }
113   }
114 };
115 
116 template <typename Type>
117 struct RecordListOf : RecordArrayOf<Type>
118 {
operator []OT::RecordListOf119   inline const Type& operator [] (unsigned int i) const
120   { return this+RecordArrayOf<Type>::operator [](i).offset; }
121 
sanitizeOT::RecordListOf122   inline bool sanitize (hb_sanitize_context_t *c) {
123     TRACE_SANITIZE (this);
124     return TRACE_RETURN (RecordArrayOf<Type>::sanitize (c, this));
125   }
126 };
127 
128 
129 struct RangeRecord
130 {
cmpOT::RangeRecord131   inline int cmp (hb_codepoint_t g) const {
132     hb_codepoint_t a = start, b = end;
133     return g < a ? -1 : g <= b ? 0 : +1 ;
134   }
135 
sanitizeOT::RangeRecord136   inline bool sanitize (hb_sanitize_context_t *c) {
137     TRACE_SANITIZE (this);
138     return TRACE_RETURN (c->check_struct (this));
139   }
140 
intersectsOT::RangeRecord141   inline bool intersects (const hb_set_t *glyphs) const {
142     return glyphs->intersects (start, end);
143   }
144 
145   template <typename set_t>
add_coverageOT::RangeRecord146   inline void add_coverage (set_t *glyphs) const {
147     glyphs->add_range (start, end);
148   }
149 
150   GlyphID	start;		/* First GlyphID in the range */
151   GlyphID	end;		/* Last GlyphID in the range */
152   USHORT	value;		/* Value */
153   public:
154   DEFINE_SIZE_STATIC (6);
155 };
156 DEFINE_NULL_DATA (RangeRecord, "\000\001");
157 
158 
159 struct IndexArray : ArrayOf<Index>
160 {
get_indexesOT::IndexArray161   inline unsigned int get_indexes (unsigned int start_offset,
162 				   unsigned int *_count /* IN/OUT */,
163 				   unsigned int *_indexes /* OUT */) const
164   {
165     if (_count) {
166       const USHORT *arr = this->sub_array (start_offset, _count);
167       unsigned int count = *_count;
168       for (unsigned int i = 0; i < count; i++)
169 	_indexes[i] = arr[i];
170     }
171     return this->len;
172   }
173 };
174 
175 
176 struct Script;
177 struct LangSys;
178 struct Feature;
179 
180 
181 struct LangSys
182 {
get_feature_countOT::LangSys183   inline unsigned int get_feature_count (void) const
184   { return featureIndex.len; }
get_feature_indexOT::LangSys185   inline hb_tag_t get_feature_index (unsigned int i) const
186   { return featureIndex[i]; }
get_feature_indexesOT::LangSys187   inline unsigned int get_feature_indexes (unsigned int start_offset,
188 					   unsigned int *feature_count /* IN/OUT */,
189 					   unsigned int *feature_indexes /* OUT */) const
190   { return featureIndex.get_indexes (start_offset, feature_count, feature_indexes); }
191 
has_required_featureOT::LangSys192   inline bool has_required_feature (void) const { return reqFeatureIndex != 0xffff; }
get_required_feature_indexOT::LangSys193   inline unsigned int get_required_feature_index (void) const
194   {
195     if (reqFeatureIndex == 0xffff)
196       return Index::NOT_FOUND_INDEX;
197    return reqFeatureIndex;;
198   }
199 
sanitizeOT::LangSys200   inline bool sanitize (hb_sanitize_context_t *c,
201 			const Record<LangSys>::sanitize_closure_t * = NULL) {
202     TRACE_SANITIZE (this);
203     return TRACE_RETURN (c->check_struct (this) && featureIndex.sanitize (c));
204   }
205 
206   Offset	lookupOrder;	/* = Null (reserved for an offset to a
207 				 * reordering table) */
208   USHORT	reqFeatureIndex;/* Index of a feature required for this
209 				 * language system--if no required features
210 				 * = 0xFFFF */
211   IndexArray	featureIndex;	/* Array of indices into the FeatureList */
212   public:
213   DEFINE_SIZE_ARRAY (6, featureIndex);
214 };
215 DEFINE_NULL_DATA (LangSys, "\0\0\xFF\xFF");
216 
217 
218 struct Script
219 {
get_lang_sys_countOT::Script220   inline unsigned int get_lang_sys_count (void) const
221   { return langSys.len; }
get_lang_sys_tagOT::Script222   inline const Tag& get_lang_sys_tag (unsigned int i) const
223   { return langSys.get_tag (i); }
get_lang_sys_tagsOT::Script224   inline unsigned int get_lang_sys_tags (unsigned int start_offset,
225 					 unsigned int *lang_sys_count /* IN/OUT */,
226 					 hb_tag_t     *lang_sys_tags /* OUT */) const
227   { return langSys.get_tags (start_offset, lang_sys_count, lang_sys_tags); }
get_lang_sysOT::Script228   inline const LangSys& get_lang_sys (unsigned int i) const
229   {
230     if (i == Index::NOT_FOUND_INDEX) return get_default_lang_sys ();
231     return this+langSys[i].offset;
232   }
find_lang_sys_indexOT::Script233   inline bool find_lang_sys_index (hb_tag_t tag, unsigned int *index) const
234   { return langSys.find_index (tag, index); }
235 
has_default_lang_sysOT::Script236   inline bool has_default_lang_sys (void) const { return defaultLangSys != 0; }
get_default_lang_sysOT::Script237   inline const LangSys& get_default_lang_sys (void) const { return this+defaultLangSys; }
238 
sanitizeOT::Script239   inline bool sanitize (hb_sanitize_context_t *c,
240 			const Record<Script>::sanitize_closure_t * = NULL) {
241     TRACE_SANITIZE (this);
242     return TRACE_RETURN (defaultLangSys.sanitize (c, this) && langSys.sanitize (c, this));
243   }
244 
245   protected:
246   OffsetTo<LangSys>
247 		defaultLangSys;	/* Offset to DefaultLangSys table--from
248 				 * beginning of Script table--may be Null */
249   RecordArrayOf<LangSys>
250 		langSys;	/* Array of LangSysRecords--listed
251 				 * alphabetically by LangSysTag */
252   public:
253   DEFINE_SIZE_ARRAY (4, langSys);
254 };
255 
256 typedef RecordListOf<Script> ScriptList;
257 
258 
259 /* http://www.microsoft.com/typography/otspec/features_pt.htm#size */
260 struct FeatureParamsSize
261 {
sanitizeOT::FeatureParamsSize262   inline bool sanitize (hb_sanitize_context_t *c) {
263     TRACE_SANITIZE (this);
264     if (unlikely (!c->check_struct (this))) return TRACE_RETURN (false);
265 
266     /* This subtable has some "history", if you will.  Some earlier versions of
267      * Adobe tools calculated the offset of the FeatureParams sutable from the
268      * beginning of the FeatureList table!  Now, that is dealt with in the
269      * Feature implementation.  But we still need to be able to tell junk from
270      * real data.  Note: We don't check that the nameID actually exists.
271      *
272      * Read Roberts wrote on 9/15/06 on opentype-list@indx.co.uk :
273      *
274      * Yes, it is correct that a new version of the AFDKO (version 2.0) will be
275      * coming out soon, and that the makeotf program will build a font with a
276      * 'size' feature that is correct by the specification.
277      *
278      * The specification for this feature tag is in the "OpenType Layout Tag
279      * Registry". You can see a copy of this at:
280      * http://partners.adobe.com/public/developer/opentype/index_tag8.html#size
281      *
282      * Here is one set of rules to determine if the 'size' feature is built
283      * correctly, or as by the older versions of MakeOTF. You may be able to do
284      * better.
285      *
286      * Assume that the offset to the size feature is according to specification,
287      * and make the following value checks. If it fails, assume the the size
288      * feature is calculated as versions of MakeOTF before the AFDKO 2.0 built it.
289      * If this fails, reject the 'size' feature. The older makeOTF's calculated the
290      * offset from the beginning of the FeatureList table, rather than from the
291      * beginning of the 'size' Feature table.
292      *
293      * If "design size" == 0:
294      *     fails check
295      *
296      * Else if ("subfamily identifier" == 0 and
297      *     "range start" == 0 and
298      *     "range end" == 0 and
299      *     "range start" == 0 and
300      *     "menu name ID" == 0)
301      *     passes check: this is the format used when there is a design size
302      * specified, but there is no recommended size range.
303      *
304      * Else if ("design size" <  "range start" or
305      *     "design size" >   "range end" or
306      *     "range end" <= "range start" or
307      *     "menu name ID"  < 256 or
308      *     "menu name ID"  > 32767 or
309      *     menu name ID is not a name ID which is actually in the name table)
310      *     fails test
311      * Else
312      *     passes test.
313      */
314 
315     if (!designSize)
316       return TRACE_RETURN (false);
317     else if (subfamilyID == 0 &&
318 	     subfamilyNameID == 0 &&
319 	     rangeStart == 0 &&
320 	     rangeEnd == 0)
321       return TRACE_RETURN (true);
322     else if (designSize < rangeStart ||
323 	     designSize > rangeEnd ||
324 	     subfamilyNameID < 256 ||
325 	     subfamilyNameID > 32767)
326       return TRACE_RETURN (false);
327     else
328       return TRACE_RETURN (true);
329   }
330 
331   USHORT	designSize;	/* Represents the design size in 720/inch
332 				 * units (decipoints).  The design size entry
333 				 * must be non-zero.  When there is a design
334 				 * size but no recommended size range, the
335 				 * rest of the array will consist of zeros. */
336   USHORT	subfamilyID;	/* Has no independent meaning, but serves
337 				 * as an identifier that associates fonts
338 				 * in a subfamily. All fonts which share a
339 				 * Preferred or Font Family name and which
340 				 * differ only by size range shall have the
341 				 * same subfamily value, and no fonts which
342 				 * differ in weight or style shall have the
343 				 * same subfamily value. If this value is
344 				 * zero, the remaining fields in the array
345 				 * will be ignored. */
346   USHORT	subfamilyNameID;/* If the preceding value is non-zero, this
347 				 * value must be set in the range 256 - 32767
348 				 * (inclusive). It records the value of a
349 				 * field in the name table, which must
350 				 * contain English-language strings encoded
351 				 * in Windows Unicode and Macintosh Roman,
352 				 * and may contain additional strings
353 				 * localized to other scripts and languages.
354 				 * Each of these strings is the name an
355 				 * application should use, in combination
356 				 * with the family name, to represent the
357 				 * subfamily in a menu.  Applications will
358 				 * choose the appropriate version based on
359 				 * their selection criteria. */
360   USHORT	rangeStart;	/* Large end of the recommended usage range
361 				 * (inclusive), stored in 720/inch units
362 				 * (decipoints). */
363   USHORT	rangeEnd;	/* Small end of the recommended usage range
364 				   (exclusive), stored in 720/inch units
365 				 * (decipoints). */
366   public:
367   DEFINE_SIZE_STATIC (10);
368 };
369 
370 /* http://www.microsoft.com/typography/otspec/features_pt.htm#ssxx */
371 struct FeatureParamsStylisticSet
372 {
sanitizeOT::FeatureParamsStylisticSet373   inline bool sanitize (hb_sanitize_context_t *c) {
374     TRACE_SANITIZE (this);
375     /* Right now minorVersion is at zero.  Which means, any table supports
376      * the uiNameID field. */
377     return TRACE_RETURN (c->check_struct (this));
378   }
379 
380   USHORT	minorVersion;	/* (set to 0): This corresponds to a “minor”
381 				 * version number. Additional data may be
382 				 * added to the end of this Feature Parameters
383 				 * table in the future. */
384 
385   USHORT	uiNameID;	/* The 'name' table name ID that specifies a
386 				 * string (or strings, for multiple languages)
387 				 * for a user-interface label for this
388 				 * feature.  The values of uiLabelNameId and
389 				 * sampleTextNameId are expected to be in the
390 				 * font-specific name ID range (256-32767),
391 				 * though that is not a requirement in this
392 				 * Feature Parameters specification. The
393 				 * user-interface label for the feature can
394 				 * be provided in multiple languages. An
395 				 * English string should be included as a
396 				 * fallback. The string should be kept to a
397 				 * minimal length to fit comfortably with
398 				 * different application interfaces. */
399   public:
400   DEFINE_SIZE_STATIC (4);
401 };
402 
403 struct FeatureParamsCharacterVariants
404 {
sanitizeOT::FeatureParamsCharacterVariants405   inline bool sanitize (hb_sanitize_context_t *c) {
406     TRACE_SANITIZE (this);
407     return TRACE_RETURN (c->check_struct (this) &&
408 			 characters.sanitize (c));
409   }
410 
411   USHORT	format;			/* Format number is set to 0. */
412   USHORT	featUILableNameID;	/* The ‘name’ table name ID that
413 					 * specifies a string (or strings,
414 					 * for multiple languages) for a
415 					 * user-interface label for this
416 					 * feature. (May be NULL.) */
417   USHORT	featUITooltipTextNameID;/* The ‘name’ table name ID that
418 					 * specifies a string (or strings,
419 					 * for multiple languages) that an
420 					 * application can use for tooltip
421 					 * text for this feature. (May be
422 					 * NULL.) */
423   USHORT	sampleTextNameID;	/* The ‘name’ table name ID that
424 					 * specifies sample text that
425 					 * illustrates the effect of this
426 					 * feature. (May be NULL.) */
427   USHORT	numNamedParameters;	/* Number of named parameters. (May
428 					 * be zero.) */
429   USHORT	firstParamUILabelNameID;/* The first ‘name’ table name ID
430 					 * used to specify strings for
431 					 * user-interface labels for the
432 					 * feature parameters. (Must be zero
433 					 * if numParameters is zero.) */
434   ArrayOf<UINT24>
435 		characters;		/* Array of the Unicode Scalar Value
436 					 * of the characters for which this
437 					 * feature provides glyph variants.
438 					 * (May be zero.) */
439   public:
440   DEFINE_SIZE_ARRAY (14, characters);
441 };
442 
443 struct FeatureParams
444 {
sanitizeOT::FeatureParams445   inline bool sanitize (hb_sanitize_context_t *c, hb_tag_t tag) {
446     TRACE_SANITIZE (this);
447     if (tag == HB_TAG ('s','i','z','e'))
448       return TRACE_RETURN (u.size.sanitize (c));
449     if ((tag & 0xFFFF0000) == HB_TAG ('s','s','\0','\0')) /* ssXX */
450       return TRACE_RETURN (u.stylisticSet.sanitize (c));
451     if ((tag & 0xFFFF0000) == HB_TAG ('c','v','\0','\0')) /* cvXX */
452       return TRACE_RETURN (u.characterVariants.sanitize (c));
453     return TRACE_RETURN (true);
454   }
455 
get_size_paramsOT::FeatureParams456   inline const FeatureParamsSize& get_size_params (hb_tag_t tag) const
457   {
458     if (tag == HB_TAG ('s','i','z','e'))
459       return u.size;
460     return Null(FeatureParamsSize);
461   }
462 
463   private:
464   union {
465   FeatureParamsSize			size;
466   FeatureParamsStylisticSet		stylisticSet;
467   FeatureParamsCharacterVariants	characterVariants;
468   } u;
469   DEFINE_SIZE_STATIC (17);
470 };
471 
472 struct Feature
473 {
get_lookup_countOT::Feature474   inline unsigned int get_lookup_count (void) const
475   { return lookupIndex.len; }
get_lookup_indexOT::Feature476   inline hb_tag_t get_lookup_index (unsigned int i) const
477   { return lookupIndex[i]; }
get_lookup_indexesOT::Feature478   inline unsigned int get_lookup_indexes (unsigned int start_index,
479 					  unsigned int *lookup_count /* IN/OUT */,
480 					  unsigned int *lookup_tags /* OUT */) const
481   { return lookupIndex.get_indexes (start_index, lookup_count, lookup_tags); }
482 
get_feature_paramsOT::Feature483   inline const FeatureParams &get_feature_params (void) const
484   { return this+featureParams; }
485 
sanitizeOT::Feature486   inline bool sanitize (hb_sanitize_context_t *c,
487 			const Record<Feature>::sanitize_closure_t *closure) {
488     TRACE_SANITIZE (this);
489     if (unlikely (!(c->check_struct (this) && lookupIndex.sanitize (c))))
490       return TRACE_RETURN (false);
491 
492     /* Some earlier versions of Adobe tools calculated the offset of the
493      * FeatureParams subtable from the beginning of the FeatureList table!
494      *
495      * If sanitizing "failed" for the FeatureParams subtable, try it with the
496      * alternative location.  We would know sanitize "failed" if old value
497      * of the offset was non-zero, but it's zeroed now.
498      *
499      * Only do this for the 'size' feature, since at the time of the faulty
500      * Adobe tools, only the 'size' feature had FeatureParams defined.
501      */
502 
503     Offset orig_offset = featureParams;
504     if (unlikely (!featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE)))
505       return TRACE_RETURN (false);
506 
507     if (likely (!orig_offset))
508       return TRACE_RETURN (true);
509 
510     if (featureParams == 0 && closure &&
511 	closure->tag == HB_TAG ('s','i','z','e') &&
512 	closure->list_base && closure->list_base < this)
513     {
514       unsigned int new_offset_int = (unsigned int) orig_offset -
515 				    ((char *) this - (char *) closure->list_base);
516 
517       Offset new_offset;
518       /* Check that it did not overflow. */
519       new_offset.set (new_offset_int);
520       if (new_offset == new_offset_int &&
521 	  featureParams.try_set (c, new_offset) &&
522 	  !featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE))
523 	return TRACE_RETURN (false);
524     }
525 
526     return TRACE_RETURN (true);
527   }
528 
529   OffsetTo<FeatureParams>
530 		 featureParams;	/* Offset to Feature Parameters table (if one
531 				 * has been defined for the feature), relative
532 				 * to the beginning of the Feature Table; = Null
533 				 * if not required */
534   IndexArray	 lookupIndex;	/* Array of LookupList indices */
535   public:
536   DEFINE_SIZE_ARRAY (4, lookupIndex);
537 };
538 
539 typedef RecordListOf<Feature> FeatureList;
540 
541 
542 struct LookupFlag : USHORT
543 {
544   enum Flags {
545     RightToLeft		= 0x0001u,
546     IgnoreBaseGlyphs	= 0x0002u,
547     IgnoreLigatures	= 0x0004u,
548     IgnoreMarks		= 0x0008u,
549     IgnoreFlags		= 0x000Eu,
550     UseMarkFilteringSet	= 0x0010u,
551     Reserved		= 0x00E0u,
552     MarkAttachmentType	= 0xFF00u
553   };
554   public:
555   DEFINE_SIZE_STATIC (2);
556 };
557 
558 struct Lookup
559 {
get_subtable_countOT::Lookup560   inline unsigned int get_subtable_count (void) const { return subTable.len; }
561 
get_typeOT::Lookup562   inline unsigned int get_type (void) const { return lookupType; }
563 
564   /* lookup_props is a 32-bit integer where the lower 16-bit is LookupFlag and
565    * higher 16-bit is mark-filtering-set if the lookup uses one.
566    * Not to be confused with glyph_props which is very similar. */
get_propsOT::Lookup567   inline uint32_t get_props (void) const
568   {
569     unsigned int flag = lookupFlag;
570     if (unlikely (flag & LookupFlag::UseMarkFilteringSet))
571     {
572       const USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
573       flag += (markFilteringSet << 16);
574     }
575     return flag;
576   }
577 
serializeOT::Lookup578   inline bool serialize (hb_serialize_context_t *c,
579 			 unsigned int lookup_type,
580 			 uint32_t lookup_props,
581 			 unsigned int num_subtables)
582   {
583     TRACE_SERIALIZE (this);
584     if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
585     lookupType.set (lookup_type);
586     lookupFlag.set (lookup_props & 0xFFFF);
587     if (unlikely (!subTable.serialize (c, num_subtables))) return TRACE_RETURN (false);
588     if (lookupFlag & LookupFlag::UseMarkFilteringSet)
589     {
590       USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
591       markFilteringSet.set (lookup_props >> 16);
592     }
593     return TRACE_RETURN (true);
594   }
595 
sanitizeOT::Lookup596   inline bool sanitize (hb_sanitize_context_t *c) {
597     TRACE_SANITIZE (this);
598     /* Real sanitize of the subtables is done by GSUB/GPOS/... */
599     if (!(c->check_struct (this) && subTable.sanitize (c))) return TRACE_RETURN (false);
600     if (lookupFlag & LookupFlag::UseMarkFilteringSet)
601     {
602       USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
603       if (!markFilteringSet.sanitize (c)) return TRACE_RETURN (false);
604     }
605     return TRACE_RETURN (true);
606   }
607 
608   USHORT	lookupType;		/* Different enumerations for GSUB and GPOS */
609   USHORT	lookupFlag;		/* Lookup qualifiers */
610   ArrayOf<Offset>
611 		subTable;		/* Array of SubTables */
612   USHORT	markFilteringSetX[VAR];	/* Index (base 0) into GDEF mark glyph sets
613 					 * structure. This field is only present if bit
614 					 * UseMarkFilteringSet of lookup flags is set. */
615   public:
616   DEFINE_SIZE_ARRAY2 (6, subTable, markFilteringSetX);
617 };
618 
619 typedef OffsetListOf<Lookup> LookupList;
620 
621 
622 /*
623  * Coverage Table
624  */
625 
626 struct CoverageFormat1
627 {
628   friend struct Coverage;
629 
630   private:
get_coverageOT::CoverageFormat1631   inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
632   {
633     int i = glyphArray.search (glyph_id);
634     ASSERT_STATIC (((unsigned int) -1) == NOT_COVERED);
635     return i;
636   }
637 
serializeOT::CoverageFormat1638   inline bool serialize (hb_serialize_context_t *c,
639 			 Supplier<GlyphID> &glyphs,
640 			 unsigned int num_glyphs)
641   {
642     TRACE_SERIALIZE (this);
643     if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
644     glyphArray.len.set (num_glyphs);
645     if (unlikely (!c->extend (glyphArray))) return TRACE_RETURN (false);
646     for (unsigned int i = 0; i < num_glyphs; i++)
647       glyphArray[i] = glyphs[i];
648     glyphs.advance (num_glyphs);
649     return TRACE_RETURN (true);
650   }
651 
sanitizeOT::CoverageFormat1652   inline bool sanitize (hb_sanitize_context_t *c) {
653     TRACE_SANITIZE (this);
654     return TRACE_RETURN (glyphArray.sanitize (c));
655   }
656 
intersects_coverageOT::CoverageFormat1657   inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const {
658     return glyphs->has (glyphArray[index]);
659   }
660 
661   template <typename set_t>
add_coverageOT::CoverageFormat1662   inline void add_coverage (set_t *glyphs) const {
663     unsigned int count = glyphArray.len;
664     for (unsigned int i = 0; i < count; i++)
665       glyphs->add (glyphArray[i]);
666   }
667 
668   public:
669   /* Older compilers need this to be public. */
670   struct Iter {
initOT::CoverageFormat1::Iter671     inline void init (const struct CoverageFormat1 &c_) { c = &c_; i = 0; };
moreOT::CoverageFormat1::Iter672     inline bool more (void) { return i < c->glyphArray.len; }
nextOT::CoverageFormat1::Iter673     inline void next (void) { i++; }
get_glyphOT::CoverageFormat1::Iter674     inline uint16_t get_glyph (void) { return c->glyphArray[i]; }
get_coverageOT::CoverageFormat1::Iter675     inline uint16_t get_coverage (void) { return i; }
676 
677     private:
678     const struct CoverageFormat1 *c;
679     unsigned int i;
680   };
681   private:
682 
683   protected:
684   USHORT	coverageFormat;	/* Format identifier--format = 1 */
685   SortedArrayOf<GlyphID>
686 		glyphArray;	/* Array of GlyphIDs--in numerical order */
687   public:
688   DEFINE_SIZE_ARRAY (4, glyphArray);
689 };
690 
691 struct CoverageFormat2
692 {
693   friend struct Coverage;
694 
695   private:
get_coverageOT::CoverageFormat2696   inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
697   {
698     int i = rangeRecord.search (glyph_id);
699     if (i != -1) {
700       const RangeRecord &range = rangeRecord[i];
701       return (unsigned int) range.value + (glyph_id - range.start);
702     }
703     return NOT_COVERED;
704   }
705 
serializeOT::CoverageFormat2706   inline bool serialize (hb_serialize_context_t *c,
707 			 Supplier<GlyphID> &glyphs,
708 			 unsigned int num_glyphs)
709   {
710     TRACE_SERIALIZE (this);
711     if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
712 
713     if (unlikely (!num_glyphs)) return TRACE_RETURN (true);
714 
715     unsigned int num_ranges = 1;
716     for (unsigned int i = 1; i < num_glyphs; i++)
717       if (glyphs[i - 1] + 1 != glyphs[i])
718         num_ranges++;
719     rangeRecord.len.set (num_ranges);
720     if (unlikely (!c->extend (rangeRecord))) return TRACE_RETURN (false);
721 
722     unsigned int range = 0;
723     rangeRecord[range].start = glyphs[0];
724     rangeRecord[range].value.set (0);
725     for (unsigned int i = 1; i < num_glyphs; i++)
726       if (glyphs[i - 1] + 1 != glyphs[i]) {
727 	range++;
728 	rangeRecord[range].start = glyphs[i];
729 	rangeRecord[range].value.set (i);
730         rangeRecord[range].end = glyphs[i];
731       } else {
732         rangeRecord[range].end = glyphs[i];
733       }
734     glyphs.advance (num_glyphs);
735     return TRACE_RETURN (true);
736   }
737 
sanitizeOT::CoverageFormat2738   inline bool sanitize (hb_sanitize_context_t *c) {
739     TRACE_SANITIZE (this);
740     return TRACE_RETURN (rangeRecord.sanitize (c));
741   }
742 
intersects_coverageOT::CoverageFormat2743   inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const {
744     unsigned int i;
745     unsigned int count = rangeRecord.len;
746     for (i = 0; i < count; i++) {
747       const RangeRecord &range = rangeRecord[i];
748       if (range.value <= index &&
749 	  index < (unsigned int) range.value + (range.end - range.start) &&
750 	  range.intersects (glyphs))
751         return true;
752       else if (index < range.value)
753         return false;
754     }
755     return false;
756   }
757 
758   template <typename set_t>
add_coverageOT::CoverageFormat2759   inline void add_coverage (set_t *glyphs) const {
760     unsigned int count = rangeRecord.len;
761     for (unsigned int i = 0; i < count; i++)
762       rangeRecord[i].add_coverage (glyphs);
763   }
764 
765   public:
766   /* Older compilers need this to be public. */
767   struct Iter {
initOT::CoverageFormat2::Iter768     inline void init (const CoverageFormat2 &c_) {
769       c = &c_;
770       coverage = 0;
771       i = 0;
772       j = c->rangeRecord.len ? c_.rangeRecord[0].start : 0;
773     }
moreOT::CoverageFormat2::Iter774     inline bool more (void) { return i < c->rangeRecord.len; }
nextOT::CoverageFormat2::Iter775     inline void next (void) {
776       coverage++;
777       if (j == c->rangeRecord[i].end) {
778         i++;
779 	if (more ())
780 	  j = c->rangeRecord[i].start;
781 	return;
782       }
783       j++;
784     }
get_glyphOT::CoverageFormat2::Iter785     inline uint16_t get_glyph (void) { return j; }
get_coverageOT::CoverageFormat2::Iter786     inline uint16_t get_coverage (void) { return coverage; }
787 
788     private:
789     const struct CoverageFormat2 *c;
790     unsigned int i, j, coverage;
791   };
792   private:
793 
794   protected:
795   USHORT	coverageFormat;	/* Format identifier--format = 2 */
796   SortedArrayOf<RangeRecord>
797 		rangeRecord;	/* Array of glyph ranges--ordered by
798 				 * Start GlyphID. rangeCount entries
799 				 * long */
800   public:
801   DEFINE_SIZE_ARRAY (4, rangeRecord);
802 };
803 
804 struct Coverage
805 {
get_coverageOT::Coverage806   inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
807   {
808     switch (u.format) {
809     case 1: return u.format1.get_coverage(glyph_id);
810     case 2: return u.format2.get_coverage(glyph_id);
811     default:return NOT_COVERED;
812     }
813   }
814 
serializeOT::Coverage815   inline bool serialize (hb_serialize_context_t *c,
816 			 Supplier<GlyphID> &glyphs,
817 			 unsigned int num_glyphs)
818   {
819     TRACE_SERIALIZE (this);
820     if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
821     unsigned int num_ranges = 1;
822     for (unsigned int i = 1; i < num_glyphs; i++)
823       if (glyphs[i - 1] + 1 != glyphs[i])
824         num_ranges++;
825     u.format.set (num_glyphs * 2 < num_ranges * 3 ? 1 : 2);
826     switch (u.format) {
827     case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, num_glyphs));
828     case 2: return TRACE_RETURN (u.format2.serialize (c, glyphs, num_glyphs));
829     default:return TRACE_RETURN (false);
830     }
831   }
832 
sanitizeOT::Coverage833   inline bool sanitize (hb_sanitize_context_t *c) {
834     TRACE_SANITIZE (this);
835     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
836     switch (u.format) {
837     case 1: return TRACE_RETURN (u.format1.sanitize (c));
838     case 2: return TRACE_RETURN (u.format2.sanitize (c));
839     default:return TRACE_RETURN (true);
840     }
841   }
842 
intersectsOT::Coverage843   inline bool intersects (const hb_set_t *glyphs) const {
844     /* TODO speed this up */
845     Coverage::Iter iter;
846     for (iter.init (*this); iter.more (); iter.next ()) {
847       if (glyphs->has (iter.get_glyph ()))
848         return true;
849     }
850     return false;
851   }
852 
intersects_coverageOT::Coverage853   inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const {
854     switch (u.format) {
855     case 1: return u.format1.intersects_coverage (glyphs, index);
856     case 2: return u.format2.intersects_coverage (glyphs, index);
857     default:return false;
858     }
859   }
860 
861   template <typename set_t>
add_coverageOT::Coverage862   inline void add_coverage (set_t *glyphs) const {
863     switch (u.format) {
864     case 1: u.format1.add_coverage (glyphs); break;
865     case 2: u.format2.add_coverage (glyphs); break;
866     default:                                 break;
867     }
868   }
869 
870   struct Iter {
IterOT::Coverage::Iter871     Iter (void) : format (0) {};
initOT::Coverage::Iter872     inline void init (const Coverage &c_) {
873       format = c_.u.format;
874       switch (format) {
875       case 1: return u.format1.init (c_.u.format1);
876       case 2: return u.format2.init (c_.u.format2);
877       default:return;
878       }
879     }
moreOT::Coverage::Iter880     inline bool more (void) {
881       switch (format) {
882       case 1: return u.format1.more ();
883       case 2: return u.format2.more ();
884       default:return true;
885       }
886     }
nextOT::Coverage::Iter887     inline void next (void) {
888       switch (format) {
889       case 1: u.format1.next (); break;
890       case 2: u.format2.next (); break;
891       default:                   break;
892       }
893     }
get_glyphOT::Coverage::Iter894     inline uint16_t get_glyph (void) {
895       switch (format) {
896       case 1: return u.format1.get_glyph ();
897       case 2: return u.format2.get_glyph ();
898       default:return true;
899       }
900     }
get_coverageOT::Coverage::Iter901     inline uint16_t get_coverage (void) {
902       switch (format) {
903       case 1: return u.format1.get_coverage ();
904       case 2: return u.format2.get_coverage ();
905       default:return true;
906       }
907     }
908 
909     private:
910     unsigned int format;
911     union {
912     CoverageFormat1::Iter	format1;
913     CoverageFormat2::Iter	format2;
914     } u;
915   };
916 
917   protected:
918   union {
919   USHORT		format;		/* Format identifier */
920   CoverageFormat1	format1;
921   CoverageFormat2	format2;
922   } u;
923   public:
924   DEFINE_SIZE_UNION (2, format);
925 };
926 
927 
928 /*
929  * Class Definition Table
930  */
931 
932 struct ClassDefFormat1
933 {
934   friend struct ClassDef;
935 
936   private:
get_classOT::ClassDefFormat1937   inline unsigned int get_class (hb_codepoint_t glyph_id) const
938   {
939     if (unlikely ((unsigned int) (glyph_id - startGlyph) < classValue.len))
940       return classValue[glyph_id - startGlyph];
941     return 0;
942   }
943 
sanitizeOT::ClassDefFormat1944   inline bool sanitize (hb_sanitize_context_t *c) {
945     TRACE_SANITIZE (this);
946     return TRACE_RETURN (c->check_struct (this) && classValue.sanitize (c));
947   }
948 
949   template <typename set_t>
add_classOT::ClassDefFormat1950   inline void add_class (set_t *glyphs, unsigned int klass) const {
951     unsigned int count = classValue.len;
952     for (unsigned int i = 0; i < count; i++)
953       if (classValue[i] == klass)
954         glyphs->add (startGlyph + i);
955   }
956 
intersects_classOT::ClassDefFormat1957   inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
958     unsigned int count = classValue.len;
959     for (unsigned int i = 0; i < count; i++)
960       if (classValue[i] == klass && glyphs->has (startGlyph + i))
961         return true;
962     return false;
963   }
964 
965   protected:
966   USHORT	classFormat;		/* Format identifier--format = 1 */
967   GlyphID	startGlyph;		/* First GlyphID of the classValueArray */
968   ArrayOf<USHORT>
969 		classValue;		/* Array of Class Values--one per GlyphID */
970   public:
971   DEFINE_SIZE_ARRAY (6, classValue);
972 };
973 
974 struct ClassDefFormat2
975 {
976   friend struct ClassDef;
977 
978   private:
get_classOT::ClassDefFormat2979   inline unsigned int get_class (hb_codepoint_t glyph_id) const
980   {
981     int i = rangeRecord.search (glyph_id);
982     if (i != -1)
983       return rangeRecord[i].value;
984     return 0;
985   }
986 
sanitizeOT::ClassDefFormat2987   inline bool sanitize (hb_sanitize_context_t *c) {
988     TRACE_SANITIZE (this);
989     return TRACE_RETURN (rangeRecord.sanitize (c));
990   }
991 
992   template <typename set_t>
add_classOT::ClassDefFormat2993   inline void add_class (set_t *glyphs, unsigned int klass) const {
994     unsigned int count = rangeRecord.len;
995     for (unsigned int i = 0; i < count; i++)
996       if (rangeRecord[i].value == klass)
997         rangeRecord[i].add_coverage (glyphs);
998   }
999 
intersects_classOT::ClassDefFormat21000   inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
1001     unsigned int count = rangeRecord.len;
1002     for (unsigned int i = 0; i < count; i++)
1003       if (rangeRecord[i].value == klass && rangeRecord[i].intersects (glyphs))
1004         return true;
1005     return false;
1006   }
1007 
1008   protected:
1009   USHORT	classFormat;	/* Format identifier--format = 2 */
1010   SortedArrayOf<RangeRecord>
1011 		rangeRecord;	/* Array of glyph ranges--ordered by
1012 				 * Start GlyphID */
1013   public:
1014   DEFINE_SIZE_ARRAY (4, rangeRecord);
1015 };
1016 
1017 struct ClassDef
1018 {
get_classOT::ClassDef1019   inline unsigned int get_class (hb_codepoint_t glyph_id) const
1020   {
1021     switch (u.format) {
1022     case 1: return u.format1.get_class(glyph_id);
1023     case 2: return u.format2.get_class(glyph_id);
1024     default:return 0;
1025     }
1026   }
1027 
sanitizeOT::ClassDef1028   inline bool sanitize (hb_sanitize_context_t *c) {
1029     TRACE_SANITIZE (this);
1030     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
1031     switch (u.format) {
1032     case 1: return TRACE_RETURN (u.format1.sanitize (c));
1033     case 2: return TRACE_RETURN (u.format2.sanitize (c));
1034     default:return TRACE_RETURN (true);
1035     }
1036   }
1037 
add_classOT::ClassDef1038   inline void add_class (hb_set_t *glyphs, unsigned int klass) const {
1039     switch (u.format) {
1040     case 1: u.format1.add_class (glyphs, klass); return;
1041     case 2: u.format2.add_class (glyphs, klass); return;
1042     default:return;
1043     }
1044   }
1045 
intersects_classOT::ClassDef1046   inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
1047     switch (u.format) {
1048     case 1: return u.format1.intersects_class (glyphs, klass);
1049     case 2: return u.format2.intersects_class (glyphs, klass);
1050     default:return false;
1051     }
1052   }
1053 
1054   protected:
1055   union {
1056   USHORT		format;		/* Format identifier */
1057   ClassDefFormat1	format1;
1058   ClassDefFormat2	format2;
1059   } u;
1060   public:
1061   DEFINE_SIZE_UNION (2, format);
1062 };
1063 
1064 
1065 /*
1066  * Device Tables
1067  */
1068 
1069 struct Device
1070 {
1071 
get_x_deltaOT::Device1072   inline hb_position_t get_x_delta (hb_font_t *font) const
1073   { return get_delta (font->x_ppem, font->x_scale); }
1074 
get_y_deltaOT::Device1075   inline hb_position_t get_y_delta (hb_font_t *font) const
1076   { return get_delta (font->y_ppem, font->y_scale); }
1077 
get_deltaOT::Device1078   inline int get_delta (unsigned int ppem, int scale) const
1079   {
1080     if (!ppem) return 0;
1081 
1082     int pixels = get_delta_pixels (ppem);
1083 
1084     if (!pixels) return 0;
1085 
1086     return pixels * (int64_t) scale / ppem;
1087   }
1088 
1089 
get_delta_pixelsOT::Device1090   inline int get_delta_pixels (unsigned int ppem_size) const
1091   {
1092     unsigned int f = deltaFormat;
1093     if (unlikely (f < 1 || f > 3))
1094       return 0;
1095 
1096     if (ppem_size < startSize || ppem_size > endSize)
1097       return 0;
1098 
1099     unsigned int s = ppem_size - startSize;
1100 
1101     unsigned int byte = deltaValue[s >> (4 - f)];
1102     unsigned int bits = (byte >> (16 - (((s & ((1 << (4 - f)) - 1)) + 1) << f)));
1103     unsigned int mask = (0xFFFF >> (16 - (1 << f)));
1104 
1105     int delta = bits & mask;
1106 
1107     if ((unsigned int) delta >= ((mask + 1) >> 1))
1108       delta -= mask + 1;
1109 
1110     return delta;
1111   }
1112 
get_sizeOT::Device1113   inline unsigned int get_size (void) const
1114   {
1115     unsigned int f = deltaFormat;
1116     if (unlikely (f < 1 || f > 3 || startSize > endSize)) return 3 * USHORT::static_size;
1117     return USHORT::static_size * (4 + ((endSize - startSize) >> (4 - f)));
1118   }
1119 
sanitizeOT::Device1120   inline bool sanitize (hb_sanitize_context_t *c) {
1121     TRACE_SANITIZE (this);
1122     return TRACE_RETURN (c->check_struct (this) && c->check_range (this, this->get_size ()));
1123   }
1124 
1125   protected:
1126   USHORT	startSize;		/* Smallest size to correct--in ppem */
1127   USHORT	endSize;		/* Largest size to correct--in ppem */
1128   USHORT	deltaFormat;		/* Format of DeltaValue array data: 1, 2, or 3
1129 					 * 1	Signed 2-bit value, 8 values per uint16
1130 					 * 2	Signed 4-bit value, 4 values per uint16
1131 					 * 3	Signed 8-bit value, 2 values per uint16
1132 					 */
1133   USHORT	deltaValue[VAR];	/* Array of compressed data */
1134   public:
1135   DEFINE_SIZE_ARRAY (6, deltaValue);
1136 };
1137 
1138 
1139 } /* namespace OT */
1140 
1141 
1142 #endif /* HB_OT_LAYOUT_COMMON_PRIVATE_HH */
1143