Upgrade to latest harfbuzz
[framework/uifw/harfbuzz.git] / src / hb-ot-layout-common-private.hh
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 #define NOT_COVERED             ((unsigned int) 0x110000)
38 #define MAX_NESTING_LEVEL       8
39
40
41
42 /*
43  *
44  * OpenType Layout Common Table Formats
45  *
46  */
47
48
49 /*
50  * Script, ScriptList, LangSys, Feature, FeatureList, Lookup, LookupList
51  */
52
53 template <typename Type>
54 struct Record
55 {
56   inline int cmp (hb_tag_t a) const {
57     return tag.cmp (a);
58   }
59
60   inline bool sanitize (hb_sanitize_context_t *c, void *base) {
61     TRACE_SANITIZE ();
62     return TRACE_RETURN (c->check_struct (this) && offset.sanitize (c, base));
63   }
64
65   Tag           tag;            /* 4-byte Tag identifier */
66   OffsetTo<Type>
67                 offset;         /* Offset from beginning of object holding
68                                  * the Record */
69   public:
70   DEFINE_SIZE_STATIC (6);
71 };
72
73 template <typename Type>
74 struct RecordArrayOf : SortedArrayOf<Record<Type> > {
75   inline const Tag& get_tag (unsigned int i) const
76   {
77     /* We cheat slightly and don't define separate Null objects
78      * for Record types.  Instead, we return the correct Null(Tag)
79      * here. */
80     if (unlikely (i >= this->len)) return Null(Tag);
81     return (*this)[i].tag;
82   }
83   inline unsigned int get_tags (unsigned int start_offset,
84                                 unsigned int *record_count /* IN/OUT */,
85                                 hb_tag_t     *record_tags /* OUT */) const
86   {
87     if (record_count) {
88       const Record<Type> *arr = this->sub_array (start_offset, record_count);
89       unsigned int count = *record_count;
90       for (unsigned int i = 0; i < count; i++)
91         record_tags[i] = arr[i].tag;
92     }
93     return this->len;
94   }
95   inline bool find_index (hb_tag_t tag, unsigned int *index) const
96   {
97     int i = this->search (tag);
98     if (i != -1) {
99         if (index) *index = i;
100         return true;
101     } else {
102       if (index) *index = Index::NOT_FOUND_INDEX;
103       return false;
104     }
105   }
106 };
107
108 template <typename Type>
109 struct RecordListOf : RecordArrayOf<Type>
110 {
111   inline const Type& operator [] (unsigned int i) const
112   { return this+RecordArrayOf<Type>::operator [](i).offset; }
113
114   inline bool sanitize (hb_sanitize_context_t *c) {
115     TRACE_SANITIZE ();
116     return TRACE_RETURN (RecordArrayOf<Type>::sanitize (c, this));
117   }
118 };
119
120
121 struct RangeRecord
122 {
123   inline int cmp (hb_codepoint_t g) const {
124     hb_codepoint_t a = start, b = end;
125     return g < a ? -1 : g <= b ? 0 : +1 ;
126   }
127
128   inline bool sanitize (hb_sanitize_context_t *c) {
129     TRACE_SANITIZE ();
130     return TRACE_RETURN (c->check_struct (this));
131   }
132
133   inline bool intersects (const hb_set_t *glyphs) const {
134     return glyphs->intersects (start, end);
135   }
136
137   GlyphID       start;          /* First GlyphID in the range */
138   GlyphID       end;            /* Last GlyphID in the range */
139   USHORT        value;          /* Value */
140   public:
141   DEFINE_SIZE_STATIC (6);
142 };
143 DEFINE_NULL_DATA (RangeRecord, "\000\001");
144
145
146 struct IndexArray : ArrayOf<Index>
147 {
148   inline unsigned int get_indexes (unsigned int start_offset,
149                                    unsigned int *_count /* IN/OUT */,
150                                    unsigned int *_indexes /* OUT */) const
151   {
152     if (_count) {
153       const USHORT *arr = this->sub_array (start_offset, _count);
154       unsigned int count = *_count;
155       for (unsigned int i = 0; i < count; i++)
156         _indexes[i] = arr[i];
157     }
158     return this->len;
159   }
160 };
161
162
163 struct Script;
164 struct LangSys;
165 struct Feature;
166
167
168 struct LangSys
169 {
170   inline unsigned int get_feature_count (void) const
171   { return featureIndex.len; }
172   inline hb_tag_t get_feature_index (unsigned int i) const
173   { return featureIndex[i]; }
174   inline unsigned int get_feature_indexes (unsigned int start_offset,
175                                            unsigned int *feature_count /* IN/OUT */,
176                                            unsigned int *feature_indexes /* OUT */) const
177   { return featureIndex.get_indexes (start_offset, feature_count, feature_indexes); }
178
179   inline bool has_required_feature (void) const { return reqFeatureIndex != 0xffff; }
180   inline unsigned int get_required_feature_index (void) const
181   {
182     if (reqFeatureIndex == 0xffff)
183       return Index::NOT_FOUND_INDEX;
184    return reqFeatureIndex;;
185   }
186
187   inline bool sanitize (hb_sanitize_context_t *c) {
188     TRACE_SANITIZE ();
189     return TRACE_RETURN (c->check_struct (this) && featureIndex.sanitize (c));
190   }
191
192   Offset        lookupOrder;    /* = Null (reserved for an offset to a
193                                  * reordering table) */
194   USHORT        reqFeatureIndex;/* Index of a feature required for this
195                                  * language system--if no required features
196                                  * = 0xFFFF */
197   IndexArray    featureIndex;   /* Array of indices into the FeatureList */
198   public:
199   DEFINE_SIZE_ARRAY (6, featureIndex);
200 };
201 DEFINE_NULL_DATA (LangSys, "\0\0\xFF\xFF");
202
203
204 struct Script
205 {
206   inline unsigned int get_lang_sys_count (void) const
207   { return langSys.len; }
208   inline const Tag& get_lang_sys_tag (unsigned int i) const
209   { return langSys.get_tag (i); }
210   inline unsigned int get_lang_sys_tags (unsigned int start_offset,
211                                          unsigned int *lang_sys_count /* IN/OUT */,
212                                          hb_tag_t     *lang_sys_tags /* OUT */) const
213   { return langSys.get_tags (start_offset, lang_sys_count, lang_sys_tags); }
214   inline const LangSys& get_lang_sys (unsigned int i) const
215   {
216     if (i == Index::NOT_FOUND_INDEX) return get_default_lang_sys ();
217     return this+langSys[i].offset;
218   }
219   inline bool find_lang_sys_index (hb_tag_t tag, unsigned int *index) const
220   { return langSys.find_index (tag, index); }
221
222   inline bool has_default_lang_sys (void) const { return defaultLangSys != 0; }
223   inline const LangSys& get_default_lang_sys (void) const { return this+defaultLangSys; }
224
225   inline bool sanitize (hb_sanitize_context_t *c) {
226     TRACE_SANITIZE ();
227     return TRACE_RETURN (defaultLangSys.sanitize (c, this) && langSys.sanitize (c, this));
228   }
229
230   private:
231   OffsetTo<LangSys>
232                 defaultLangSys; /* Offset to DefaultLangSys table--from
233                                  * beginning of Script table--may be Null */
234   RecordArrayOf<LangSys>
235                 langSys;        /* Array of LangSysRecords--listed
236                                  * alphabetically by LangSysTag */
237   public:
238   DEFINE_SIZE_ARRAY (4, langSys);
239 };
240
241 typedef RecordListOf<Script> ScriptList;
242
243
244 struct Feature
245 {
246   inline unsigned int get_lookup_count (void) const
247   { return lookupIndex.len; }
248   inline hb_tag_t get_lookup_index (unsigned int i) const
249   { return lookupIndex[i]; }
250   inline unsigned int get_lookup_indexes (unsigned int start_index,
251                                           unsigned int *lookup_count /* IN/OUT */,
252                                           unsigned int *lookup_tags /* OUT */) const
253   { return lookupIndex.get_indexes (start_index, lookup_count, lookup_tags); }
254
255   inline bool sanitize (hb_sanitize_context_t *c) {
256     TRACE_SANITIZE ();
257     return TRACE_RETURN (c->check_struct (this) && lookupIndex.sanitize (c));
258   }
259
260   Offset        featureParams;  /* Offset to Feature Parameters table (if one
261                                  * has been defined for the feature), relative
262                                  * to the beginning of the Feature Table; = Null
263                                  * if not required */
264   IndexArray     lookupIndex;   /* Array of LookupList indices */
265   public:
266   DEFINE_SIZE_ARRAY (4, lookupIndex);
267 };
268
269 typedef RecordListOf<Feature> FeatureList;
270
271
272 struct LookupFlag : USHORT
273 {
274   enum Flags {
275     RightToLeft         = 0x0001u,
276     IgnoreBaseGlyphs    = 0x0002u,
277     IgnoreLigatures     = 0x0004u,
278     IgnoreMarks         = 0x0008u,
279     IgnoreFlags         = 0x000Eu,
280     UseMarkFilteringSet = 0x0010u,
281     Reserved            = 0x00E0u,
282     MarkAttachmentType  = 0xFF00u
283   };
284   public:
285   DEFINE_SIZE_STATIC (2);
286 };
287
288 struct Lookup
289 {
290   inline unsigned int get_subtable_count (void) const { return subTable.len; }
291
292   inline unsigned int get_type (void) const { return lookupType; }
293
294   /* lookup_props is a 32-bit integer where the lower 16-bit is LookupFlag and
295    * higher 16-bit is mark-filtering-set if the lookup uses one.
296    * Not to be confused with glyph_props which is very similar. */
297   inline uint32_t get_props (void) const
298   {
299     unsigned int flag = lookupFlag;
300     if (unlikely (flag & LookupFlag::UseMarkFilteringSet))
301     {
302       const USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
303       flag += (markFilteringSet << 16);
304     }
305     return flag;
306   }
307
308   inline bool sanitize (hb_sanitize_context_t *c) {
309     TRACE_SANITIZE ();
310     /* Real sanitize of the subtables is done by GSUB/GPOS/... */
311     if (!(c->check_struct (this) && subTable.sanitize (c))) return TRACE_RETURN (false);
312     if (unlikely (lookupFlag & LookupFlag::UseMarkFilteringSet))
313     {
314       USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
315       if (!markFilteringSet.sanitize (c)) return TRACE_RETURN (false);
316     }
317     return TRACE_RETURN (true);
318   }
319
320   USHORT        lookupType;             /* Different enumerations for GSUB and GPOS */
321   USHORT        lookupFlag;             /* Lookup qualifiers */
322   ArrayOf<Offset>
323                 subTable;               /* Array of SubTables */
324   USHORT        markFilteringSetX[VAR]; /* Index (base 0) into GDEF mark glyph sets
325                                          * structure. This field is only present if bit
326                                          * UseMarkFilteringSet of lookup flags is set. */
327   public:
328   DEFINE_SIZE_ARRAY2 (6, subTable, markFilteringSetX);
329 };
330
331 typedef OffsetListOf<Lookup> LookupList;
332
333
334 /*
335  * Coverage Table
336  */
337
338 struct CoverageFormat1
339 {
340   friend struct Coverage;
341
342   private:
343   inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
344   {
345     int i = glyphArray.search (glyph_id);
346     if (i != -1)
347         return i;
348     return NOT_COVERED;
349   }
350
351   inline bool sanitize (hb_sanitize_context_t *c) {
352     TRACE_SANITIZE ();
353     return TRACE_RETURN (glyphArray.sanitize (c));
354   }
355
356   inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const {
357     return glyphs->has (glyphArray[index]);
358   }
359
360   struct Iter {
361     inline void init (const struct CoverageFormat1 &c_) { c = &c_; i = 0; };
362     inline bool more (void) { return i < c->glyphArray.len; }
363     inline void next (void) { i++; }
364     inline uint16_t get_glyph (void) { return c->glyphArray[i]; }
365     inline uint16_t get_coverage (void) { return i; }
366
367     private:
368     const struct CoverageFormat1 *c;
369     unsigned int i;
370   };
371
372   private:
373   USHORT        coverageFormat; /* Format identifier--format = 1 */
374   SortedArrayOf<GlyphID>
375                 glyphArray;     /* Array of GlyphIDs--in numerical order */
376   public:
377   DEFINE_SIZE_ARRAY (4, glyphArray);
378 };
379
380 struct CoverageFormat2
381 {
382   friend struct Coverage;
383
384   private:
385   inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
386   {
387     int i = rangeRecord.search (glyph_id);
388     if (i != -1) {
389       const RangeRecord &range = rangeRecord[i];
390       return (unsigned int) range.value + (glyph_id - range.start);
391     }
392     return NOT_COVERED;
393   }
394
395   inline bool sanitize (hb_sanitize_context_t *c) {
396     TRACE_SANITIZE ();
397     return TRACE_RETURN (rangeRecord.sanitize (c));
398   }
399
400   inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const {
401     unsigned int i;
402     unsigned int count = rangeRecord.len;
403     for (i = 0; i < count; i++) {
404       const RangeRecord &range = rangeRecord[i];
405       if (range.value <= index &&
406           index < (unsigned int) range.value + (range.end - range.start) &&
407           range.intersects (glyphs))
408         return true;
409       else if (index < range.value)
410         return false;
411     }
412     return false;
413   }
414
415   struct Iter {
416     inline void init (const CoverageFormat2 &c_) {
417       c = &c_;
418       coverage = 0;
419       i = 0;
420       j = c->rangeRecord.len ? c_.rangeRecord[0].start : 0;
421     }
422     inline bool more (void) { return i < c->rangeRecord.len; }
423     inline void next (void) {
424       coverage++;
425       if (j == c->rangeRecord[i].end) {
426         i++;
427         if (more ())
428           j = c->rangeRecord[i].start;
429         return;
430       }
431       j++;
432     }
433     inline uint16_t get_glyph (void) { return j; }
434     inline uint16_t get_coverage (void) { return coverage; }
435
436     private:
437     const struct CoverageFormat2 *c;
438     unsigned int i, j, coverage;
439   };
440
441   private:
442   USHORT        coverageFormat; /* Format identifier--format = 2 */
443   SortedArrayOf<RangeRecord>
444                 rangeRecord;    /* Array of glyph ranges--ordered by
445                                  * Start GlyphID. rangeCount entries
446                                  * long */
447   public:
448   DEFINE_SIZE_ARRAY (4, rangeRecord);
449 };
450
451 struct Coverage
452 {
453   inline unsigned int operator () (hb_codepoint_t glyph_id) const { return get_coverage (glyph_id); }
454
455   inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
456   {
457     switch (u.format) {
458     case 1: return u.format1.get_coverage(glyph_id);
459     case 2: return u.format2.get_coverage(glyph_id);
460     default:return NOT_COVERED;
461     }
462   }
463
464   inline bool sanitize (hb_sanitize_context_t *c) {
465     TRACE_SANITIZE ();
466     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
467     switch (u.format) {
468     case 1: return TRACE_RETURN (u.format1.sanitize (c));
469     case 2: return TRACE_RETURN (u.format2.sanitize (c));
470     default:return TRACE_RETURN (true);
471     }
472   }
473
474   inline bool intersects (const hb_set_t *glyphs) const {
475     /* TODO speed this up */
476     Coverage::Iter iter;
477     for (iter.init (*this); iter.more (); iter.next ()) {
478       if (glyphs->has (iter.get_glyph ()))
479         return true;
480     }
481     return false;
482   }
483
484   inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const {
485     switch (u.format) {
486     case 1: return u.format1.intersects_coverage (glyphs, index);
487     case 2: return u.format2.intersects_coverage (glyphs, index);
488     default:return false;
489     }
490   }
491
492   struct Iter {
493     Iter (void) : format (0) {};
494     inline void init (const Coverage &c_) {
495       format = c_.u.format;
496       switch (format) {
497       case 1: return u.format1.init (c_.u.format1);
498       case 2: return u.format2.init (c_.u.format2);
499       default:return;
500       }
501     }
502     inline bool more (void) {
503       switch (format) {
504       case 1: return u.format1.more ();
505       case 2: return u.format2.more ();
506       default:return true;
507       }
508     }
509     inline void next (void) {
510       switch (format) {
511       case 1: u.format1.next (); break;
512       case 2: u.format2.next (); break;
513       default:                   break;
514       }
515     }
516     inline uint16_t get_glyph (void) {
517       switch (format) {
518       case 1: return u.format1.get_glyph ();
519       case 2: return u.format2.get_glyph ();
520       default:return true;
521       }
522     }
523     inline uint16_t get_coverage (void) {
524       switch (format) {
525       case 1: return u.format1.get_coverage ();
526       case 2: return u.format2.get_coverage ();
527       default:return true;
528       }
529     }
530
531     private:
532     unsigned int format;
533     union {
534     CoverageFormat1::Iter       format1;
535     CoverageFormat2::Iter       format2;
536     } u;
537   };
538
539   private:
540   union {
541   USHORT                format;         /* Format identifier */
542   CoverageFormat1       format1;
543   CoverageFormat2       format2;
544   } u;
545   public:
546   DEFINE_SIZE_UNION (2, format);
547 };
548
549
550 /*
551  * Class Definition Table
552  */
553
554 struct ClassDefFormat1
555 {
556   friend struct ClassDef;
557
558   private:
559   inline unsigned int get_class (hb_codepoint_t glyph_id) const
560   {
561     if ((unsigned int) (glyph_id - startGlyph) < classValue.len)
562       return classValue[glyph_id - startGlyph];
563     return 0;
564   }
565
566   inline bool sanitize (hb_sanitize_context_t *c) {
567     TRACE_SANITIZE ();
568     return TRACE_RETURN (c->check_struct (this) && classValue.sanitize (c));
569   }
570
571   inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
572     unsigned int count = classValue.len;
573     for (unsigned int i = 0; i < count; i++)
574       if (classValue[i] == klass && glyphs->has (startGlyph + i))
575         return true;
576     return false;
577   }
578
579   USHORT        classFormat;            /* Format identifier--format = 1 */
580   GlyphID       startGlyph;             /* First GlyphID of the classValueArray */
581   ArrayOf<USHORT>
582                 classValue;             /* Array of Class Values--one per GlyphID */
583   public:
584   DEFINE_SIZE_ARRAY (6, classValue);
585 };
586
587 struct ClassDefFormat2
588 {
589   friend struct ClassDef;
590
591   private:
592   inline unsigned int get_class (hb_codepoint_t glyph_id) const
593   {
594     int i = rangeRecord.search (glyph_id);
595     if (i != -1)
596       return rangeRecord[i].value;
597     return 0;
598   }
599
600   inline bool sanitize (hb_sanitize_context_t *c) {
601     TRACE_SANITIZE ();
602     return TRACE_RETURN (rangeRecord.sanitize (c));
603   }
604
605   inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
606     unsigned int count = rangeRecord.len;
607     for (unsigned int i = 0; i < count; i++)
608       if (rangeRecord[i].value == klass && rangeRecord[i].intersects (glyphs))
609         return true;
610     return false;
611   }
612
613   USHORT        classFormat;    /* Format identifier--format = 2 */
614   SortedArrayOf<RangeRecord>
615                 rangeRecord;    /* Array of glyph ranges--ordered by
616                                  * Start GlyphID */
617   public:
618   DEFINE_SIZE_ARRAY (4, rangeRecord);
619 };
620
621 struct ClassDef
622 {
623   inline unsigned int operator () (hb_codepoint_t glyph_id) const { return get_class (glyph_id); }
624
625   inline unsigned int get_class (hb_codepoint_t glyph_id) const
626   {
627     switch (u.format) {
628     case 1: return u.format1.get_class(glyph_id);
629     case 2: return u.format2.get_class(glyph_id);
630     default:return 0;
631     }
632   }
633
634   inline bool sanitize (hb_sanitize_context_t *c) {
635     TRACE_SANITIZE ();
636     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
637     switch (u.format) {
638     case 1: return TRACE_RETURN (u.format1.sanitize (c));
639     case 2: return TRACE_RETURN (u.format2.sanitize (c));
640     default:return TRACE_RETURN (true);
641     }
642   }
643
644   inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
645     switch (u.format) {
646     case 1: return u.format1.intersects_class (glyphs, klass);
647     case 2: return u.format2.intersects_class (glyphs, klass);
648     default:return false;
649     }
650   }
651
652   private:
653   union {
654   USHORT                format;         /* Format identifier */
655   ClassDefFormat1       format1;
656   ClassDefFormat2       format2;
657   } u;
658   public:
659   DEFINE_SIZE_UNION (2, format);
660 };
661
662
663 /*
664  * Device Tables
665  */
666
667 struct Device
668 {
669
670   inline hb_position_t get_x_delta (hb_font_t *font) const
671   { return get_delta (font->x_ppem, font->x_scale); }
672
673   inline hb_position_t get_y_delta (hb_font_t *font) const
674   { return get_delta (font->y_ppem, font->y_scale); }
675
676   inline int get_delta (unsigned int ppem, int scale) const
677   {
678     if (!ppem) return 0;
679
680     int pixels = get_delta_pixels (ppem);
681
682     if (!pixels) return 0;
683
684     return pixels * (int64_t) scale / ppem;
685   }
686
687
688   inline int get_delta_pixels (unsigned int ppem_size) const
689   {
690     unsigned int f = deltaFormat;
691     if (unlikely (f < 1 || f > 3))
692       return 0;
693
694     if (ppem_size < startSize || ppem_size > endSize)
695       return 0;
696
697     unsigned int s = ppem_size - startSize;
698
699     unsigned int byte = deltaValue[s >> (4 - f)];
700     unsigned int bits = (byte >> (16 - (((s & ((1 << (4 - f)) - 1)) + 1) << f)));
701     unsigned int mask = (0xFFFF >> (16 - (1 << f)));
702
703     int delta = bits & mask;
704
705     if ((unsigned int) delta >= ((mask + 1) >> 1))
706       delta -= mask + 1;
707
708     return delta;
709   }
710
711   inline unsigned int get_size (void) const
712   {
713     unsigned int f = deltaFormat;
714     if (unlikely (f < 1 || f > 3 || startSize > endSize)) return 3 * USHORT::static_size;
715     return USHORT::static_size * (4 + ((endSize - startSize) >> (4 - f)));
716   }
717
718   inline bool sanitize (hb_sanitize_context_t *c) {
719     TRACE_SANITIZE ();
720     return TRACE_RETURN (c->check_struct (this) && c->check_range (this, this->get_size ()));
721   }
722
723   private:
724   USHORT        startSize;              /* Smallest size to correct--in ppem */
725   USHORT        endSize;                /* Largest size to correct--in ppem */
726   USHORT        deltaFormat;            /* Format of DeltaValue array data: 1, 2, or 3
727                                          * 1    Signed 2-bit value, 8 values per uint16
728                                          * 2    Signed 4-bit value, 4 values per uint16
729                                          * 3    Signed 8-bit value, 2 values per uint16
730                                          */
731   USHORT        deltaValue[VAR];        /* Array of compressed data */
732   public:
733   DEFINE_SIZE_ARRAY (6, deltaValue);
734 };
735
736
737
738 #endif /* HB_OT_LAYOUT_COMMON_PRIVATE_HH */