Fix warning
[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   inline bool sanitize (hb_sanitize_context_t *context, void *base) {
55     TRACE_SANITIZE ();
56     return context->check_struct (this)
57         && offset.sanitize (context, base);
58   }
59
60   Tag           tag;            /* 4-byte Tag identifier */
61   OffsetTo<Type>
62                 offset;         /* Offset from beginning of object holding
63                                  * the Record */
64   public:
65   DEFINE_SIZE_STATIC (6);
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 = Index::NOT_FOUND_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 (hb_sanitize_context_t *context) {
114     TRACE_SANITIZE ();
115     return RecordArrayOf<Type>::sanitize (context, this);
116   }
117 };
118
119
120 struct IndexArray : ArrayOf<Index>
121 {
122   inline unsigned int get_indexes (unsigned int start_offset,
123                                    unsigned int *_count /* IN/OUT */,
124                                    unsigned int *_indexes /* OUT */) const
125   {
126     if (_count) {
127       const USHORT *array = this->sub_array (start_offset, _count);
128       unsigned int count = *_count;
129       for (unsigned int i = 0; i < count; i++)
130         _indexes[i] = array[i];
131     }
132     return this->len;
133   }
134 };
135
136
137 struct Script;
138 struct LangSys;
139 struct Feature;
140
141
142 struct LangSys
143 {
144   inline unsigned int get_feature_count (void) const
145   { return featureIndex.len; }
146   inline hb_tag_t get_feature_index (unsigned int i) const
147   { return featureIndex[i]; }
148   inline unsigned int get_feature_indexes (unsigned int start_offset,
149                                            unsigned int *feature_count /* IN/OUT */,
150                                            unsigned int *feature_indexes /* OUT */) const
151   { return featureIndex.get_indexes (start_offset, feature_count, feature_indexes); }
152
153   inline bool has_required_feature (void) const { return reqFeatureIndex != 0xffff; }
154   inline unsigned int get_required_feature_index (void) const
155   {
156     if (reqFeatureIndex == 0xffff)
157       return Index::NOT_FOUND_INDEX;
158    return reqFeatureIndex;;
159   }
160
161   inline bool sanitize (hb_sanitize_context_t *context) {
162     TRACE_SANITIZE ();
163     return context->check_struct (this)
164         && featureIndex.sanitize (context);
165   }
166
167   Offset        lookupOrder;    /* = Null (reserved for an offset to a
168                                  * reordering table) */
169   USHORT        reqFeatureIndex;/* Index of a feature required for this
170                                  * language system--if no required features
171                                  * = 0xFFFF */
172   IndexArray    featureIndex;   /* Array of indices into the FeatureList */
173   public:
174   DEFINE_SIZE_ARRAY (6, featureIndex);
175 };
176 DEFINE_NULL_DATA (LangSys, "\0\0\xFF\xFF");
177
178
179 struct Script
180 {
181   inline unsigned int get_lang_sys_count (void) const
182   { return langSys.len; }
183   inline const Tag& get_lang_sys_tag (unsigned int i) const
184   { return langSys.get_tag (i); }
185   inline unsigned int get_lang_sys_tags (unsigned int start_offset,
186                                          unsigned int *lang_sys_count /* IN/OUT */,
187                                          hb_tag_t     *lang_sys_tags /* OUT */) const
188   { return langSys.get_tags (start_offset, lang_sys_count, lang_sys_tags); }
189   inline const LangSys& get_lang_sys (unsigned int i) const
190   {
191     if (i == Index::NOT_FOUND_INDEX) return get_default_lang_sys ();
192     return this+langSys[i].offset;
193   }
194   inline bool find_lang_sys_index (hb_tag_t tag, unsigned int *index) const
195   { return langSys.find_index (tag, index); }
196
197   inline bool has_default_lang_sys (void) const { return defaultLangSys != 0; }
198   inline const LangSys& get_default_lang_sys (void) const { return this+defaultLangSys; }
199
200   inline bool sanitize (hb_sanitize_context_t *context) {
201     TRACE_SANITIZE ();
202     return defaultLangSys.sanitize (context, this)
203         && langSys.sanitize (context, this);
204   }
205
206   private:
207   OffsetTo<LangSys>
208                 defaultLangSys; /* Offset to DefaultLangSys table--from
209                                  * beginning of Script table--may be Null */
210   RecordArrayOf<LangSys>
211                 langSys;        /* Array of LangSysRecords--listed
212                                  * alphabetically by LangSysTag */
213   public:
214   DEFINE_SIZE_ARRAY (4, langSys);
215 };
216
217 typedef RecordListOf<Script> ScriptList;
218
219
220 struct Feature
221 {
222   inline unsigned int get_lookup_count (void) const
223   { return lookupIndex.len; }
224   inline hb_tag_t get_lookup_index (unsigned int i) const
225   { return lookupIndex[i]; }
226   inline unsigned int get_lookup_indexes (unsigned int start_index,
227                                           unsigned int *lookup_count /* IN/OUT */,
228                                           unsigned int *lookup_tags /* OUT */) const
229   { return lookupIndex.get_indexes (start_index, lookup_count, lookup_tags); }
230
231   inline bool sanitize (hb_sanitize_context_t *context) {
232     TRACE_SANITIZE ();
233     return context->check_struct (this)
234         && lookupIndex.sanitize (context);
235   }
236
237   /* LONGTERMTODO: implement get_feature_parameters() */
238   /* LONGTERMTODO: implement FeatureSize and other special features? */
239   Offset        featureParams;  /* Offset to Feature Parameters table (if one
240                                  * has been defined for the feature), relative
241                                  * to the beginning of the Feature Table; = Null
242                                  * if not required */
243   IndexArray     lookupIndex;   /* Array of LookupList indices */
244   public:
245   DEFINE_SIZE_ARRAY (4, lookupIndex);
246 };
247
248 typedef RecordListOf<Feature> FeatureList;
249
250
251 struct LookupFlag : USHORT
252 {
253   enum {
254     RightToLeft         = 0x0001u,
255     IgnoreBaseGlyphs    = 0x0002u,
256     IgnoreLigatures     = 0x0004u,
257     IgnoreMarks         = 0x0008u,
258     IgnoreFlags         = 0x000Eu,
259     UseMarkFilteringSet = 0x0010u,
260     Reserved            = 0x00E0u,
261     MarkAttachmentType  = 0xFF00u
262   };
263   public:
264   DEFINE_SIZE_STATIC (2);
265 };
266
267 struct Lookup
268 {
269   inline unsigned int get_subtable_count (void) const { return subTable.len; }
270
271   inline unsigned int get_type (void) const { return lookupType; }
272   inline unsigned int get_flag (void) const
273   {
274     unsigned int flag = lookupFlag;
275     if (unlikely (flag & LookupFlag::UseMarkFilteringSet))
276     {
277       const USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
278       flag += (markFilteringSet << 16);
279     }
280     return flag;
281   }
282
283   inline bool sanitize (hb_sanitize_context_t *context) {
284     TRACE_SANITIZE ();
285     /* Real sanitize of the subtables is done by GSUB/GPOS/... */
286     if (!(context->check_struct (this)
287        && likely (subTable.sanitize (context)))) return false;
288     if (unlikely (lookupFlag & LookupFlag::UseMarkFilteringSet))
289     {
290       USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
291       if (!markFilteringSet.sanitize (context)) return false;
292     }
293     return true;
294   }
295
296   USHORT        lookupType;             /* Different enumerations for GSUB and GPOS */
297   USHORT        lookupFlag;             /* Lookup qualifiers */
298   ArrayOf<Offset>
299                 subTable;               /* Array of SubTables */
300   USHORT        markFilteringSetX[VAR]; /* Index (base 0) into GDEF mark glyph sets
301                                          * structure. This field is only present if bit
302                                          * UseMarkFilteringSet of lookup flags is set. */
303   public:
304   DEFINE_SIZE_ARRAY2 (6, subTable, markFilteringSetX);
305 };
306
307 typedef OffsetListOf<Lookup> LookupList;
308
309
310 /*
311  * Coverage Table
312  */
313
314 struct CoverageFormat1
315 {
316   friend struct Coverage;
317
318   private:
319   inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
320   {
321     if (unlikely (glyph_id > 0xFFFF))
322       return NOT_COVERED;
323     GlyphID gid;
324     gid.set (glyph_id);
325     /* TODO: bsearch (need to sort in sanitize) */
326     unsigned int num_glyphs = glyphArray.len;
327     for (unsigned int i = 0; i < num_glyphs; i++)
328       if (gid == glyphArray[i])
329         return i;
330     return NOT_COVERED;
331   }
332
333   inline bool sanitize (hb_sanitize_context_t *context) {
334     TRACE_SANITIZE ();
335     return glyphArray.sanitize (context);
336   }
337
338   private:
339   USHORT        coverageFormat; /* Format identifier--format = 1 */
340   ArrayOf<GlyphID>
341                 glyphArray;     /* Array of GlyphIDs--in numerical order */
342   public:
343   DEFINE_SIZE_ARRAY (4, glyphArray);
344 };
345
346 struct CoverageRangeRecord
347 {
348   friend struct CoverageFormat2;
349
350   private:
351   inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
352   {
353     if (glyph_id >= start && glyph_id <= end)
354       return (unsigned int) startCoverageIndex + (glyph_id - start);
355     return NOT_COVERED;
356   }
357
358   public:
359   inline bool sanitize (hb_sanitize_context_t *context) {
360     TRACE_SANITIZE ();
361     return context->check_struct (this);
362   }
363
364   private:
365   GlyphID       start;                  /* First GlyphID in the range */
366   GlyphID       end;                    /* Last GlyphID in the range */
367   USHORT        startCoverageIndex;     /* Coverage Index of first GlyphID in
368                                          * range */
369   public:
370   DEFINE_SIZE_STATIC (6);
371 };
372 DEFINE_NULL_DATA (CoverageRangeRecord, "\000\001");
373
374 struct CoverageFormat2
375 {
376   friend struct Coverage;
377
378   private:
379   inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
380   {
381     /* TODO: bsearch (need to sort in sanitize) */
382     unsigned int count = rangeRecord.len;
383     for (unsigned int i = 0; i < count; i++)
384     {
385       unsigned int coverage = rangeRecord[i].get_coverage (glyph_id);
386       if (coverage != NOT_COVERED)
387         return coverage;
388     }
389     return NOT_COVERED;
390   }
391
392   inline bool sanitize (hb_sanitize_context_t *context) {
393     TRACE_SANITIZE ();
394     return rangeRecord.sanitize (context);
395   }
396
397   private:
398   USHORT        coverageFormat; /* Format identifier--format = 2 */
399   ArrayOf<CoverageRangeRecord>
400                 rangeRecord;    /* Array of glyph ranges--ordered by
401                                  * Start GlyphID. rangeCount entries
402                                  * long */
403   public:
404   DEFINE_SIZE_ARRAY (4, rangeRecord);
405 };
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 (hb_sanitize_context_t *context) {
421     TRACE_SANITIZE ();
422     if (!u.format.sanitize (context)) return false;
423     switch (u.format) {
424     case 1: return u.format1.sanitize (context);
425     case 2: return u.format2.sanitize (context);
426     default:return true;
427     }
428   }
429
430   private:
431   union {
432   USHORT                format;         /* Format identifier */
433   CoverageFormat1       format1;
434   CoverageFormat2       format2;
435   } u;
436   public:
437   DEFINE_SIZE_UNION (2, format);
438 };
439
440
441 /*
442  * Class Definition Table
443  */
444
445 struct ClassDefFormat1
446 {
447   friend struct ClassDef;
448
449   private:
450   inline hb_ot_layout_class_t get_class (hb_codepoint_t glyph_id) const
451   {
452     if ((unsigned int) (glyph_id - startGlyph) < classValue.len)
453       return classValue[glyph_id - startGlyph];
454     return 0;
455   }
456
457   inline bool sanitize (hb_sanitize_context_t *context) {
458     TRACE_SANITIZE ();
459     return context->check_struct (this)
460         && classValue.sanitize (context);
461   }
462
463   USHORT        classFormat;            /* Format identifier--format = 1 */
464   GlyphID       startGlyph;             /* First GlyphID of the classValueArray */
465   ArrayOf<USHORT>
466                 classValue;             /* Array of Class Values--one per GlyphID */
467   public:
468   DEFINE_SIZE_ARRAY (6, classValue);
469 };
470
471 struct ClassRangeRecord
472 {
473   friend struct ClassDefFormat2;
474
475   private:
476   inline hb_ot_layout_class_t get_class (hb_codepoint_t glyph_id) const
477   {
478     if (glyph_id >= start && glyph_id <= end)
479       return classValue;
480     return 0;
481   }
482
483   public:
484   inline bool sanitize (hb_sanitize_context_t *context) {
485     TRACE_SANITIZE ();
486     return context->check_struct (this);
487   }
488
489   private:
490   GlyphID       start;          /* First GlyphID in the range */
491   GlyphID       end;            /* Last GlyphID in the range */
492   USHORT        classValue;     /* Applied to all glyphs in the range */
493   public:
494   DEFINE_SIZE_STATIC (6);
495 };
496 DEFINE_NULL_DATA (ClassRangeRecord, "\000\001");
497
498 struct ClassDefFormat2
499 {
500   friend struct ClassDef;
501
502   private:
503   inline hb_ot_layout_class_t get_class (hb_codepoint_t glyph_id) const
504   {
505     /* TODO: bsearch (need to sort in sanitize) */
506     unsigned int count = rangeRecord.len;
507     for (unsigned int i = 0; i < count; i++)
508     {
509       int classValue = rangeRecord[i].get_class (glyph_id);
510       if (classValue > 0)
511         return classValue;
512     }
513     return 0;
514   }
515
516   inline bool sanitize (hb_sanitize_context_t *context) {
517     TRACE_SANITIZE ();
518     return rangeRecord.sanitize (context);
519   }
520
521   USHORT        classFormat;    /* Format identifier--format = 2 */
522   ArrayOf<ClassRangeRecord>
523                 rangeRecord;    /* Array of glyph ranges--ordered by
524                                  * Start GlyphID */
525   public:
526   DEFINE_SIZE_ARRAY (4, rangeRecord);
527 };
528
529 struct ClassDef
530 {
531   inline hb_ot_layout_class_t operator () (hb_codepoint_t glyph_id) const { return get_class (glyph_id); }
532
533   inline hb_ot_layout_class_t get_class (hb_codepoint_t glyph_id) const
534   {
535     switch (u.format) {
536     case 1: return u.format1.get_class(glyph_id);
537     case 2: return u.format2.get_class(glyph_id);
538     default:return 0;
539     }
540   }
541
542   inline bool sanitize (hb_sanitize_context_t *context) {
543     TRACE_SANITIZE ();
544     if (!u.format.sanitize (context)) return false;
545     switch (u.format) {
546     case 1: return u.format1.sanitize (context);
547     case 2: return u.format2.sanitize (context);
548     default:return true;
549     }
550   }
551
552   private:
553   union {
554   USHORT                format;         /* Format identifier */
555   ClassDefFormat1       format1;
556   ClassDefFormat2       format2;
557   } u;
558   public:
559   DEFINE_SIZE_UNION (2, format);
560 };
561
562
563 /*
564  * Device Tables
565  */
566
567 struct Device
568 {
569   inline int operator () (unsigned int ppem_size) const { return get_delta (ppem_size); }
570
571   inline int get_delta (unsigned int ppem_size) const
572   {
573     unsigned int f = deltaFormat;
574     if (unlikely (f < 1 || f > 3))
575       return 0;
576
577     if (ppem_size < startSize || ppem_size > endSize)
578       return 0;
579
580     unsigned int s = ppem_size - startSize;
581
582     unsigned int byte = deltaValue[s >> (4 - f)];
583     unsigned int bits = (byte >> (16 - (((s & ((1 << (4 - f)) - 1)) + 1) << f)));
584     unsigned int mask = (0xFFFF >> (16 - (1 << f)));
585
586     int delta = bits & mask;
587
588     if ((unsigned int) delta >= ((mask + 1) >> 1))
589       delta -= mask + 1;
590
591     return delta;
592   }
593
594   inline unsigned int get_size () const
595   {
596     unsigned int f = deltaFormat;
597     if (unlikely (f < 1 || f > 3 || startSize > endSize)) return 3 * USHORT::static_size;
598     return USHORT::static_size * (4 + ((endSize - startSize) >> (4 - f)));
599   }
600
601   inline bool sanitize (hb_sanitize_context_t *context) {
602     TRACE_SANITIZE ();
603     return context->check_struct (this)
604         && context->check_range (this, this->get_size ());
605   }
606
607   private:
608   USHORT        startSize;              /* Smallest size to correct--in ppem */
609   USHORT        endSize;                /* Largest size to correct--in ppem */
610   USHORT        deltaFormat;            /* Format of DeltaValue array data: 1, 2, or 3
611                                          * 1    Signed 2-bit value, 8 values per uint16
612                                          * 2    Signed 4-bit value, 4 values per uint16
613                                          * 3    Signed 8-bit value, 2 values per uint16
614                                          */
615   USHORT        deltaValue[VAR];        /* Array of compressed data */
616   public:
617   DEFINE_SIZE_ARRAY (6, deltaValue);
618 };
619
620
621 #endif /* HB_OT_LAYOUT_COMMON_PRIVATE_HH */