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