hb-ot-layout-common-private.hh revision abcfe9b59b4475eb02dd679aac4bc59616713b28
1/*
2 * Copyright © 2007,2008,2009  Red Hat, Inc.
3 * Copyright © 2010  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
34#include "hb-open-type-private.hh"
35
36
37#define NO_CONTEXT		((unsigned int) 0x110000)
38#define NOT_COVERED		((unsigned int) 0x110000)
39#define MAX_NESTING_LEVEL	8
40
41HB_BEGIN_DECLS
42HB_END_DECLS
43
44
45/*
46 *
47 * OpenType Layout Common Table Formats
48 *
49 */
50
51
52/*
53 * Script, ScriptList, LangSys, Feature, FeatureList, Lookup, LookupList
54 */
55
56template <typename Type>
57struct Record
58{
59  inline int cmp (hb_tag_t a) const {
60    return tag.cmp (a);
61  }
62
63  inline bool sanitize (hb_sanitize_context_t *c, void *base) {
64    TRACE_SANITIZE ();
65    return c->check_struct (this)
66	&& offset.sanitize (c, base);
67  }
68
69  Tag		tag;		/* 4-byte Tag identifier */
70  OffsetTo<Type>
71		offset;		/* Offset from beginning of object holding
72				 * the Record */
73  public:
74  DEFINE_SIZE_STATIC (6);
75};
76
77template <typename Type>
78struct RecordArrayOf : SortedArrayOf<Record<Type> > {
79  inline const Tag& get_tag (unsigned int i) const
80  {
81    /* We cheat slightly and don't define separate Null objects
82     * for Record types.  Instead, we return the correct Null(Tag)
83     * here. */
84    if (unlikely (i >= this->len)) return Null(Tag);
85    return (*this)[i].tag;
86  }
87  inline unsigned int get_tags (unsigned int start_offset,
88				unsigned int *record_count /* IN/OUT */,
89				hb_tag_t     *record_tags /* OUT */) const
90  {
91    if (record_count) {
92      const Record<Type> *array = this->sub_array (start_offset, record_count);
93      unsigned int count = *record_count;
94      for (unsigned int i = 0; i < count; i++)
95	record_tags[i] = array[i].tag;
96    }
97    return this->len;
98  }
99  inline bool find_index (hb_tag_t tag, unsigned int *index) const
100  {
101    int i = this->search (tag);
102    if (i != -1) {
103        if (index) *index = i;
104        return true;
105    } else {
106      if (index) *index = Index::NOT_FOUND_INDEX;
107      return false;
108    }
109  }
110};
111
112template <typename Type>
113struct RecordListOf : RecordArrayOf<Type>
114{
115  inline const Type& operator [] (unsigned int i) const
116  { return this+RecordArrayOf<Type>::operator [](i).offset; }
117
118  inline bool sanitize (hb_sanitize_context_t *c) {
119    TRACE_SANITIZE ();
120    return RecordArrayOf<Type>::sanitize (c, this);
121  }
122};
123
124
125struct RangeRecord
126{
127  inline int cmp (hb_codepoint_t g) const {
128    hb_codepoint_t a = start, b = end;
129    return g < a ? -1 : g <= b ? 0 : +1 ;
130  }
131
132  inline bool sanitize (hb_sanitize_context_t *c) {
133    TRACE_SANITIZE ();
134    return c->check_struct (this);
135  }
136
137  GlyphID	start;		/* First GlyphID in the range */
138  GlyphID	end;		/* Last GlyphID in the range */
139  USHORT	value;		/* Value */
140  public:
141  DEFINE_SIZE_STATIC (6);
142};
143DEFINE_NULL_DATA (RangeRecord, "\000\001");
144
145
146struct IndexArray : ArrayOf<Index>
147{
148  inline unsigned int get_indexes (unsigned int start_offset,
149				   unsigned int *_count /* IN/OUT */,
150				   unsigned int *_indexes /* OUT */) const
151  {
152    if (_count) {
153      const USHORT *array = this->sub_array (start_offset, _count);
154      unsigned int count = *_count;
155      for (unsigned int i = 0; i < count; i++)
156	_indexes[i] = array[i];
157    }
158    return this->len;
159  }
160};
161
162
163struct Script;
164struct LangSys;
165struct Feature;
166
167
168struct LangSys
169{
170  inline unsigned int get_feature_count (void) const
171  { return featureIndex.len; }
172  inline hb_tag_t get_feature_index (unsigned int i) const
173  { return featureIndex[i]; }
174  inline unsigned int get_feature_indexes (unsigned int start_offset,
175					   unsigned int *feature_count /* IN/OUT */,
176					   unsigned int *feature_indexes /* OUT */) const
177  { return featureIndex.get_indexes (start_offset, feature_count, feature_indexes); }
178
179  inline bool has_required_feature (void) const { return reqFeatureIndex != 0xffff; }
180  inline unsigned int get_required_feature_index (void) const
181  {
182    if (reqFeatureIndex == 0xffff)
183      return Index::NOT_FOUND_INDEX;
184   return reqFeatureIndex;;
185  }
186
187  inline bool sanitize (hb_sanitize_context_t *c) {
188    TRACE_SANITIZE ();
189    return c->check_struct (this)
190	&& featureIndex.sanitize (c);
191  }
192
193  Offset	lookupOrder;	/* = Null (reserved for an offset to a
194				 * reordering table) */
195  USHORT	reqFeatureIndex;/* Index of a feature required for this
196				 * language system--if no required features
197				 * = 0xFFFF */
198  IndexArray	featureIndex;	/* Array of indices into the FeatureList */
199  public:
200  DEFINE_SIZE_ARRAY (6, featureIndex);
201};
202DEFINE_NULL_DATA (LangSys, "\0\0\xFF\xFF");
203
204
205struct Script
206{
207  inline unsigned int get_lang_sys_count (void) const
208  { return langSys.len; }
209  inline const Tag& get_lang_sys_tag (unsigned int i) const
210  { return langSys.get_tag (i); }
211  inline unsigned int get_lang_sys_tags (unsigned int start_offset,
212					 unsigned int *lang_sys_count /* IN/OUT */,
213					 hb_tag_t     *lang_sys_tags /* OUT */) const
214  { return langSys.get_tags (start_offset, lang_sys_count, lang_sys_tags); }
215  inline const LangSys& get_lang_sys (unsigned int i) const
216  {
217    if (i == Index::NOT_FOUND_INDEX) return get_default_lang_sys ();
218    return this+langSys[i].offset;
219  }
220  inline bool find_lang_sys_index (hb_tag_t tag, unsigned int *index) const
221  { return langSys.find_index (tag, index); }
222
223  inline bool has_default_lang_sys (void) const { return defaultLangSys != 0; }
224  inline const LangSys& get_default_lang_sys (void) const { return this+defaultLangSys; }
225
226  inline bool sanitize (hb_sanitize_context_t *c) {
227    TRACE_SANITIZE ();
228    return defaultLangSys.sanitize (c, this)
229	&& langSys.sanitize (c, this);
230  }
231
232  private:
233  OffsetTo<LangSys>
234		defaultLangSys;	/* Offset to DefaultLangSys table--from
235				 * beginning of Script table--may be Null */
236  RecordArrayOf<LangSys>
237		langSys;	/* Array of LangSysRecords--listed
238				 * alphabetically by LangSysTag */
239  public:
240  DEFINE_SIZE_ARRAY (4, langSys);
241};
242
243typedef RecordListOf<Script> ScriptList;
244
245
246struct Feature
247{
248  inline unsigned int get_lookup_count (void) const
249  { return lookupIndex.len; }
250  inline hb_tag_t get_lookup_index (unsigned int i) const
251  { return lookupIndex[i]; }
252  inline unsigned int get_lookup_indexes (unsigned int start_index,
253					  unsigned int *lookup_count /* IN/OUT */,
254					  unsigned int *lookup_tags /* OUT */) const
255  { return lookupIndex.get_indexes (start_index, lookup_count, lookup_tags); }
256
257  inline bool sanitize (hb_sanitize_context_t *c) {
258    TRACE_SANITIZE ();
259    return c->check_struct (this)
260	&& lookupIndex.sanitize (c);
261  }
262
263  Offset	featureParams;	/* Offset to Feature Parameters table (if one
264				 * has been defined for the feature), relative
265				 * to the beginning of the Feature Table; = Null
266				 * if not required */
267  IndexArray	 lookupIndex;	/* Array of LookupList indices */
268  public:
269  DEFINE_SIZE_ARRAY (4, lookupIndex);
270};
271
272typedef RecordListOf<Feature> FeatureList;
273
274
275struct LookupFlag : USHORT
276{
277  enum {
278    RightToLeft		= 0x0001u,
279    IgnoreBaseGlyphs	= 0x0002u,
280    IgnoreLigatures	= 0x0004u,
281    IgnoreMarks		= 0x0008u,
282    IgnoreFlags		= 0x000Eu,
283    UseMarkFilteringSet	= 0x0010u,
284    Reserved		= 0x00E0u,
285    MarkAttachmentType	= 0xFF00u
286  };
287  public:
288  DEFINE_SIZE_STATIC (2);
289};
290
291struct Lookup
292{
293  inline unsigned int get_subtable_count (void) const { return subTable.len; }
294
295  inline unsigned int get_type (void) const { return lookupType; }
296
297  /* lookup_props is a 32-bit integer where the lower 16-bit is LookupFlag and
298   * higher 16-bit is mark-filtering-set if the lookup uses one.
299   * Not to be confused with glyph_props which is very similar. */
300  inline uint32_t get_props (void) const
301  {
302    unsigned int flag = lookupFlag;
303    if (unlikely (flag & LookupFlag::UseMarkFilteringSet))
304    {
305      const USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
306      flag += (markFilteringSet << 16);
307    }
308    return flag;
309  }
310
311  inline bool sanitize (hb_sanitize_context_t *c) {
312    TRACE_SANITIZE ();
313    /* Real sanitize of the subtables is done by GSUB/GPOS/... */
314    if (!(c->check_struct (this)
315       && subTable.sanitize (c))) return false;
316    if (unlikely (lookupFlag & LookupFlag::UseMarkFilteringSet))
317    {
318      USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
319      if (!markFilteringSet.sanitize (c)) return false;
320    }
321    return true;
322  }
323
324  USHORT	lookupType;		/* Different enumerations for GSUB and GPOS */
325  USHORT	lookupFlag;		/* Lookup qualifiers */
326  ArrayOf<Offset>
327		subTable;		/* Array of SubTables */
328  USHORT	markFilteringSetX[VAR];	/* Index (base 0) into GDEF mark glyph sets
329					 * structure. This field is only present if bit
330					 * UseMarkFilteringSet of lookup flags is set. */
331  public:
332  DEFINE_SIZE_ARRAY2 (6, subTable, markFilteringSetX);
333};
334
335typedef OffsetListOf<Lookup> LookupList;
336
337
338/*
339 * Coverage Table
340 */
341
342struct CoverageFormat1
343{
344  friend struct Coverage;
345
346  private:
347  inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
348  {
349    int i = glyphArray.search (glyph_id);
350    if (i != -1)
351        return i;
352    return NOT_COVERED;
353  }
354
355  inline bool sanitize (hb_sanitize_context_t *c) {
356    TRACE_SANITIZE ();
357    return glyphArray.sanitize (c);
358  }
359
360  private:
361  USHORT	coverageFormat;	/* Format identifier--format = 1 */
362  SortedArrayOf<GlyphID>
363		glyphArray;	/* Array of GlyphIDs--in numerical order */
364  public:
365  DEFINE_SIZE_ARRAY (4, glyphArray);
366};
367
368struct CoverageFormat2
369{
370  friend struct Coverage;
371
372  private:
373  inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
374  {
375    int i = rangeRecord.search (glyph_id);
376    if (i != -1) {
377      const RangeRecord &range = rangeRecord[i];
378      return (unsigned int) range.value + (glyph_id - range.start);
379    }
380    return NOT_COVERED;
381  }
382
383  inline bool sanitize (hb_sanitize_context_t *c) {
384    TRACE_SANITIZE ();
385    return rangeRecord.sanitize (c);
386  }
387
388  private:
389  USHORT	coverageFormat;	/* Format identifier--format = 2 */
390  SortedArrayOf<RangeRecord>
391		rangeRecord;	/* Array of glyph ranges--ordered by
392				 * Start GlyphID. rangeCount entries
393				 * long */
394  public:
395  DEFINE_SIZE_ARRAY (4, rangeRecord);
396};
397
398struct Coverage
399{
400  inline unsigned int operator () (hb_codepoint_t glyph_id) const { return get_coverage (glyph_id); }
401
402  inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
403  {
404    switch (u.format) {
405    case 1: return u.format1.get_coverage(glyph_id);
406    case 2: return u.format2.get_coverage(glyph_id);
407    default:return NOT_COVERED;
408    }
409  }
410
411  inline bool sanitize (hb_sanitize_context_t *c) {
412    TRACE_SANITIZE ();
413    if (!u.format.sanitize (c)) return false;
414    switch (u.format) {
415    case 1: return u.format1.sanitize (c);
416    case 2: return u.format2.sanitize (c);
417    default:return true;
418    }
419  }
420
421  private:
422  union {
423  USHORT		format;		/* Format identifier */
424  CoverageFormat1	format1;
425  CoverageFormat2	format2;
426  } u;
427  public:
428  DEFINE_SIZE_UNION (2, format);
429};
430
431
432/*
433 * Class Definition Table
434 */
435
436struct ClassDefFormat1
437{
438  friend struct ClassDef;
439
440  private:
441  inline unsigned int get_class (hb_codepoint_t glyph_id) const
442  {
443    if ((unsigned int) (glyph_id - startGlyph) < classValue.len)
444      return classValue[glyph_id - startGlyph];
445    return 0;
446  }
447
448  inline bool sanitize (hb_sanitize_context_t *c) {
449    TRACE_SANITIZE ();
450    return c->check_struct (this)
451	&& classValue.sanitize (c);
452  }
453
454  USHORT	classFormat;		/* Format identifier--format = 1 */
455  GlyphID	startGlyph;		/* First GlyphID of the classValueArray */
456  ArrayOf<USHORT>
457		classValue;		/* Array of Class Values--one per GlyphID */
458  public:
459  DEFINE_SIZE_ARRAY (6, classValue);
460};
461
462struct ClassDefFormat2
463{
464  friend struct ClassDef;
465
466  private:
467  inline unsigned int get_class (hb_codepoint_t glyph_id) const
468  {
469    int i = rangeRecord.search (glyph_id);
470    if (i != -1)
471      return rangeRecord[i].value;
472    return 0;
473  }
474
475  inline bool sanitize (hb_sanitize_context_t *c) {
476    TRACE_SANITIZE ();
477    return rangeRecord.sanitize (c);
478  }
479
480  USHORT	classFormat;	/* Format identifier--format = 2 */
481  SortedArrayOf<RangeRecord>
482		rangeRecord;	/* Array of glyph ranges--ordered by
483				 * Start GlyphID */
484  public:
485  DEFINE_SIZE_ARRAY (4, rangeRecord);
486};
487
488struct ClassDef
489{
490  inline unsigned int operator () (hb_codepoint_t glyph_id) const { return get_class (glyph_id); }
491
492  inline unsigned int get_class (hb_codepoint_t glyph_id) const
493  {
494    switch (u.format) {
495    case 1: return u.format1.get_class(glyph_id);
496    case 2: return u.format2.get_class(glyph_id);
497    default:return 0;
498    }
499  }
500
501  inline bool sanitize (hb_sanitize_context_t *c) {
502    TRACE_SANITIZE ();
503    if (!u.format.sanitize (c)) return false;
504    switch (u.format) {
505    case 1: return u.format1.sanitize (c);
506    case 2: return u.format2.sanitize (c);
507    default:return true;
508    }
509  }
510
511  private:
512  union {
513  USHORT		format;		/* Format identifier */
514  ClassDefFormat1	format1;
515  ClassDefFormat2	format2;
516  } u;
517  public:
518  DEFINE_SIZE_UNION (2, format);
519};
520
521
522/*
523 * Device Tables
524 */
525
526struct Device
527{
528
529  inline hb_position_t get_x_delta (hb_font_t *font) const
530  { return get_delta (font->x_ppem, font->x_scale); }
531
532  inline hb_position_t get_y_delta (hb_font_t *font) const
533  { return get_delta (font->y_ppem, font->y_scale); }
534
535  inline int get_delta (unsigned int ppem, int scale) const
536  {
537    if (!ppem) return 0;
538
539    int pixels = get_delta_pixels (ppem);
540
541    if (!pixels) return 0;
542
543    return pixels * (int64_t) scale / ppem;
544  }
545
546
547  inline int get_delta_pixels (unsigned int ppem_size) const
548  {
549    unsigned int f = deltaFormat;
550    if (unlikely (f < 1 || f > 3))
551      return 0;
552
553    if (ppem_size < startSize || ppem_size > endSize)
554      return 0;
555
556    unsigned int s = ppem_size - startSize;
557
558    unsigned int byte = deltaValue[s >> (4 - f)];
559    unsigned int bits = (byte >> (16 - (((s & ((1 << (4 - f)) - 1)) + 1) << f)));
560    unsigned int mask = (0xFFFF >> (16 - (1 << f)));
561
562    int delta = bits & mask;
563
564    if ((unsigned int) delta >= ((mask + 1) >> 1))
565      delta -= mask + 1;
566
567    return delta;
568  }
569
570  inline unsigned int get_size (void) const
571  {
572    unsigned int f = deltaFormat;
573    if (unlikely (f < 1 || f > 3 || startSize > endSize)) return 3 * USHORT::static_size;
574    return USHORT::static_size * (4 + ((endSize - startSize) >> (4 - f)));
575  }
576
577  inline bool sanitize (hb_sanitize_context_t *c) {
578    TRACE_SANITIZE ();
579    return c->check_struct (this)
580	&& c->check_range (this, this->get_size ());
581  }
582
583  private:
584  USHORT	startSize;		/* Smallest size to correct--in ppem */
585  USHORT	endSize;		/* Largest size to correct--in ppem */
586  USHORT	deltaFormat;		/* Format of DeltaValue array data: 1, 2, or 3
587					 * 1	Signed 2-bit value, 8 values per uint16
588					 * 2	Signed 4-bit value, 4 values per uint16
589					 * 3	Signed 8-bit value, 2 values per uint16
590					 */
591  USHORT	deltaValue[VAR];	/* Array of compressed data */
592  public:
593  DEFINE_SIZE_ARRAY (6, deltaValue);
594};
595
596
597HB_BEGIN_DECLS
598HB_END_DECLS
599
600#endif /* HB_OT_LAYOUT_COMMON_PRIVATE_HH */
601