Rename SANITIZE_BASE to SANITIZE_WITH_BASE
[framework/uifw/harfbuzz.git] / src / hb-ot-layout-common-private.hh
1 /*
2  * Copyright (C) 2007,2008,2009  Red Hat, Inc.
3  *
4  *  This is part of HarfBuzz, a text shaping library.
5  *
6  * Permission is hereby granted, without written agreement and without
7  * license or royalty fees, to use, copy, modify, and distribute this
8  * software and its documentation for any purpose, provided that the
9  * above copyright notice and the following two paragraphs appear in
10  * all copies of this software.
11  *
12  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16  * DAMAGE.
17  *
18  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
21  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23  *
24  * Red Hat Author(s): Behdad Esfahbod
25  */
26
27 #ifndef HB_OT_LAYOUT_COMMON_PRIVATE_HH
28 #define HB_OT_LAYOUT_COMMON_PRIVATE_HH
29
30 #include "hb-ot-layout-private.h"
31
32 #include "hb-open-type-private.hh"
33
34
35 #define NO_CONTEXT              ((unsigned int) 0x110000)
36 #define NOT_COVERED             ((unsigned int) 0x110000)
37 #define MAX_NESTING_LEVEL       8
38
39
40 /*
41  *
42  * OpenType Layout Common Table Formats
43  *
44  */
45
46
47 /*
48  * Script, ScriptList, LangSys, Feature, FeatureList, Lookup, LookupList
49  */
50
51 template <typename Type>
52 struct Record
53 {
54   static inline unsigned int get_size () { return sizeof (Record<Type>); }
55
56   inline bool sanitize (SANITIZE_ARG_DEF, void *base) {
57     TRACE_SANITIZE ();
58     return SANITIZE_SELF ()
59         && SANITIZE_WITH_BASE (base, offset);
60   }
61
62   Tag           tag;            /* 4-byte Tag identifier */
63   OffsetTo<Type>
64                 offset;         /* Offset from beginning of object holding
65                                  * the Record */
66 };
67
68 template <typename Type>
69 struct RecordArrayOf : ArrayOf<Record<Type> > {
70   inline const Tag& get_tag (unsigned int i) const
71   {
72     if (unlikely (i >= this->len)) return Null(Tag);
73     return (*this)[i].tag;
74   }
75   inline unsigned int get_tags (unsigned int start_offset,
76                                 unsigned int *record_count /* IN/OUT */,
77                                 hb_tag_t     *record_tags /* OUT */) const
78   {
79     if (record_count) {
80       const Record<Type> *array = this->sub_array (start_offset, record_count);
81       unsigned int count = *record_count;
82       for (unsigned int i = 0; i < count; i++)
83         record_tags[i] = array[i].tag;
84     }
85     return this->len;
86   }
87   inline bool find_index (hb_tag_t tag, unsigned int *index) const
88   {
89     Tag t;
90     t.set (tag);
91     /* TODO: bsearch (need to sort in sanitize) */
92     const Record<Type> *a = this->array();
93     unsigned int count = this->len;
94     for (unsigned int i = 0; i < count; i++)
95     {
96       if (t == a[i].tag)
97       {
98         if (index) *index = i;
99         return true;
100       }
101     }
102     if (index) *index = NO_INDEX;
103     return false;
104   }
105 };
106
107 template <typename Type>
108 struct RecordListOf : RecordArrayOf<Type>
109 {
110   inline const Type& operator [] (unsigned int i) const
111   { return this+RecordArrayOf<Type>::operator [](i).offset; }
112
113   inline bool sanitize (SANITIZE_ARG_DEF) {
114     TRACE_SANITIZE ();
115     return RecordArrayOf<Type>::sanitize (SANITIZE_ARG, CharP(this));
116   }
117 };
118
119
120 struct IndexArray : ArrayOf<USHORT>
121 {
122   inline unsigned int operator [] (unsigned int i) const
123   {
124     if (unlikely (i >= this->len))
125       return NO_INDEX;
126     return this->array()[i];
127   }
128   inline unsigned int get_indexes (unsigned int start_offset,
129                                    unsigned int *_count /* IN/OUT */,
130                                    unsigned int *_indexes /* OUT */) const
131   {
132     if (_count) {
133       const USHORT *array = this->sub_array (start_offset, _count);
134       unsigned int count = *_count;
135       for (unsigned int i = 0; i < count; i++)
136         _indexes[i] = array[i];
137     }
138     return this->len;
139   }
140 };
141
142
143 struct Script;
144 struct LangSys;
145 struct Feature;
146
147
148 struct LangSys
149 {
150   inline unsigned int get_feature_count (void) const
151   { return featureIndex.len; }
152   inline hb_tag_t get_feature_index (unsigned int i) const
153   { return featureIndex[i]; }
154   inline unsigned int get_feature_indexes (unsigned int start_offset,
155                                            unsigned int *feature_count /* IN/OUT */,
156                                            unsigned int *feature_indexes /* OUT */) const
157   { return featureIndex.get_indexes (start_offset, feature_count, feature_indexes); }
158
159   inline bool has_required_feature (void) const { return reqFeatureIndex != 0xffff; }
160   inline int get_required_feature_index (void) const
161   {
162     if (reqFeatureIndex == 0xffff)
163       return NO_INDEX;
164    return reqFeatureIndex;;
165   }
166
167   inline bool sanitize (SANITIZE_ARG_DEF) {
168     TRACE_SANITIZE ();
169     return SANITIZE_SELF () && SANITIZE (featureIndex);
170   }
171
172   Offset        lookupOrder;    /* = Null (reserved for an offset to a
173                                  * reordering table) */
174   USHORT        reqFeatureIndex;/* Index of a feature required for this
175                                  * language system--if no required features
176                                  * = 0xFFFF */
177   IndexArray    featureIndex;   /* Array of indices into the FeatureList */
178 };
179 ASSERT_SIZE (LangSys, 6);
180 DEFINE_NULL_DATA (LangSys, 6, "\0\0\xFF\xFF");
181
182
183 struct Script
184 {
185   inline unsigned int get_lang_sys_count (void) const
186   { return langSys.len; }
187   inline const Tag& get_lang_sys_tag (unsigned int i) const
188   { return langSys.get_tag (i); }
189   inline unsigned int get_lang_sys_tags (unsigned int start_offset,
190                                          unsigned int *lang_sys_count /* IN/OUT */,
191                                          hb_tag_t     *lang_sys_tags /* OUT */) const
192   { return langSys.get_tags (start_offset, lang_sys_count, lang_sys_tags); }
193   inline const LangSys& get_lang_sys (unsigned int i) const
194   {
195     if (i == NO_INDEX) return get_default_lang_sys ();
196     return this+langSys[i].offset;
197   }
198   inline bool find_lang_sys_index (hb_tag_t tag, unsigned int *index) const
199   { return langSys.find_index (tag, index); }
200
201   inline bool has_default_lang_sys (void) const { return defaultLangSys != 0; }
202   inline const LangSys& get_default_lang_sys (void) const { return this+defaultLangSys; }
203
204   inline bool sanitize (SANITIZE_ARG_DEF) {
205     TRACE_SANITIZE ();
206     return SANITIZE_THIS (defaultLangSys)
207         && SANITIZE_THIS (langSys);
208   }
209
210   private:
211   OffsetTo<LangSys>
212                 defaultLangSys; /* Offset to DefaultLangSys table--from
213                                  * beginning of Script table--may be Null */
214   RecordArrayOf<LangSys>
215                 langSys;        /* Array of LangSysRecords--listed
216                                  * alphabetically by LangSysTag */
217 };
218 ASSERT_SIZE (Script, 4);
219
220 typedef RecordListOf<Script> ScriptList;
221 ASSERT_SIZE (ScriptList, 2);
222
223
224 struct Feature
225 {
226   inline unsigned int get_lookup_count (void) const
227   { return lookupIndex.len; }
228   inline hb_tag_t get_lookup_index (unsigned int i) const
229   { return lookupIndex[i]; }
230   inline unsigned int get_lookup_indexes (unsigned int start_index,
231                                           unsigned int *lookup_count /* IN/OUT */,
232                                           unsigned int *lookup_tags /* OUT */) const
233   { return lookupIndex.get_indexes (start_index, lookup_count, lookup_tags); }
234
235   inline bool sanitize (SANITIZE_ARG_DEF) {
236     TRACE_SANITIZE ();
237     return SANITIZE_SELF () && SANITIZE (lookupIndex);
238   }
239
240   /* LONGTERMTODO: implement get_feature_parameters() */
241   /* LONGTERMTODO: implement FeatureSize and other special features? */
242   Offset        featureParams;  /* Offset to Feature Parameters table (if one
243                                  * has been defined for the feature), relative
244                                  * to the beginning of the Feature Table; = Null
245                                  * if not required */
246   IndexArray     lookupIndex;   /* Array of LookupList indices */
247 };
248 ASSERT_SIZE (Feature, 4);
249
250 typedef RecordListOf<Feature> FeatureList;
251 ASSERT_SIZE (FeatureList, 2);
252
253
254 struct LookupFlag : USHORT
255 {
256   enum {
257     RightToLeft         = 0x0001u,
258     IgnoreBaseGlyphs    = 0x0002u,
259     IgnoreLigatures     = 0x0004u,
260     IgnoreMarks         = 0x0008u,
261     IgnoreFlags         = 0x000Eu,
262     UseMarkFilteringSet = 0x0010u,
263     Reserved            = 0x00E0u,
264     MarkAttachmentType  = 0xFF00u
265   };
266 };
267 ASSERT_SIZE (LookupFlag, 2);
268
269 struct Lookup
270 {
271   inline unsigned int get_subtable_count (void) const { return subTable.len; }
272
273   inline unsigned int get_type (void) const { return lookupType; }
274   inline unsigned int get_flag (void) const
275   {
276     unsigned int flag = lookupFlag;
277     if (unlikely (flag & LookupFlag::UseMarkFilteringSet))
278     {
279       const USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
280       flag += (markFilteringSet << 16);
281     }
282     return flag;
283   }
284
285   inline bool sanitize (SANITIZE_ARG_DEF) {
286     TRACE_SANITIZE ();
287     /* Real sanitize of the subtables is done by GSUB/GPOS/... */
288     if (!(SANITIZE_SELF () && likely (subTable.sanitize (SANITIZE_ARG)))) return false;
289     if (unlikely (lookupFlag & LookupFlag::UseMarkFilteringSet))
290     {
291       USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
292       if (!SANITIZE (markFilteringSet)) return false;
293     }
294     return true;
295   }
296
297   USHORT        lookupType;             /* Different enumerations for GSUB and GPOS */
298   USHORT        lookupFlag;             /* Lookup qualifiers */
299   ArrayOf<Offset>
300                 subTable;               /* Array of SubTables */
301   USHORT        markFilteringSetX[VAR]; /* Index (base 0) into GDEF mark glyph sets
302                                          * structure. This field is only present if bit
303                                          * UseMarkFilteringSet of lookup flags is set. */
304 };
305 ASSERT_SIZE_VAR (Lookup, 6, USHORT);
306
307 typedef OffsetListOf<Lookup> LookupList;
308 ASSERT_SIZE (LookupList, 2);
309
310
311 /*
312  * Coverage Table
313  */
314
315 struct CoverageFormat1
316 {
317   friend struct Coverage;
318
319   private:
320   inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
321   {
322     if (unlikely (glyph_id > 0xFFFF))
323       return NOT_COVERED;
324     GlyphID gid;
325     gid.set (glyph_id);
326     /* TODO: bsearch (need to sort in sanitize) */
327     unsigned int num_glyphs = glyphArray.len;
328     for (unsigned int i = 0; i < num_glyphs; i++)
329       if (gid == glyphArray[i])
330         return i;
331     return NOT_COVERED;
332   }
333
334   inline bool sanitize (SANITIZE_ARG_DEF) {
335     TRACE_SANITIZE ();
336     return SANITIZE (glyphArray);
337   }
338
339   private:
340   USHORT        coverageFormat; /* Format identifier--format = 1 */
341   ArrayOf<GlyphID>
342                 glyphArray;     /* Array of GlyphIDs--in numerical order */
343 };
344 ASSERT_SIZE (CoverageFormat1, 4);
345
346 struct CoverageRangeRecord
347 {
348   friend struct CoverageFormat2;
349
350   static inline unsigned int get_size () { return sizeof (CoverageRangeRecord); }
351
352   private:
353   inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
354   {
355     if (glyph_id >= start && glyph_id <= end)
356       return (unsigned int) startCoverageIndex + (glyph_id - start);
357     return NOT_COVERED;
358   }
359
360   public:
361   inline bool sanitize (SANITIZE_ARG_DEF) {
362     TRACE_SANITIZE ();
363     return SANITIZE_SELF ();
364   }
365
366   private:
367   GlyphID       start;                  /* First GlyphID in the range */
368   GlyphID       end;                    /* Last GlyphID in the range */
369   USHORT        startCoverageIndex;     /* Coverage Index of first GlyphID in
370                                          * range */
371 };
372 ASSERT_SIZE (CoverageRangeRecord, 6);
373 DEFINE_NULL_DATA (CoverageRangeRecord, 6, "\000\001");
374
375 struct CoverageFormat2
376 {
377   friend struct Coverage;
378
379   private:
380   inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
381   {
382     /* TODO: bsearch (need to sort in sanitize) */
383     unsigned int count = rangeRecord.len;
384     for (unsigned int i = 0; i < count; i++)
385     {
386       unsigned int coverage = rangeRecord[i].get_coverage (glyph_id);
387       if (coverage != NOT_COVERED)
388         return coverage;
389     }
390     return NOT_COVERED;
391   }
392
393   inline bool sanitize (SANITIZE_ARG_DEF) {
394     TRACE_SANITIZE ();
395     return SANITIZE (rangeRecord);
396   }
397
398   private:
399   USHORT        coverageFormat; /* Format identifier--format = 2 */
400   ArrayOf<CoverageRangeRecord>
401                 rangeRecord;    /* Array of glyph ranges--ordered by
402                                  * Start GlyphID. rangeCount entries
403                                  * long */
404 };
405 ASSERT_SIZE (CoverageFormat2, 4);
406
407 struct Coverage
408 {
409   inline unsigned int operator () (hb_codepoint_t glyph_id) const { return get_coverage (glyph_id); }
410
411   inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
412   {
413     switch (u.format) {
414     case 1: return u.format1->get_coverage(glyph_id);
415     case 2: return u.format2->get_coverage(glyph_id);
416     default:return NOT_COVERED;
417     }
418   }
419
420   inline bool sanitize (SANITIZE_ARG_DEF) {
421     TRACE_SANITIZE ();
422     if (!SANITIZE (u.format)) return false;
423     switch (u.format) {
424     case 1: return u.format1->sanitize (SANITIZE_ARG);
425     case 2: return u.format2->sanitize (SANITIZE_ARG);
426     default:return true;
427     }
428   }
429
430   private:
431   union {
432   USHORT                format;         /* Format identifier */
433   CoverageFormat1       format1[VAR];
434   CoverageFormat2       format2[VAR];
435   } u;
436 };
437
438
439 /*
440  * Class Definition Table
441  */
442
443 struct ClassDefFormat1
444 {
445   friend struct ClassDef;
446
447   private:
448   inline hb_ot_layout_class_t get_class (hb_codepoint_t glyph_id) const
449   {
450     if ((unsigned int) (glyph_id - startGlyph) < classValue.len)
451       return classValue[glyph_id - startGlyph];
452     return 0;
453   }
454
455   inline bool sanitize (SANITIZE_ARG_DEF) {
456     TRACE_SANITIZE ();
457     return SANITIZE_SELF () && SANITIZE (classValue);
458   }
459
460   USHORT        classFormat;            /* Format identifier--format = 1 */
461   GlyphID       startGlyph;             /* First GlyphID of the classValueArray */
462   ArrayOf<USHORT>
463                 classValue;             /* Array of Class Values--one per GlyphID */
464 };
465 ASSERT_SIZE (ClassDefFormat1, 6);
466
467 struct ClassRangeRecord
468 {
469   friend struct ClassDefFormat2;
470
471   static inline unsigned int get_size () { return sizeof (ClassRangeRecord); }
472
473   private:
474   inline hb_ot_layout_class_t get_class (hb_codepoint_t glyph_id) const
475   {
476     if (glyph_id >= start && glyph_id <= end)
477       return classValue;
478     return 0;
479   }
480
481   public:
482   inline bool sanitize (SANITIZE_ARG_DEF) {
483     TRACE_SANITIZE ();
484     return SANITIZE_SELF ();
485   }
486
487   private:
488   GlyphID       start;          /* First GlyphID in the range */
489   GlyphID       end;            /* Last GlyphID in the range */
490   USHORT        classValue;     /* Applied to all glyphs in the range */
491 };
492 ASSERT_SIZE (ClassRangeRecord, 6);
493 DEFINE_NULL_DATA (ClassRangeRecord, 6, "\000\001");
494
495 struct ClassDefFormat2
496 {
497   friend struct ClassDef;
498
499   private:
500   inline hb_ot_layout_class_t get_class (hb_codepoint_t glyph_id) const
501   {
502     /* TODO: bsearch (need to sort in sanitize) */
503     unsigned int count = rangeRecord.len;
504     for (unsigned int i = 0; i < count; i++)
505     {
506       int classValue = rangeRecord[i].get_class (glyph_id);
507       if (classValue > 0)
508         return classValue;
509     }
510     return 0;
511   }
512
513   inline bool sanitize (SANITIZE_ARG_DEF) {
514     TRACE_SANITIZE ();
515     return SANITIZE (rangeRecord);
516   }
517
518   USHORT        classFormat;    /* Format identifier--format = 2 */
519   ArrayOf<ClassRangeRecord>
520                 rangeRecord;    /* Array of glyph ranges--ordered by
521                                  * Start GlyphID */
522 };
523 ASSERT_SIZE (ClassDefFormat2, 4);
524
525 struct ClassDef
526 {
527   inline hb_ot_layout_class_t operator () (hb_codepoint_t glyph_id) const { return get_class (glyph_id); }
528
529   inline hb_ot_layout_class_t get_class (hb_codepoint_t glyph_id) const
530   {
531     switch (u.format) {
532     case 1: return u.format1->get_class(glyph_id);
533     case 2: return u.format2->get_class(glyph_id);
534     default:return 0;
535     }
536   }
537
538   inline bool sanitize (SANITIZE_ARG_DEF) {
539     TRACE_SANITIZE ();
540     if (!SANITIZE (u.format)) return false;
541     switch (u.format) {
542     case 1: return u.format1->sanitize (SANITIZE_ARG);
543     case 2: return u.format2->sanitize (SANITIZE_ARG);
544     default:return true;
545     }
546   }
547
548   private:
549   union {
550   USHORT                format;         /* Format identifier */
551   ClassDefFormat1       format1[VAR];
552   ClassDefFormat2       format2[VAR];
553   } u;
554 };
555
556
557 /*
558  * Device Tables
559  */
560
561 struct Device
562 {
563   inline int operator () (unsigned int ppem_size) const { return get_delta (ppem_size); }
564
565   inline int get_delta (unsigned int ppem_size) const
566   {
567     unsigned int f = deltaFormat;
568     if (unlikely (f < 1 || f > 3))
569       return 0;
570
571     if (ppem_size < startSize || ppem_size > endSize)
572       return 0;
573
574     unsigned int s = ppem_size - startSize;
575
576     unsigned int byte = deltaValue[s >> (4 - f)];
577     unsigned int bits = (byte >> (16 - (((s & ((1 << (4 - f)) - 1)) + 1) << f)));
578     unsigned int mask = (0xFFFF >> (16 - (1 << f)));
579
580     int delta = bits & mask;
581
582     if ((unsigned int) delta >= ((mask + 1) >> 1))
583       delta -= mask + 1;
584
585     return delta;
586   }
587
588   inline unsigned int get_size () const
589   {
590     unsigned int f = deltaFormat;
591     if (unlikely (f < 1 || f > 3 || startSize > endSize)) return 3 * USHORT::get_size ();
592     return USHORT::get_size () * (4 + ((endSize - startSize) >> (4 - f)));
593   }
594
595   inline bool sanitize (SANITIZE_ARG_DEF) {
596     TRACE_SANITIZE ();
597     return SANITIZE_SELF() && SANITIZE_MEM (this, this->get_size ());
598   }
599
600   private:
601   USHORT        startSize;              /* Smallest size to correct--in ppem */
602   USHORT        endSize;                /* Largest size to correct--in ppem */
603   USHORT        deltaFormat;            /* Format of DeltaValue array data: 1, 2, or 3
604                                          * 1    Signed 2-bit value, 8 values per uint16
605                                          * 2    Signed 4-bit value, 4 values per uint16
606                                          * 3    Signed 8-bit value, 2 values per uint16
607                                          */
608   USHORT        deltaValue[VAR];        /* Array of compressed data */
609 };
610 ASSERT_SIZE_VAR (Device, 6, USHORT);
611
612
613 #endif /* HB_OT_LAYOUT_COMMON_PRIVATE_HH */