hb-ot-layout-common-private.hh revision bb029af943faa9905e652d58856998687e60c31d
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
51template <typename Type>
52struct 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
68template <typename Type>
69struct 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
107template <typename Type>
108struct 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
120struct 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
143struct Script;
144struct LangSys;
145struct Feature;
146
147
148struct 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};
179ASSERT_SIZE (LangSys, 6);
180DEFINE_NULL_DATA (LangSys, 6, "\0\0\xFF\xFF");
181
182
183struct 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_WITH_BASE (this, defaultLangSys)
207	&& SANITIZE_WITH_BASE (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};
218ASSERT_SIZE (Script, 4);
219
220typedef RecordListOf<Script> ScriptList;
221ASSERT_SIZE (ScriptList, 2);
222
223
224struct 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};
248ASSERT_SIZE (Feature, 4);
249
250typedef RecordListOf<Feature> FeatureList;
251ASSERT_SIZE (FeatureList, 2);
252
253
254struct 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};
267ASSERT_SIZE (LookupFlag, 2);
268
269struct 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};
305ASSERT_SIZE_VAR (Lookup, 6, USHORT);
306
307typedef OffsetListOf<Lookup> LookupList;
308ASSERT_SIZE (LookupList, 2);
309
310
311/*
312 * Coverage Table
313 */
314
315struct 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};
344ASSERT_SIZE (CoverageFormat1, 4);
345
346struct 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};
372ASSERT_SIZE (CoverageRangeRecord, 6);
373DEFINE_NULL_DATA (CoverageRangeRecord, 6, "\000\001");
374
375struct 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};
405ASSERT_SIZE (CoverageFormat2, 4);
406
407struct 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
443struct 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};
465ASSERT_SIZE (ClassDefFormat1, 6);
466
467struct 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};
492ASSERT_SIZE (ClassRangeRecord, 6);
493DEFINE_NULL_DATA (ClassRangeRecord, 6, "\000\001");
494
495struct 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};
523ASSERT_SIZE (ClassDefFormat2, 4);
524
525struct 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
561struct 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};
610ASSERT_SIZE_VAR (Device, 6, USHORT);
611
612
613#endif /* HB_OT_LAYOUT_COMMON_PRIVATE_HH */
614