[HB] Add comment
[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, an OpenType Layout engine 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-types-private.hh"
33
34
35 /*
36  *
37  * OpenType Layout Common Table Formats
38  *
39  */
40
41
42 /*
43  * Script, ScriptList, LangSys, Feature, FeatureList, Lookup, LookupList
44  */
45
46 template <typename Type>
47 struct Record
48 {
49   inline bool sanitize (SANITIZE_ARG_DEF, const char *base) {
50     /* Note: Only accept ASCII-visible tags (mind DEL)
51      * This is one of the few times (only time?) we check
52      * for data integrity, as opposed o just boundary checks
53      */
54     return (tag & 0x80808080) == 0 && offset.sanitize (SANITIZE_ARG, base);
55   }
56
57   Tag           tag;            /* 4-byte Tag identifier */
58   OffsetTo<Type>
59                 offset;         /* Offset from beginning of object holding
60                                  * the Record */
61 };
62
63 template <typename Type>
64 struct RecordArrayOf : ArrayOf<Record<Type> >
65 {
66   inline bool sanitize (SANITIZE_ARG_DEF, const char *base) {
67     if (!(SANITIZE (this->len) && SANITIZE_GET_SIZE())) return false;
68     unsigned int count = this->len;
69     for (unsigned int i = 0; i < count; i++)
70       if (!SANITIZE_THIS (this->array[i]))
71         return false;
72   }
73 };
74
75 template <typename Type>
76 struct RecordListOf : RecordArrayOf<Type>
77 {
78   inline const Type& operator [] (unsigned int i) const
79   {
80     if (HB_UNLIKELY (i >= this->len)) return Null(Type);
81     return this+this->array[i].offset;
82   }
83   inline const Tag& get_tag (unsigned int i) const
84   {
85     if (HB_UNLIKELY (i >= this->len)) return Null(Tag);
86     return this->array[i].tag;
87   }
88
89   inline bool sanitize (SANITIZE_ARG_DEF) {
90     return RecordArrayOf<Type>::sanitize (SANITIZE_ARG, (const char *) this);
91   }
92 };
93
94
95 struct Script;
96 struct LangSys;
97 struct Feature;
98
99
100 struct LangSys
101 {
102   inline const unsigned int get_feature_index (unsigned int i) const { return featureIndex[i]; }
103   inline unsigned int get_feature_count (void) const { return featureIndex.len; }
104
105   inline bool has_required_feature (void) const { return reqFeatureIndex != 0xffff; }
106   inline int get_required_feature_index (void) const
107   {
108     if (reqFeatureIndex == 0xffff)
109       return NO_INDEX;
110    return reqFeatureIndex;;
111   }
112
113   inline bool sanitize (SANITIZE_ARG_DEF) {
114     return SANITIZE_SELF () && SANITIZE (featureIndex);
115   }
116
117   Offset        lookupOrder;    /* = Null (reserved for an offset to a
118                                  * reordering table) */
119   USHORT        reqFeatureIndex;/* Index of a feature required for this
120                                  * language system--if no required features
121                                  * = 0xFFFF */
122   ArrayOf<USHORT>
123                 featureIndex;   /* Array of indices into the FeatureList */
124 };
125 ASSERT_SIZE_DATA (LangSys, 6, "\0\0\xFF\xFF");
126
127
128 struct Script
129 {
130   inline const LangSys& get_lang_sys (unsigned int i) const
131   {
132     if (i == NO_INDEX) return get_default_lang_sys ();
133     return this+langSys[i].offset;
134   }
135   inline unsigned int get_lang_sys_count (void) const { return langSys.len; }
136   inline const Tag& get_lang_sys_tag (unsigned int i) const { return langSys[i].tag; }
137
138   // LONGTERMTODO bsearch
139   DEFINE_TAG_FIND_INTERFACE (LangSys, lang_sys);        /* find_lang_sys_index (), get_lang_sys_by_tag (tag) */
140
141   inline bool has_default_lang_sys (void) const { return defaultLangSys != 0; }
142   inline const LangSys& get_default_lang_sys (void) const { return this+defaultLangSys; }
143
144   inline bool sanitize (SANITIZE_ARG_DEF) {
145     return SANITIZE_THIS (defaultLangSys) && SANITIZE_THIS (langSys);
146   }
147
148   private:
149   OffsetTo<LangSys>
150                 defaultLangSys; /* Offset to DefaultLangSys table--from
151                                  * beginning of Script table--may be Null */
152   RecordArrayOf<LangSys>
153                 langSys;        /* Array of LangSysRecords--listed
154                                  * alphabetically by LangSysTag */
155 };
156 ASSERT_SIZE (Script, 4);
157
158 typedef RecordListOf<Script> ScriptList;
159 ASSERT_SIZE (ScriptList, 2);
160
161
162 struct Feature
163 {
164   inline const unsigned int get_lookup_index (unsigned int i) const { return lookupIndex[i]; }
165   inline unsigned int get_lookup_count (void) const { return lookupIndex.len; }
166
167   inline bool sanitize (SANITIZE_ARG_DEF) {
168     return SANITIZE_SELF () && SANITIZE (lookupIndex);
169   }
170
171   /* TODO: implement get_feature_parameters() */
172   /* TODO: implement FeatureSize and other special features? */
173   Offset        featureParams;  /* Offset to Feature Parameters table (if one
174                                  * has been defined for the feature), relative
175                                  * to the beginning of the Feature Table; = Null
176                                  * if not required */
177   ArrayOf<USHORT>
178                 lookupIndex;    /* Array of LookupList indices */
179 };
180 ASSERT_SIZE (Feature, 4);
181
182 typedef RecordListOf<Feature> FeatureList;
183 ASSERT_SIZE (FeatureList, 2);
184
185
186 struct LookupFlag : USHORT
187 {
188   enum {
189     RightToLeft         = 0x0001u,
190     IgnoreBaseGlyphs    = 0x0002u,
191     IgnoreLigatures     = 0x0004u,
192     IgnoreMarks         = 0x0008u,
193     UseMarkFilteringSet = 0x0010u,
194     Reserved            = 0x00E0u,
195     MarkAttachmentType  = 0xFF00u,
196   };
197 };
198 ASSERT_SIZE (LookupFlag, 2);
199
200 struct LookupSubTable
201 {
202   inline bool sanitize (SANITIZE_ARG_DEF) {
203     return SANITIZE_SELF ();
204   }
205
206   private:
207   USHORT        format;         /* Subtable format.  Different for GSUB and GPOS */
208 };
209 ASSERT_SIZE (LookupSubTable, 2);
210
211 struct Lookup
212 {
213   inline const LookupSubTable& get_subtable (unsigned int i) const { return this+subTable[i]; }
214   inline unsigned int get_subtable_count (void) const { return subTable.len; }
215
216   inline unsigned int get_type (void) const { return lookupType; }
217   inline unsigned int get_flag (void) const
218   {
219     unsigned int flag = lookupFlag;
220     if (HB_UNLIKELY (flag & LookupFlag::UseMarkFilteringSet))
221     {
222       const USHORT &markFilteringSet = *(const USHORT*)
223                                         ((const char *) &subTable + subTable.get_size ());
224       flag += (markFilteringSet << 16);
225     }
226     return flag;
227   }
228
229   inline bool sanitize (SANITIZE_ARG_DEF) {
230     if (!(SANITIZE_SELF () && SANITIZE_THIS (subTable))) return false;
231     if (HB_UNLIKELY (lookupFlag & LookupFlag::UseMarkFilteringSet))
232     {
233       USHORT &markFilteringSet = *(USHORT*) ((char *) &subTable + subTable.get_size ());
234       if (!SANITIZE (markFilteringSet)) return false;
235     }
236     return true;
237   }
238
239   USHORT        lookupType;             /* Different enumerations for GSUB and GPOS */
240   USHORT        lookupFlag;             /* Lookup qualifiers */
241   OffsetArrayOf<LookupSubTable>
242                 subTable;               /* Array of SubTables */
243   USHORT        markFilteringSetX[0];   /* Index (base 0) into GDEF mark glyph sets
244                                          * structure. This field is only present if bit
245                                          * UseMarkFilteringSet of lookup flags is set. */
246 };
247 ASSERT_SIZE (Lookup, 6);
248
249 template <typename Type>
250 struct OffsetListOf : OffsetArrayOf<Type>
251 {
252   inline const Type& operator [] (unsigned int i) const
253   {
254     if (HB_UNLIKELY (i >= this->len)) return Null(Type);
255     return this+this->array[i];
256   }
257
258   inline bool sanitize (SANITIZE_ARG_DEF) {
259     return OffsetArrayOf<Type>::sanitize (SANITIZE_ARG, (const char *) this);
260   }
261 };
262
263 typedef OffsetListOf<Lookup> LookupList;
264 ASSERT_SIZE (LookupList, 2);
265
266
267 /*
268  * Coverage Table
269  */
270
271 struct CoverageFormat1
272 {
273   friend struct Coverage;
274
275   private:
276   inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
277   {
278     if (HB_UNLIKELY (glyph_id > 0xFFFF))
279       return NOT_COVERED;
280     GlyphID gid;
281     gid = glyph_id;
282     // TODO: bsearch
283     unsigned int num_glyphs = glyphArray.len;
284     for (unsigned int i = 0; i < num_glyphs; i++)
285       if (gid == glyphArray[i])
286         return i;
287     return NOT_COVERED;
288   }
289
290   inline bool sanitize (SANITIZE_ARG_DEF) {
291     return SANITIZE (glyphArray);
292   }
293
294   private:
295   USHORT        coverageFormat; /* Format identifier--format = 1 */
296   ArrayOf<GlyphID>
297                 glyphArray;     /* Array of GlyphIDs--in numerical order */
298 };
299 ASSERT_SIZE (CoverageFormat1, 4);
300
301 struct CoverageRangeRecord
302 {
303   friend struct CoverageFormat2;
304
305   private:
306   inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
307   {
308     if (glyph_id >= start && glyph_id <= end)
309       return (unsigned int) startCoverageIndex + (glyph_id - start);
310     return NOT_COVERED;
311   }
312
313   public:
314   inline bool sanitize (SANITIZE_ARG_DEF) {
315     return SANITIZE_SELF ();
316   }
317
318   private:
319   GlyphID       start;                  /* First GlyphID in the range */
320   GlyphID       end;                    /* Last GlyphID in the range */
321   USHORT        startCoverageIndex;     /* Coverage Index of first GlyphID in
322                                          * range */
323 };
324 ASSERT_SIZE_DATA (CoverageRangeRecord, 6, "\000\001");
325
326 struct CoverageFormat2
327 {
328   friend struct Coverage;
329
330   private:
331   inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
332   {
333     // TODO: bsearch
334     unsigned int count = rangeRecord.len;
335     for (unsigned int i = 0; i < count; i++)
336     {
337       unsigned int coverage = rangeRecord[i].get_coverage (glyph_id);
338       if (coverage != NOT_COVERED)
339         return coverage;
340     }
341     return NOT_COVERED;
342   }
343
344   inline bool sanitize (SANITIZE_ARG_DEF) {
345     return SANITIZE (rangeRecord);
346   }
347
348   private:
349   USHORT        coverageFormat; /* Format identifier--format = 2 */
350   ArrayOf<CoverageRangeRecord>
351                 rangeRecord;    /* Array of glyph ranges--ordered by
352                                  * Start GlyphID. rangeCount entries
353                                  * long */
354 };
355 ASSERT_SIZE (CoverageFormat2, 4);
356
357 struct Coverage
358 {
359   inline unsigned int operator() (hb_codepoint_t glyph_id) const { return get_coverage (glyph_id); }
360
361   unsigned int get_coverage (hb_codepoint_t glyph_id) const
362   {
363     switch (u.format) {
364     case 1: return u.format1->get_coverage(glyph_id);
365     case 2: return u.format2->get_coverage(glyph_id);
366     default:return NOT_COVERED;
367     }
368   }
369
370   inline bool sanitize (SANITIZE_ARG_DEF) {
371     if (!SANITIZE (u.format)) return false;
372     switch (u.format) {
373     case 1: return u.format1->sanitize (SANITIZE_ARG);
374     case 2: return u.format2->sanitize (SANITIZE_ARG);
375     default:return true;
376     }
377   }
378
379   private:
380   union {
381   USHORT                format;         /* Format identifier */
382   CoverageFormat1       format1[];
383   CoverageFormat2       format2[];
384   } u;
385 };
386 ASSERT_SIZE (Coverage, 2);
387
388
389 /*
390  * Class Definition Table
391  */
392
393 struct ClassDefFormat1
394 {
395   friend struct ClassDef;
396
397   private:
398   inline hb_ot_layout_class_t get_class (hb_codepoint_t glyph_id) const
399   {
400     if ((unsigned int) (glyph_id - startGlyph) < classValue.len)
401       return classValue[glyph_id - startGlyph];
402     return 0;
403   }
404
405   inline bool sanitize (SANITIZE_ARG_DEF) {
406     return SANITIZE_SELF () && SANITIZE (classValue);
407   }
408
409   USHORT        classFormat;            /* Format identifier--format = 1 */
410   GlyphID       startGlyph;             /* First GlyphID of the classValueArray */
411   ArrayOf<USHORT>
412                 classValue;             /* Array of Class Values--one per GlyphID */
413 };
414 ASSERT_SIZE (ClassDefFormat1, 6);
415
416 struct ClassRangeRecord
417 {
418   friend struct ClassDefFormat2;
419
420   private:
421   inline hb_ot_layout_class_t get_class (hb_codepoint_t glyph_id) const
422   {
423     if (glyph_id >= start && glyph_id <= end)
424       return classValue;
425     return 0;
426   }
427
428   public:
429   inline bool sanitize (SANITIZE_ARG_DEF) {
430     return SANITIZE_SELF ();
431   }
432
433   private:
434   GlyphID       start;          /* First GlyphID in the range */
435   GlyphID       end;            /* Last GlyphID in the range */
436   USHORT        classValue;     /* Applied to all glyphs in the range */
437 };
438 ASSERT_SIZE_DATA (ClassRangeRecord, 6, "\000\001");
439
440 struct ClassDefFormat2
441 {
442   friend struct ClassDef;
443
444   private:
445   inline hb_ot_layout_class_t get_class (hb_codepoint_t glyph_id) const
446   {
447     // TODO: bsearch
448     unsigned int count = rangeRecord.len;
449     for (unsigned int i = 0; i < count; i++)
450     {
451       int classValue = rangeRecord[i].get_class (glyph_id);
452       if (classValue > 0)
453         return classValue;
454     }
455     return 0;
456   }
457
458   inline bool sanitize (SANITIZE_ARG_DEF) {
459     return SANITIZE (rangeRecord);
460   }
461
462   USHORT        classFormat;    /* Format identifier--format = 2 */
463   ArrayOf<ClassRangeRecord>
464                 rangeRecord;    /* Array of glyph ranges--ordered by
465                                  * Start GlyphID */
466 };
467 ASSERT_SIZE (ClassDefFormat2, 4);
468
469 struct ClassDef
470 {
471   inline unsigned int operator() (hb_codepoint_t glyph_id) const { return get_class (glyph_id); }
472
473   hb_ot_layout_class_t get_class (hb_codepoint_t glyph_id) const
474   {
475     switch (u.format) {
476     case 1: return u.format1->get_class(glyph_id);
477     case 2: return u.format2->get_class(glyph_id);
478     default:return 0;
479     }
480   }
481
482   inline bool sanitize (SANITIZE_ARG_DEF) {
483     if (!SANITIZE (u.format)) return false;
484     switch (u.format) {
485     case 1: return u.format1->sanitize (SANITIZE_ARG);
486     case 2: return u.format2->sanitize (SANITIZE_ARG);
487     default:return true;
488     }
489   }
490
491   private:
492   union {
493   USHORT                format;         /* Format identifier */
494   ClassDefFormat1       format1[];
495   ClassDefFormat2       format2[];
496   } u;
497 };
498 ASSERT_SIZE (ClassDef, 2);
499
500
501 /*
502  * Device Tables
503  */
504
505 struct Device
506 {
507   int get_delta (unsigned int ppem_size) const
508   {
509     unsigned int f = deltaFormat;
510     if (HB_UNLIKELY (f < 1 || f > 3))
511       return 0;
512
513     if (ppem_size < startSize || ppem_size > endSize)
514       return 0;
515
516     unsigned int s = ppem_size - startSize;
517
518     unsigned int byte = deltaValue[s >> (4 - f)];
519     unsigned int bits = (byte >> (16 - (((s & ((1 << (4 - f)) - 1)) + 1) << f)));
520     unsigned int mask = (0xFFFF >> (16 - (1 << f)));
521
522     int delta = bits & mask;
523
524     if (delta >= ((mask + 1) >> 1))
525       delta -= mask + 1;
526
527     return delta;
528   }
529
530   inline int operator() (unsigned int ppem_size) const { return get_delta (ppem_size); }
531
532   private:
533   USHORT        startSize;      /* Smallest size to correct--in ppem */
534   USHORT        endSize;        /* Largest size to correct--in ppem */
535   USHORT        deltaFormat;    /* Format of DeltaValue array data: 1, 2, or 3 */
536   USHORT        deltaValue[];   /* Array of compressed data */
537 };
538 ASSERT_SIZE (Device, 6);
539
540
541 #endif /* HB_OT_LAYOUT_COMMON_PRIVATE_HH */