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