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
37namespace OT {
38
39
40#define NOT_COVERED		((unsigned int) -1)
41#define MAX_NESTING_LEVEL	8
42#define MAX_CONTEXT_LENGTH	64
43
44
45
46/*
47 *
48 * OpenType Layout Common Table Formats
49 *
50 */
51
52
53/*
54 * Script, ScriptList, LangSys, Feature, FeatureList, Lookup, LookupList
55 */
56
57template <typename Type>
58struct Record
59{
60  inline int cmp (hb_tag_t a) const {
61    return tag.cmp (a);
62  }
63
64  struct sanitize_closure_t {
65    hb_tag_t tag;
66    void *list_base;
67  };
68  inline bool sanitize (hb_sanitize_context_t *c, void *base) {
69    TRACE_SANITIZE (this);
70    const sanitize_closure_t closure = {tag, base};
71    return TRACE_RETURN (c->check_struct (this) && offset.sanitize (c, base, &closure));
72  }
73
74  Tag		tag;		/* 4-byte Tag identifier */
75  OffsetTo<Type>
76		offset;		/* Offset from beginning of object holding
77				 * the Record */
78  public:
79  DEFINE_SIZE_STATIC (6);
80};
81
82template <typename Type>
83struct RecordArrayOf : SortedArrayOf<Record<Type> > {
84  inline const Tag& get_tag (unsigned int i) const
85  {
86    /* We cheat slightly and don't define separate Null objects
87     * for Record types.  Instead, we return the correct Null(Tag)
88     * here. */
89    if (unlikely (i >= this->len)) return Null(Tag);
90    return (*this)[i].tag;
91  }
92  inline unsigned int get_tags (unsigned int start_offset,
93				unsigned int *record_count /* IN/OUT */,
94				hb_tag_t     *record_tags /* OUT */) const
95  {
96    if (record_count) {
97      const Record<Type> *arr = this->sub_array (start_offset, record_count);
98      unsigned int count = *record_count;
99      for (unsigned int i = 0; i < count; i++)
100	record_tags[i] = arr[i].tag;
101    }
102    return this->len;
103  }
104  inline bool find_index (hb_tag_t tag, unsigned int *index) const
105  {
106    int i = this->search (tag);
107    if (i != -1) {
108        if (index) *index = i;
109        return true;
110    } else {
111      if (index) *index = Index::NOT_FOUND_INDEX;
112      return false;
113    }
114  }
115};
116
117template <typename Type>
118struct RecordListOf : RecordArrayOf<Type>
119{
120  inline const Type& operator [] (unsigned int i) const
121  { return this+RecordArrayOf<Type>::operator [](i).offset; }
122
123  inline bool sanitize (hb_sanitize_context_t *c) {
124    TRACE_SANITIZE (this);
125    return TRACE_RETURN (RecordArrayOf<Type>::sanitize (c, this));
126  }
127};
128
129
130struct RangeRecord
131{
132  inline int cmp (hb_codepoint_t g) const {
133    return g < start ? -1 : g <= end ? 0 : +1 ;
134  }
135
136  inline bool sanitize (hb_sanitize_context_t *c) {
137    TRACE_SANITIZE (this);
138    return TRACE_RETURN (c->check_struct (this));
139  }
140
141  inline bool intersects (const hb_set_t *glyphs) const {
142    return glyphs->intersects (start, end);
143  }
144
145  template <typename set_t>
146  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};
156DEFINE_NULL_DATA (RangeRecord, "\000\001");
157
158
159struct IndexArray : ArrayOf<Index>
160{
161  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
176struct Script;
177struct LangSys;
178struct Feature;
179
180
181struct LangSys
182{
183  inline unsigned int get_feature_count (void) const
184  { return featureIndex.len; }
185  inline hb_tag_t get_feature_index (unsigned int i) const
186  { return featureIndex[i]; }
187  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
192  inline bool has_required_feature (void) const { return reqFeatureIndex != 0xffff; }
193  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
200  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};
215DEFINE_NULL_DATA (LangSys, "\0\0\xFF\xFF");
216
217
218struct Script
219{
220  inline unsigned int get_lang_sys_count (void) const
221  { return langSys.len; }
222  inline const Tag& get_lang_sys_tag (unsigned int i) const
223  { return langSys.get_tag (i); }
224  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); }
228  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  }
233  inline bool find_lang_sys_index (hb_tag_t tag, unsigned int *index) const
234  { return langSys.find_index (tag, index); }
235
236  inline bool has_default_lang_sys (void) const { return defaultLangSys != 0; }
237  inline const LangSys& get_default_lang_sys (void) const { return this+defaultLangSys; }
238
239  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
256typedef RecordListOf<Script> ScriptList;
257
258
259/* http://www.microsoft.com/typography/otspec/features_pt.htm#size */
260struct FeatureParamsSize
261{
262  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 */
371struct FeatureParamsStylisticSet
372{
373  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	version;	/* (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/* http://www.microsoft.com/typography/otspec/features_ae.htm#cv01-cv99 */
404struct FeatureParamsCharacterVariants
405{
406  inline bool sanitize (hb_sanitize_context_t *c) {
407    TRACE_SANITIZE (this);
408    return TRACE_RETURN (c->check_struct (this) &&
409			 characters.sanitize (c));
410  }
411
412  USHORT	format;			/* Format number is set to 0. */
413  USHORT	featUILableNameID;	/* The ‘name’ table name ID that
414					 * specifies a string (or strings,
415					 * for multiple languages) for a
416					 * user-interface label for this
417					 * feature. (May be NULL.) */
418  USHORT	featUITooltipTextNameID;/* The ‘name’ table name ID that
419					 * specifies a string (or strings,
420					 * for multiple languages) that an
421					 * application can use for tooltip
422					 * text for this feature. (May be
423					 * NULL.) */
424  USHORT	sampleTextNameID;	/* The ‘name’ table name ID that
425					 * specifies sample text that
426					 * illustrates the effect of this
427					 * feature. (May be NULL.) */
428  USHORT	numNamedParameters;	/* Number of named parameters. (May
429					 * be zero.) */
430  USHORT	firstParamUILabelNameID;/* The first ‘name’ table name ID
431					 * used to specify strings for
432					 * user-interface labels for the
433					 * feature parameters. (Must be zero
434					 * if numParameters is zero.) */
435  ArrayOf<UINT24>
436		characters;		/* Array of the Unicode Scalar Value
437					 * of the characters for which this
438					 * feature provides glyph variants.
439					 * (May be zero.) */
440  public:
441  DEFINE_SIZE_ARRAY (14, characters);
442};
443
444struct FeatureParams
445{
446  inline bool sanitize (hb_sanitize_context_t *c, hb_tag_t tag) {
447    TRACE_SANITIZE (this);
448    if (tag == HB_TAG ('s','i','z','e'))
449      return TRACE_RETURN (u.size.sanitize (c));
450    if ((tag & 0xFFFF0000) == HB_TAG ('s','s','\0','\0')) /* ssXX */
451      return TRACE_RETURN (u.stylisticSet.sanitize (c));
452    if ((tag & 0xFFFF0000) == HB_TAG ('c','v','\0','\0')) /* cvXX */
453      return TRACE_RETURN (u.characterVariants.sanitize (c));
454    return TRACE_RETURN (true);
455  }
456
457  inline const FeatureParamsSize& get_size_params (hb_tag_t tag) const
458  {
459    if (tag == HB_TAG ('s','i','z','e'))
460      return u.size;
461    return Null(FeatureParamsSize);
462  }
463
464  private:
465  union {
466  FeatureParamsSize			size;
467  FeatureParamsStylisticSet		stylisticSet;
468  FeatureParamsCharacterVariants	characterVariants;
469  } u;
470  DEFINE_SIZE_STATIC (17);
471};
472
473struct Feature
474{
475  inline unsigned int get_lookup_count (void) const
476  { return lookupIndex.len; }
477  inline hb_tag_t get_lookup_index (unsigned int i) const
478  { return lookupIndex[i]; }
479  inline unsigned int get_lookup_indexes (unsigned int start_index,
480					  unsigned int *lookup_count /* IN/OUT */,
481					  unsigned int *lookup_tags /* OUT */) const
482  { return lookupIndex.get_indexes (start_index, lookup_count, lookup_tags); }
483
484  inline const FeatureParams &get_feature_params (void) const
485  { return this+featureParams; }
486
487  inline bool sanitize (hb_sanitize_context_t *c,
488			const Record<Feature>::sanitize_closure_t *closure) {
489    TRACE_SANITIZE (this);
490    if (unlikely (!(c->check_struct (this) && lookupIndex.sanitize (c))))
491      return TRACE_RETURN (false);
492
493    /* Some earlier versions of Adobe tools calculated the offset of the
494     * FeatureParams subtable from the beginning of the FeatureList table!
495     *
496     * If sanitizing "failed" for the FeatureParams subtable, try it with the
497     * alternative location.  We would know sanitize "failed" if old value
498     * of the offset was non-zero, but it's zeroed now.
499     *
500     * Only do this for the 'size' feature, since at the time of the faulty
501     * Adobe tools, only the 'size' feature had FeatureParams defined.
502     */
503
504    Offset orig_offset = featureParams;
505    if (unlikely (!featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE)))
506      return TRACE_RETURN (false);
507
508    if (likely (!orig_offset))
509      return TRACE_RETURN (true);
510
511    if (featureParams == 0 && closure &&
512	closure->tag == HB_TAG ('s','i','z','e') &&
513	closure->list_base && closure->list_base < this)
514    {
515      unsigned int new_offset_int = (unsigned int) orig_offset -
516				    ((char *) this - (char *) closure->list_base);
517
518      Offset new_offset;
519      /* Check that it did not overflow. */
520      new_offset.set (new_offset_int);
521      if (new_offset == new_offset_int &&
522	  featureParams.try_set (c, new_offset) &&
523	  !featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE))
524	return TRACE_RETURN (false);
525    }
526
527    return TRACE_RETURN (true);
528  }
529
530  OffsetTo<FeatureParams>
531		 featureParams;	/* Offset to Feature Parameters table (if one
532				 * has been defined for the feature), relative
533				 * to the beginning of the Feature Table; = Null
534				 * if not required */
535  IndexArray	 lookupIndex;	/* Array of LookupList indices */
536  public:
537  DEFINE_SIZE_ARRAY (4, lookupIndex);
538};
539
540typedef RecordListOf<Feature> FeatureList;
541
542
543struct LookupFlag : USHORT
544{
545  enum Flags {
546    RightToLeft		= 0x0001u,
547    IgnoreBaseGlyphs	= 0x0002u,
548    IgnoreLigatures	= 0x0004u,
549    IgnoreMarks		= 0x0008u,
550    IgnoreFlags		= 0x000Eu,
551    UseMarkFilteringSet	= 0x0010u,
552    Reserved		= 0x00E0u,
553    MarkAttachmentType	= 0xFF00u
554  };
555  public:
556  DEFINE_SIZE_STATIC (2);
557};
558
559struct Lookup
560{
561  inline unsigned int get_subtable_count (void) const { return subTable.len; }
562
563  inline unsigned int get_type (void) const { return lookupType; }
564
565  /* lookup_props is a 32-bit integer where the lower 16-bit is LookupFlag and
566   * higher 16-bit is mark-filtering-set if the lookup uses one.
567   * Not to be confused with glyph_props which is very similar. */
568  inline uint32_t get_props (void) const
569  {
570    unsigned int flag = lookupFlag;
571    if (unlikely (flag & LookupFlag::UseMarkFilteringSet))
572    {
573      const USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
574      flag += (markFilteringSet << 16);
575    }
576    return flag;
577  }
578
579  inline bool serialize (hb_serialize_context_t *c,
580			 unsigned int lookup_type,
581			 uint32_t lookup_props,
582			 unsigned int num_subtables)
583  {
584    TRACE_SERIALIZE (this);
585    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
586    lookupType.set (lookup_type);
587    lookupFlag.set (lookup_props & 0xFFFF);
588    if (unlikely (!subTable.serialize (c, num_subtables))) return TRACE_RETURN (false);
589    if (lookupFlag & LookupFlag::UseMarkFilteringSet)
590    {
591      USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
592      markFilteringSet.set (lookup_props >> 16);
593    }
594    return TRACE_RETURN (true);
595  }
596
597  inline bool sanitize (hb_sanitize_context_t *c) {
598    TRACE_SANITIZE (this);
599    /* Real sanitize of the subtables is done by GSUB/GPOS/... */
600    if (!(c->check_struct (this) && subTable.sanitize (c))) return TRACE_RETURN (false);
601    if (lookupFlag & LookupFlag::UseMarkFilteringSet)
602    {
603      USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
604      if (!markFilteringSet.sanitize (c)) return TRACE_RETURN (false);
605    }
606    return TRACE_RETURN (true);
607  }
608
609  USHORT	lookupType;		/* Different enumerations for GSUB and GPOS */
610  USHORT	lookupFlag;		/* Lookup qualifiers */
611  ArrayOf<Offset>
612		subTable;		/* Array of SubTables */
613  USHORT	markFilteringSetX[VAR];	/* Index (base 0) into GDEF mark glyph sets
614					 * structure. This field is only present if bit
615					 * UseMarkFilteringSet of lookup flags is set. */
616  public:
617  DEFINE_SIZE_ARRAY2 (6, subTable, markFilteringSetX);
618};
619
620typedef OffsetListOf<Lookup> LookupList;
621
622
623/*
624 * Coverage Table
625 */
626
627struct CoverageFormat1
628{
629  friend struct Coverage;
630
631  private:
632  inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
633  {
634    int i = glyphArray.search (glyph_id);
635    ASSERT_STATIC (((unsigned int) -1) == NOT_COVERED);
636    return i;
637  }
638
639  inline bool serialize (hb_serialize_context_t *c,
640			 Supplier<GlyphID> &glyphs,
641			 unsigned int num_glyphs)
642  {
643    TRACE_SERIALIZE (this);
644    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
645    glyphArray.len.set (num_glyphs);
646    if (unlikely (!c->extend (glyphArray))) return TRACE_RETURN (false);
647    for (unsigned int i = 0; i < num_glyphs; i++)
648      glyphArray[i] = glyphs[i];
649    glyphs.advance (num_glyphs);
650    return TRACE_RETURN (true);
651  }
652
653  inline bool sanitize (hb_sanitize_context_t *c) {
654    TRACE_SANITIZE (this);
655    return TRACE_RETURN (glyphArray.sanitize (c));
656  }
657
658  inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const {
659    return glyphs->has (glyphArray[index]);
660  }
661
662  template <typename set_t>
663  inline void add_coverage (set_t *glyphs) const {
664    unsigned int count = glyphArray.len;
665    for (unsigned int i = 0; i < count; i++)
666      glyphs->add (glyphArray[i]);
667  }
668
669  public:
670  /* Older compilers need this to be public. */
671  struct Iter {
672    inline void init (const struct CoverageFormat1 &c_) { c = &c_; i = 0; };
673    inline bool more (void) { return i < c->glyphArray.len; }
674    inline void next (void) { i++; }
675    inline uint16_t get_glyph (void) { return c->glyphArray[i]; }
676    inline uint16_t get_coverage (void) { return i; }
677
678    private:
679    const struct CoverageFormat1 *c;
680    unsigned int i;
681  };
682  private:
683
684  protected:
685  USHORT	coverageFormat;	/* Format identifier--format = 1 */
686  SortedArrayOf<GlyphID>
687		glyphArray;	/* Array of GlyphIDs--in numerical order */
688  public:
689  DEFINE_SIZE_ARRAY (4, glyphArray);
690};
691
692struct CoverageFormat2
693{
694  friend struct Coverage;
695
696  private:
697  inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
698  {
699    int i = rangeRecord.search (glyph_id);
700    if (i != -1) {
701      const RangeRecord &range = rangeRecord[i];
702      return (unsigned int) range.value + (glyph_id - range.start);
703    }
704    return NOT_COVERED;
705  }
706
707  inline bool serialize (hb_serialize_context_t *c,
708			 Supplier<GlyphID> &glyphs,
709			 unsigned int num_glyphs)
710  {
711    TRACE_SERIALIZE (this);
712    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
713
714    if (unlikely (!num_glyphs)) return TRACE_RETURN (true);
715
716    unsigned int num_ranges = 1;
717    for (unsigned int i = 1; i < num_glyphs; i++)
718      if (glyphs[i - 1] + 1 != glyphs[i])
719        num_ranges++;
720    rangeRecord.len.set (num_ranges);
721    if (unlikely (!c->extend (rangeRecord))) return TRACE_RETURN (false);
722
723    unsigned int range = 0;
724    rangeRecord[range].start = glyphs[0];
725    rangeRecord[range].value.set (0);
726    for (unsigned int i = 1; i < num_glyphs; i++)
727      if (glyphs[i - 1] + 1 != glyphs[i]) {
728	range++;
729	rangeRecord[range].start = glyphs[i];
730	rangeRecord[range].value.set (i);
731        rangeRecord[range].end = glyphs[i];
732      } else {
733        rangeRecord[range].end = glyphs[i];
734      }
735    glyphs.advance (num_glyphs);
736    return TRACE_RETURN (true);
737  }
738
739  inline bool sanitize (hb_sanitize_context_t *c) {
740    TRACE_SANITIZE (this);
741    return TRACE_RETURN (rangeRecord.sanitize (c));
742  }
743
744  inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const {
745    unsigned int i;
746    unsigned int count = rangeRecord.len;
747    for (i = 0; i < count; i++) {
748      const RangeRecord &range = rangeRecord[i];
749      if (range.value <= index &&
750	  index < (unsigned int) range.value + (range.end - range.start) &&
751	  range.intersects (glyphs))
752        return true;
753      else if (index < range.value)
754        return false;
755    }
756    return false;
757  }
758
759  template <typename set_t>
760  inline void add_coverage (set_t *glyphs) const {
761    unsigned int count = rangeRecord.len;
762    for (unsigned int i = 0; i < count; i++)
763      rangeRecord[i].add_coverage (glyphs);
764  }
765
766  public:
767  /* Older compilers need this to be public. */
768  struct Iter {
769    inline void init (const CoverageFormat2 &c_) {
770      c = &c_;
771      coverage = 0;
772      i = 0;
773      j = c->rangeRecord.len ? c_.rangeRecord[0].start : 0;
774    }
775    inline bool more (void) { return i < c->rangeRecord.len; }
776    inline void next (void) {
777      coverage++;
778      if (j == c->rangeRecord[i].end) {
779        i++;
780	if (more ())
781	  j = c->rangeRecord[i].start;
782	return;
783      }
784      j++;
785    }
786    inline uint16_t get_glyph (void) { return j; }
787    inline uint16_t get_coverage (void) { return coverage; }
788
789    private:
790    const struct CoverageFormat2 *c;
791    unsigned int i, j, coverage;
792  };
793  private:
794
795  protected:
796  USHORT	coverageFormat;	/* Format identifier--format = 2 */
797  SortedArrayOf<RangeRecord>
798		rangeRecord;	/* Array of glyph ranges--ordered by
799				 * Start GlyphID. rangeCount entries
800				 * long */
801  public:
802  DEFINE_SIZE_ARRAY (4, rangeRecord);
803};
804
805struct Coverage
806{
807  inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
808  {
809    switch (u.format) {
810    case 1: return u.format1.get_coverage(glyph_id);
811    case 2: return u.format2.get_coverage(glyph_id);
812    default:return NOT_COVERED;
813    }
814  }
815
816  inline bool serialize (hb_serialize_context_t *c,
817			 Supplier<GlyphID> &glyphs,
818			 unsigned int num_glyphs)
819  {
820    TRACE_SERIALIZE (this);
821    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
822    unsigned int num_ranges = 1;
823    for (unsigned int i = 1; i < num_glyphs; i++)
824      if (glyphs[i - 1] + 1 != glyphs[i])
825        num_ranges++;
826    u.format.set (num_glyphs * 2 < num_ranges * 3 ? 1 : 2);
827    switch (u.format) {
828    case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, num_glyphs));
829    case 2: return TRACE_RETURN (u.format2.serialize (c, glyphs, num_glyphs));
830    default:return TRACE_RETURN (false);
831    }
832  }
833
834  inline bool sanitize (hb_sanitize_context_t *c) {
835    TRACE_SANITIZE (this);
836    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
837    switch (u.format) {
838    case 1: return TRACE_RETURN (u.format1.sanitize (c));
839    case 2: return TRACE_RETURN (u.format2.sanitize (c));
840    default:return TRACE_RETURN (true);
841    }
842  }
843
844  inline bool intersects (const hb_set_t *glyphs) const {
845    /* TODO speed this up */
846    Coverage::Iter iter;
847    for (iter.init (*this); iter.more (); iter.next ()) {
848      if (glyphs->has (iter.get_glyph ()))
849        return true;
850    }
851    return false;
852  }
853
854  inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const {
855    switch (u.format) {
856    case 1: return u.format1.intersects_coverage (glyphs, index);
857    case 2: return u.format2.intersects_coverage (glyphs, index);
858    default:return false;
859    }
860  }
861
862  template <typename set_t>
863  inline void add_coverage (set_t *glyphs) const {
864    switch (u.format) {
865    case 1: u.format1.add_coverage (glyphs); break;
866    case 2: u.format2.add_coverage (glyphs); break;
867    default:                                 break;
868    }
869  }
870
871  struct Iter {
872    Iter (void) : format (0) {};
873    inline void init (const Coverage &c_) {
874      format = c_.u.format;
875      switch (format) {
876      case 1: u.format1.init (c_.u.format1); return;
877      case 2: u.format2.init (c_.u.format2); return;
878      default:                               return;
879      }
880    }
881    inline bool more (void) {
882      switch (format) {
883      case 1: return u.format1.more ();
884      case 2: return u.format2.more ();
885      default:return false;
886      }
887    }
888    inline void next (void) {
889      switch (format) {
890      case 1: u.format1.next (); break;
891      case 2: u.format2.next (); break;
892      default:                   break;
893      }
894    }
895    inline uint16_t get_glyph (void) {
896      switch (format) {
897      case 1: return u.format1.get_glyph ();
898      case 2: return u.format2.get_glyph ();
899      default:return 0;
900      }
901    }
902    inline uint16_t get_coverage (void) {
903      switch (format) {
904      case 1: return u.format1.get_coverage ();
905      case 2: return u.format2.get_coverage ();
906      default:return -1;
907      }
908    }
909
910    private:
911    unsigned int format;
912    union {
913    CoverageFormat1::Iter	format1;
914    CoverageFormat2::Iter	format2;
915    } u;
916  };
917
918  protected:
919  union {
920  USHORT		format;		/* Format identifier */
921  CoverageFormat1	format1;
922  CoverageFormat2	format2;
923  } u;
924  public:
925  DEFINE_SIZE_UNION (2, format);
926};
927
928
929/*
930 * Class Definition Table
931 */
932
933struct ClassDefFormat1
934{
935  friend struct ClassDef;
936
937  private:
938  inline unsigned int get_class (hb_codepoint_t glyph_id) const
939  {
940    if (unlikely ((unsigned int) (glyph_id - startGlyph) < classValue.len))
941      return classValue[glyph_id - startGlyph];
942    return 0;
943  }
944
945  inline bool sanitize (hb_sanitize_context_t *c) {
946    TRACE_SANITIZE (this);
947    return TRACE_RETURN (c->check_struct (this) && classValue.sanitize (c));
948  }
949
950  template <typename set_t>
951  inline void add_class (set_t *glyphs, unsigned int klass) const {
952    unsigned int count = classValue.len;
953    for (unsigned int i = 0; i < count; i++)
954      if (classValue[i] == klass)
955        glyphs->add (startGlyph + i);
956  }
957
958  inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
959    unsigned int count = classValue.len;
960    if (klass == 0)
961    {
962      /* Match if there's any glyph that is not listed! */
963      hb_codepoint_t g = -1;
964      if (!hb_set_next (glyphs, &g))
965        return false;
966      if (g < startGlyph)
967        return true;
968      g = startGlyph + count - 1;
969      if (hb_set_next (glyphs, &g))
970        return true;
971      /* Fall through. */
972    }
973    for (unsigned int i = 0; i < count; i++)
974      if (classValue[i] == klass && glyphs->has (startGlyph + i))
975        return true;
976    return false;
977  }
978
979  protected:
980  USHORT	classFormat;		/* Format identifier--format = 1 */
981  GlyphID	startGlyph;		/* First GlyphID of the classValueArray */
982  ArrayOf<USHORT>
983		classValue;		/* Array of Class Values--one per GlyphID */
984  public:
985  DEFINE_SIZE_ARRAY (6, classValue);
986};
987
988struct ClassDefFormat2
989{
990  friend struct ClassDef;
991
992  private:
993  inline unsigned int get_class (hb_codepoint_t glyph_id) const
994  {
995    int i = rangeRecord.search (glyph_id);
996    if (i != -1)
997      return rangeRecord[i].value;
998    return 0;
999  }
1000
1001  inline bool sanitize (hb_sanitize_context_t *c) {
1002    TRACE_SANITIZE (this);
1003    return TRACE_RETURN (rangeRecord.sanitize (c));
1004  }
1005
1006  template <typename set_t>
1007  inline void add_class (set_t *glyphs, unsigned int klass) const {
1008    unsigned int count = rangeRecord.len;
1009    for (unsigned int i = 0; i < count; i++)
1010      if (rangeRecord[i].value == klass)
1011        rangeRecord[i].add_coverage (glyphs);
1012  }
1013
1014  inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
1015    unsigned int count = rangeRecord.len;
1016    if (klass == 0)
1017    {
1018      /* Match if there's any glyph that is not listed! */
1019      hb_codepoint_t g = (hb_codepoint_t) -1;
1020      for (unsigned int i = 0; i < count; i++)
1021      {
1022	if (!hb_set_next (glyphs, &g))
1023	  break;
1024	if (g < rangeRecord[i].start)
1025	  return true;
1026	g = rangeRecord[i].end;
1027      }
1028      if (g != (hb_codepoint_t) -1 && hb_set_next (glyphs, &g))
1029        return true;
1030      /* Fall through. */
1031    }
1032    for (unsigned int i = 0; i < count; i++)
1033      if (rangeRecord[i].value == klass && rangeRecord[i].intersects (glyphs))
1034        return true;
1035    return false;
1036  }
1037
1038  protected:
1039  USHORT	classFormat;	/* Format identifier--format = 2 */
1040  SortedArrayOf<RangeRecord>
1041		rangeRecord;	/* Array of glyph ranges--ordered by
1042				 * Start GlyphID */
1043  public:
1044  DEFINE_SIZE_ARRAY (4, rangeRecord);
1045};
1046
1047struct ClassDef
1048{
1049  inline unsigned int get_class (hb_codepoint_t glyph_id) const
1050  {
1051    switch (u.format) {
1052    case 1: return u.format1.get_class(glyph_id);
1053    case 2: return u.format2.get_class(glyph_id);
1054    default:return 0;
1055    }
1056  }
1057
1058  inline bool sanitize (hb_sanitize_context_t *c) {
1059    TRACE_SANITIZE (this);
1060    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
1061    switch (u.format) {
1062    case 1: return TRACE_RETURN (u.format1.sanitize (c));
1063    case 2: return TRACE_RETURN (u.format2.sanitize (c));
1064    default:return TRACE_RETURN (true);
1065    }
1066  }
1067
1068  inline void add_class (hb_set_t *glyphs, unsigned int klass) const {
1069    switch (u.format) {
1070    case 1: u.format1.add_class (glyphs, klass); return;
1071    case 2: u.format2.add_class (glyphs, klass); return;
1072    default:return;
1073    }
1074  }
1075
1076  inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
1077    switch (u.format) {
1078    case 1: return u.format1.intersects_class (glyphs, klass);
1079    case 2: return u.format2.intersects_class (glyphs, klass);
1080    default:return false;
1081    }
1082  }
1083
1084  protected:
1085  union {
1086  USHORT		format;		/* Format identifier */
1087  ClassDefFormat1	format1;
1088  ClassDefFormat2	format2;
1089  } u;
1090  public:
1091  DEFINE_SIZE_UNION (2, format);
1092};
1093
1094
1095/*
1096 * Device Tables
1097 */
1098
1099struct Device
1100{
1101
1102  inline hb_position_t get_x_delta (hb_font_t *font) const
1103  { return get_delta (font->x_ppem, font->x_scale); }
1104
1105  inline hb_position_t get_y_delta (hb_font_t *font) const
1106  { return get_delta (font->y_ppem, font->y_scale); }
1107
1108  inline int get_delta (unsigned int ppem, int scale) const
1109  {
1110    if (!ppem) return 0;
1111
1112    int pixels = get_delta_pixels (ppem);
1113
1114    if (!pixels) return 0;
1115
1116    return (int) (pixels * (int64_t) scale / ppem);
1117  }
1118
1119
1120  inline int get_delta_pixels (unsigned int ppem_size) const
1121  {
1122    unsigned int f = deltaFormat;
1123    if (unlikely (f < 1 || f > 3))
1124      return 0;
1125
1126    if (ppem_size < startSize || ppem_size > endSize)
1127      return 0;
1128
1129    unsigned int s = ppem_size - startSize;
1130
1131    unsigned int byte = deltaValue[s >> (4 - f)];
1132    unsigned int bits = (byte >> (16 - (((s & ((1 << (4 - f)) - 1)) + 1) << f)));
1133    unsigned int mask = (0xFFFF >> (16 - (1 << f)));
1134
1135    int delta = bits & mask;
1136
1137    if ((unsigned int) delta >= ((mask + 1) >> 1))
1138      delta -= mask + 1;
1139
1140    return delta;
1141  }
1142
1143  inline unsigned int get_size (void) const
1144  {
1145    unsigned int f = deltaFormat;
1146    if (unlikely (f < 1 || f > 3 || startSize > endSize)) return 3 * USHORT::static_size;
1147    return USHORT::static_size * (4 + ((endSize - startSize) >> (4 - f)));
1148  }
1149
1150  inline bool sanitize (hb_sanitize_context_t *c) {
1151    TRACE_SANITIZE (this);
1152    return TRACE_RETURN (c->check_struct (this) && c->check_range (this, this->get_size ()));
1153  }
1154
1155  protected:
1156  USHORT	startSize;		/* Smallest size to correct--in ppem */
1157  USHORT	endSize;		/* Largest size to correct--in ppem */
1158  USHORT	deltaFormat;		/* Format of DeltaValue array data: 1, 2, or 3
1159					 * 1	Signed 2-bit value, 8 values per uint16
1160					 * 2	Signed 4-bit value, 4 values per uint16
1161					 * 3	Signed 8-bit value, 2 values per uint16
1162					 */
1163  USHORT	deltaValue[VAR];	/* Array of compressed data */
1164  public:
1165  DEFINE_SIZE_ARRAY (6, deltaValue);
1166};
1167
1168
1169} /* namespace OT */
1170
1171
1172#endif /* HB_OT_LAYOUT_COMMON_PRIVATE_HH */
1173