1/*
2 * Copyright © 2007,2008,2009 Red Hat, Inc.
3 * Copyright © 2010,2012 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_HH
30#define HB_OT_LAYOUT_COMMON_HH
31
32#include "hb.hh"
33#include "hb-ot-layout.hh"
34#include "hb-open-type.hh"
35#include "hb-set.hh"
36
37
38#ifndef HB_MAX_NESTING_LEVEL
39#define HB_MAX_NESTING_LEVEL 6
40#endif
41#ifndef HB_MAX_CONTEXT_LENGTH
42#define HB_MAX_CONTEXT_LENGTH 64
43#endif
44#ifndef HB_CLOSURE_MAX_STAGES
45/*
46 * The maximum number of times a lookup can be applied during shaping.
47 * Used to limit the number of iterations of the closure algorithm.
48 * This must be larger than the number of times add_pause() is
49 * called in a collect_features call of any shaper.
50 */
51#define HB_CLOSURE_MAX_STAGES 32
52#endif
53
54
55namespace OT {
56
57
58#define NOT_COVERED ((unsigned int) -1)
59
60
61
62/*
63 *
64 * OpenType Layout Common Table Formats
65 *
66 */
67
68
69/*
70 * Script, ScriptList, LangSys, Feature, FeatureList, Lookup, LookupList
71 */
72
73template <typename Type>
74struct Record
75{
76 inline int cmp (hb_tag_t a) const {
77 return tag.cmp (a);
78 }
79
80 struct sanitize_closure_t {
81 hb_tag_t tag;
82 const void *list_base;
83 };
84 inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
85 {
86 TRACE_SANITIZE (this);
87 const sanitize_closure_t closure = {tag, base};
88 return_trace (c->check_struct (this) && offset.sanitize (c, base, &closure));
89 }
90
91 Tag tag; /* 4-byte Tag identifier */
92 OffsetTo<Type>
93 offset; /* Offset from beginning of object holding
94 * the Record */
95 public:
96 DEFINE_SIZE_STATIC (6);
97};
98
99template <typename Type>
100struct RecordArrayOf : SortedArrayOf<Record<Type> >
101{
102 inline const OffsetTo<Type>& get_offset (unsigned int i) const
103 { return (*this)[i].offset; }
104 inline OffsetTo<Type>& get_offset (unsigned int i)
105 { return (*this)[i].offset; }
106 inline const Tag& get_tag (unsigned int i) const
107 { return (*this)[i].tag; }
108 inline unsigned int get_tags (unsigned int start_offset,
109 unsigned int *record_count /* IN/OUT */,
110 hb_tag_t *record_tags /* OUT */) const
111 {
112 if (record_count) {
113 const Record<Type> *arr = this->sub_array (start_offset, record_count);
114 unsigned int count = *record_count;
115 for (unsigned int i = 0; i < count; i++)
116 record_tags[i] = arr[i].tag;
117 }
118 return this->len;
119 }
120 inline bool find_index (hb_tag_t tag, unsigned int *index) const
121 {
122 /* If we want to allow non-sorted data, we can lsearch(). */
123 int i = this->/*lsearch*/bsearch (tag);
124 if (i != -1) {
125 if (index) *index = i;
126 return true;
127 } else {
128 if (index) *index = Index::NOT_FOUND_INDEX;
129 return false;
130 }
131 }
132};
133
134template <typename Type>
135struct RecordListOf : RecordArrayOf<Type>
136{
137 inline const Type& operator [] (unsigned int i) const
138 { return this+this->get_offset (i); }
139
140 inline bool subset (hb_subset_context_t *c) const
141 {
142 TRACE_SUBSET (this);
143 struct RecordListOf<Type> *out = c->serializer->embed (*this);
144 if (unlikely (!out)) return_trace (false);
145 unsigned int count = this->len;
146 for (unsigned int i = 0; i < count; i++)
147 out->get_offset (i).serialize_subset (c, (*this)[i], out);
148 return_trace (true);
149 }
150
151 inline bool sanitize (hb_sanitize_context_t *c) const
152 {
153 TRACE_SANITIZE (this);
154 return_trace (RecordArrayOf<Type>::sanitize (c, this));
155 }
156};
157
158
159struct RangeRecord
160{
161 inline int cmp (hb_codepoint_t g) const {
162 return g < start ? -1 : g <= end ? 0 : +1 ;
163 }
164
165 inline bool sanitize (hb_sanitize_context_t *c) const
166 {
167 TRACE_SANITIZE (this);
168 return_trace (c->check_struct (this));
169 }
170
171 inline bool intersects (const hb_set_t *glyphs) const
172 { return glyphs->intersects (start, end); }
173
174 template <typename set_t>
175 inline bool add_coverage (set_t *glyphs) const {
176 return glyphs->add_range (start, end);
177 }
178
179 GlyphID start; /* First GlyphID in the range */
180 GlyphID end; /* Last GlyphID in the range */
181 HBUINT16 value; /* Value */
182 public:
183 DEFINE_SIZE_STATIC (6);
184};
185DECLARE_NULL_NAMESPACE_BYTES (OT, RangeRecord);
186
187
188struct IndexArray : ArrayOf<Index>
189{
190 inline unsigned int get_indexes (unsigned int start_offset,
191 unsigned int *_count /* IN/OUT */,
192 unsigned int *_indexes /* OUT */) const
193 {
194 if (_count) {
195 const HBUINT16 *arr = this->sub_array (start_offset, _count);
196 unsigned int count = *_count;
197 for (unsigned int i = 0; i < count; i++)
198 _indexes[i] = arr[i];
199 }
200 return this->len;
201 }
202
203 inline void add_indexes_to (hb_set_t* output /* OUT */) const
204 {
205 output->add_array (arrayZ, len);
206 }
207};
208
209
210struct Script;
211struct LangSys;
212struct Feature;
213
214
215struct LangSys
216{
217 inline unsigned int get_feature_count (void) const
218 { return featureIndex.len; }
219 inline hb_tag_t get_feature_index (unsigned int i) const
220 { return featureIndex[i]; }
221 inline unsigned int get_feature_indexes (unsigned int start_offset,
222 unsigned int *feature_count /* IN/OUT */,
223 unsigned int *feature_indexes /* OUT */) const
224 { return featureIndex.get_indexes (start_offset, feature_count, feature_indexes); }
225 inline void add_feature_indexes_to (hb_set_t *feature_indexes) const
226 { featureIndex.add_indexes_to (feature_indexes); }
227
228 inline bool has_required_feature (void) const { return reqFeatureIndex != 0xFFFFu; }
229 inline unsigned int get_required_feature_index (void) const
230 {
231 if (reqFeatureIndex == 0xFFFFu)
232 return Index::NOT_FOUND_INDEX;
233 return reqFeatureIndex;;
234 }
235
236 inline bool subset (hb_subset_context_t *c) const
237 {
238 TRACE_SUBSET (this);
239 return_trace (c->serializer->embed (*this));
240 }
241
242 inline bool sanitize (hb_sanitize_context_t *c,
243 const Record<LangSys>::sanitize_closure_t * = nullptr) const
244 {
245 TRACE_SANITIZE (this);
246 return_trace (c->check_struct (this) && featureIndex.sanitize (c));
247 }
248
249 Offset16 lookupOrderZ; /* = Null (reserved for an offset to a
250 * reordering table) */
251 HBUINT16 reqFeatureIndex;/* Index of a feature required for this
252 * language system--if no required features
253 * = 0xFFFFu */
254 IndexArray featureIndex; /* Array of indices into the FeatureList */
255 public:
256 DEFINE_SIZE_ARRAY_SIZED (6, featureIndex);
257};
258DECLARE_NULL_NAMESPACE_BYTES (OT, LangSys);
259
260struct Script
261{
262 inline unsigned int get_lang_sys_count (void) const
263 { return langSys.len; }
264 inline const Tag& get_lang_sys_tag (unsigned int i) const
265 { return langSys.get_tag (i); }
266 inline unsigned int get_lang_sys_tags (unsigned int start_offset,
267 unsigned int *lang_sys_count /* IN/OUT */,
268 hb_tag_t *lang_sys_tags /* OUT */) const
269 { return langSys.get_tags (start_offset, lang_sys_count, lang_sys_tags); }
270 inline const LangSys& get_lang_sys (unsigned int i) const
271 {
272 if (i == Index::NOT_FOUND_INDEX) return get_default_lang_sys ();
273 return this+langSys[i].offset;
274 }
275 inline bool find_lang_sys_index (hb_tag_t tag, unsigned int *index) const
276 { return langSys.find_index (tag, index); }
277
278 inline bool has_default_lang_sys (void) const { return defaultLangSys != 0; }
279 inline const LangSys& get_default_lang_sys (void) const { return this+defaultLangSys; }
280
281 inline bool subset (hb_subset_context_t *c) const
282 {
283 TRACE_SUBSET (this);
284 struct Script *out = c->serializer->embed (*this);
285 if (unlikely (!out)) return_trace (false);
286 out->defaultLangSys.serialize_subset (c, this+defaultLangSys, out);
287 unsigned int count = langSys.len;
288 for (unsigned int i = 0; i < count; i++)
289 out->langSys.arrayZ[i].offset.serialize_subset (c, this+langSys[i].offset, out);
290 return_trace (true);
291 }
292
293 inline bool sanitize (hb_sanitize_context_t *c,
294 const Record<Script>::sanitize_closure_t * = nullptr) const
295 {
296 TRACE_SANITIZE (this);
297 return_trace (defaultLangSys.sanitize (c, this) && langSys.sanitize (c, this));
298 }
299
300 protected:
301 OffsetTo<LangSys>
302 defaultLangSys; /* Offset to DefaultLangSys table--from
303 * beginning of Script table--may be Null */
304 RecordArrayOf<LangSys>
305 langSys; /* Array of LangSysRecords--listed
306 * alphabetically by LangSysTag */
307 public:
308 DEFINE_SIZE_ARRAY_SIZED (4, langSys);
309};
310
311typedef RecordListOf<Script> ScriptList;
312
313
314/* https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#size */
315struct FeatureParamsSize
316{
317 inline bool sanitize (hb_sanitize_context_t *c) const
318 {
319 TRACE_SANITIZE (this);
320 if (unlikely (!c->check_struct (this))) return_trace (false);
321
322 /* This subtable has some "history", if you will. Some earlier versions of
323 * Adobe tools calculated the offset of the FeatureParams sutable from the
324 * beginning of the FeatureList table! Now, that is dealt with in the
325 * Feature implementation. But we still need to be able to tell junk from
326 * real data. Note: We don't check that the nameID actually exists.
327 *
328 * Read Roberts wrote on 9/15/06 on opentype-list@indx.co.uk :
329 *
330 * Yes, it is correct that a new version of the AFDKO (version 2.0) will be
331 * coming out soon, and that the makeotf program will build a font with a
332 * 'size' feature that is correct by the specification.
333 *
334 * The specification for this feature tag is in the "OpenType Layout Tag
335 * Registry". You can see a copy of this at:
336 * https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#tag-size
337 *
338 * Here is one set of rules to determine if the 'size' feature is built
339 * correctly, or as by the older versions of MakeOTF. You may be able to do
340 * better.
341 *
342 * Assume that the offset to the size feature is according to specification,
343 * and make the following value checks. If it fails, assume the size
344 * feature is calculated as versions of MakeOTF before the AFDKO 2.0 built it.
345 * If this fails, reject the 'size' feature. The older makeOTF's calculated the
346 * offset from the beginning of the FeatureList table, rather than from the
347 * beginning of the 'size' Feature table.
348 *
349 * If "design size" == 0:
350 * fails check
351 *
352 * Else if ("subfamily identifier" == 0 and
353 * "range start" == 0 and
354 * "range end" == 0 and
355 * "range start" == 0 and
356 * "menu name ID" == 0)
357 * passes check: this is the format used when there is a design size
358 * specified, but there is no recommended size range.
359 *
360 * Else if ("design size" < "range start" or
361 * "design size" > "range end" or
362 * "range end" <= "range start" or
363 * "menu name ID" < 256 or
364 * "menu name ID" > 32767 or
365 * menu name ID is not a name ID which is actually in the name table)
366 * fails test
367 * Else
368 * passes test.
369 */
370
371 if (!designSize)
372 return_trace (false);
373 else if (subfamilyID == 0 &&
374 subfamilyNameID == 0 &&
375 rangeStart == 0 &&
376 rangeEnd == 0)
377 return_trace (true);
378 else if (designSize < rangeStart ||
379 designSize > rangeEnd ||
380 subfamilyNameID < 256 ||
381 subfamilyNameID > 32767)
382 return_trace (false);
383 else
384 return_trace (true);
385 }
386
387 HBUINT16 designSize; /* Represents the design size in 720/inch
388 * units (decipoints). The design size entry
389 * must be non-zero. When there is a design
390 * size but no recommended size range, the
391 * rest of the array will consist of zeros. */
392 HBUINT16 subfamilyID; /* Has no independent meaning, but serves
393 * as an identifier that associates fonts
394 * in a subfamily. All fonts which share a
395 * Preferred or Font Family name and which
396 * differ only by size range shall have the
397 * same subfamily value, and no fonts which
398 * differ in weight or style shall have the
399 * same subfamily value. If this value is
400 * zero, the remaining fields in the array
401 * will be ignored. */
402 HBUINT16 subfamilyNameID;/* If the preceding value is non-zero, this
403 * value must be set in the range 256 - 32767
404 * (inclusive). It records the value of a
405 * field in the name table, which must
406 * contain English-language strings encoded
407 * in Windows Unicode and Macintosh Roman,
408 * and may contain additional strings
409 * localized to other scripts and languages.
410 * Each of these strings is the name an
411 * application should use, in combination
412 * with the family name, to represent the
413 * subfamily in a menu. Applications will
414 * choose the appropriate version based on
415 * their selection criteria. */
416 HBUINT16 rangeStart; /* Large end of the recommended usage range
417 * (inclusive), stored in 720/inch units
418 * (decipoints). */
419 HBUINT16 rangeEnd; /* Small end of the recommended usage range
420 (exclusive), stored in 720/inch units
421 * (decipoints). */
422 public:
423 DEFINE_SIZE_STATIC (10);
424};
425
426/* https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#ssxx */
427struct FeatureParamsStylisticSet
428{
429 inline bool sanitize (hb_sanitize_context_t *c) const
430 {
431 TRACE_SANITIZE (this);
432 /* Right now minorVersion is at zero. Which means, any table supports
433 * the uiNameID field. */
434 return_trace (c->check_struct (this));
435 }
436
437 HBUINT16 version; /* (set to 0): This corresponds to a “minor”
438 * version number. Additional data may be
439 * added to the end of this Feature Parameters
440 * table in the future. */
441
442 NameID uiNameID; /* The 'name' table name ID that specifies a
443 * string (or strings, for multiple languages)
444 * for a user-interface label for this
445 * feature. The values of uiLabelNameId and
446 * sampleTextNameId are expected to be in the
447 * font-specific name ID range (256-32767),
448 * though that is not a requirement in this
449 * Feature Parameters specification. The
450 * user-interface label for the feature can
451 * be provided in multiple languages. An
452 * English string should be included as a
453 * fallback. The string should be kept to a
454 * minimal length to fit comfortably with
455 * different application interfaces. */
456 public:
457 DEFINE_SIZE_STATIC (4);
458};
459
460/* https://docs.microsoft.com/en-us/typography/opentype/spec/features_ae#cv01-cv99 */
461struct FeatureParamsCharacterVariants
462{
463 inline bool sanitize (hb_sanitize_context_t *c) const
464 {
465 TRACE_SANITIZE (this);
466 return_trace (c->check_struct (this) &&
467 characters.sanitize (c));
468 }
469
470 HBUINT16 format; /* Format number is set to 0. */
471 NameID featUILableNameID; /* The ‘name’ table name ID that
472 * specifies a string (or strings,
473 * for multiple languages) for a
474 * user-interface label for this
475 * feature. (May be nullptr.) */
476 NameID featUITooltipTextNameID;/* The ‘name’ table name ID that
477 * specifies a string (or strings,
478 * for multiple languages) that an
479 * application can use for tooltip
480 * text for this feature. (May be
481 * nullptr.) */
482 NameID sampleTextNameID; /* The ‘name’ table name ID that
483 * specifies sample text that
484 * illustrates the effect of this
485 * feature. (May be nullptr.) */
486 HBUINT16 numNamedParameters; /* Number of named parameters. (May
487 * be zero.) */
488 NameID firstParamUILabelNameID;/* The first ‘name’ table name ID
489 * used to specify strings for
490 * user-interface labels for the
491 * feature parameters. (Must be zero
492 * if numParameters is zero.) */
493 ArrayOf<HBUINT24>
494 characters; /* Array of the Unicode Scalar Value
495 * of the characters for which this
496 * feature provides glyph variants.
497 * (May be zero.) */
498 public:
499 DEFINE_SIZE_ARRAY (14, characters);
500};
501
502struct FeatureParams
503{
504 inline bool sanitize (hb_sanitize_context_t *c, hb_tag_t tag) const
505 {
506 TRACE_SANITIZE (this);
507 if (tag == HB_TAG ('s','i','z','e'))
508 return_trace (u.size.sanitize (c));
509 if ((tag & 0xFFFF0000u) == HB_TAG ('s','s','\0','\0')) /* ssXX */
510 return_trace (u.stylisticSet.sanitize (c));
511 if ((tag & 0xFFFF0000u) == HB_TAG ('c','v','\0','\0')) /* cvXX */
512 return_trace (u.characterVariants.sanitize (c));
513 return_trace (true);
514 }
515
516 inline const FeatureParamsSize& get_size_params (hb_tag_t tag) const
517 {
518 if (tag == HB_TAG ('s','i','z','e'))
519 return u.size;
520 return Null(FeatureParamsSize);
521 }
522
523 private:
524 union {
525 FeatureParamsSize size;
526 FeatureParamsStylisticSet stylisticSet;
527 FeatureParamsCharacterVariants characterVariants;
528 } u;
529 DEFINE_SIZE_STATIC (17);
530};
531
532struct Feature
533{
534 inline unsigned int get_lookup_count (void) const
535 { return lookupIndex.len; }
536 inline hb_tag_t get_lookup_index (unsigned int i) const
537 { return lookupIndex[i]; }
538 inline unsigned int get_lookup_indexes (unsigned int start_index,
539 unsigned int *lookup_count /* IN/OUT */,
540 unsigned int *lookup_tags /* OUT */) const
541 { return lookupIndex.get_indexes (start_index, lookup_count, lookup_tags); }
542
543 inline const FeatureParams &get_feature_params (void) const
544 { return this+featureParams; }
545
546 inline bool subset (hb_subset_context_t *c) const
547 {
548 TRACE_SUBSET (this);
549 struct Feature *out = c->serializer->embed (*this);
550 if (unlikely (!out)) return_trace (false);
551 out->featureParams.set (0); /* TODO(subset) FeatureParams. */
552 return_trace (true);
553 }
554
555 inline bool sanitize (hb_sanitize_context_t *c,
556 const Record<Feature>::sanitize_closure_t *closure = nullptr) const
557 {
558 TRACE_SANITIZE (this);
559 if (unlikely (!(c->check_struct (this) && lookupIndex.sanitize (c))))
560 return_trace (false);
561
562 /* Some earlier versions of Adobe tools calculated the offset of the
563 * FeatureParams subtable from the beginning of the FeatureList table!
564 *
565 * If sanitizing "failed" for the FeatureParams subtable, try it with the
566 * alternative location. We would know sanitize "failed" if old value
567 * of the offset was non-zero, but it's zeroed now.
568 *
569 * Only do this for the 'size' feature, since at the time of the faulty
570 * Adobe tools, only the 'size' feature had FeatureParams defined.
571 */
572
573 OffsetTo<FeatureParams> orig_offset = featureParams;
574 if (unlikely (!featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE)))
575 return_trace (false);
576
577 if (likely (orig_offset.is_null ()))
578 return_trace (true);
579
580 if (featureParams == 0 && closure &&
581 closure->tag == HB_TAG ('s','i','z','e') &&
582 closure->list_base && closure->list_base < this)
583 {
584 unsigned int new_offset_int = (unsigned int) orig_offset -
585 (((char *) this) - ((char *) closure->list_base));
586
587 OffsetTo<FeatureParams> new_offset;
588 /* Check that it did not overflow. */
589 new_offset.set (new_offset_int);
590 if (new_offset == new_offset_int &&
591 c->try_set (&featureParams, new_offset) &&
592 !featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE))
593 return_trace (false);
594 }
595
596 return_trace (true);
597 }
598
599 OffsetTo<FeatureParams>
600 featureParams; /* Offset to Feature Parameters table (if one
601 * has been defined for the feature), relative
602 * to the beginning of the Feature Table; = Null
603 * if not required */
604 IndexArray lookupIndex; /* Array of LookupList indices */
605 public:
606 DEFINE_SIZE_ARRAY_SIZED (4, lookupIndex);
607};
608
609typedef RecordListOf<Feature> FeatureList;
610
611
612struct LookupFlag : HBUINT16
613{
614 enum Flags {
615 RightToLeft = 0x0001u,
616 IgnoreBaseGlyphs = 0x0002u,
617 IgnoreLigatures = 0x0004u,
618 IgnoreMarks = 0x0008u,
619 IgnoreFlags = 0x000Eu,
620 UseMarkFilteringSet = 0x0010u,
621 Reserved = 0x00E0u,
622 MarkAttachmentType = 0xFF00u
623 };
624 public:
625 DEFINE_SIZE_STATIC (2);
626};
627
628} /* namespace OT */
629/* This has to be outside the namespace. */
630HB_MARK_AS_FLAG_T (OT::LookupFlag::Flags);
631namespace OT {
632
633struct Lookup
634{
635 inline unsigned int get_subtable_count (void) const { return subTable.len; }
636
637 template <typename TSubTable>
638 inline const TSubTable& get_subtable (unsigned int i) const
639 { return this+CastR<OffsetArrayOf<TSubTable> > (subTable)[i]; }
640
641 template <typename TSubTable>
642 inline const OffsetArrayOf<TSubTable>& get_subtables (void) const
643 { return CastR<OffsetArrayOf<TSubTable> > (subTable); }
644 template <typename TSubTable>
645 inline OffsetArrayOf<TSubTable>& get_subtables (void)
646 { return CastR<OffsetArrayOf<TSubTable> > (subTable); }
647
648 inline unsigned int get_size (void) const
649 {
650 const HBUINT16 &markFilteringSet = StructAfter<const HBUINT16> (subTable);
651 if (lookupFlag & LookupFlag::UseMarkFilteringSet)
652 return (const char *) &StructAfter<const char> (markFilteringSet) - (const char *) this;
653 return (const char *) &markFilteringSet - (const char *) this;
654 }
655
656 inline unsigned int get_type (void) const { return lookupType; }
657
658 /* lookup_props is a 32-bit integer where the lower 16-bit is LookupFlag and
659 * higher 16-bit is mark-filtering-set if the lookup uses one.
660 * Not to be confused with glyph_props which is very similar. */
661 inline uint32_t get_props (void) const
662 {
663 unsigned int flag = lookupFlag;
664 if (unlikely (flag & LookupFlag::UseMarkFilteringSet))
665 {
666 const HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
667 flag += (markFilteringSet << 16);
668 }
669 return flag;
670 }
671
672 template <typename TSubTable, typename context_t>
673 inline typename context_t::return_t dispatch (context_t *c) const
674 {
675 unsigned int lookup_type = get_type ();
676 TRACE_DISPATCH (this, lookup_type);
677 unsigned int count = get_subtable_count ();
678 for (unsigned int i = 0; i < count; i++) {
679 typename context_t::return_t r = get_subtable<TSubTable> (i).dispatch (c, lookup_type);
680 if (c->stop_sublookup_iteration (r))
681 return_trace (r);
682 }
683 return_trace (c->default_return_value ());
684 }
685
686 inline bool serialize (hb_serialize_context_t *c,
687 unsigned int lookup_type,
688 uint32_t lookup_props,
689 unsigned int num_subtables)
690 {
691 TRACE_SERIALIZE (this);
692 if (unlikely (!c->extend_min (*this))) return_trace (false);
693 lookupType.set (lookup_type);
694 lookupFlag.set (lookup_props & 0xFFFFu);
695 if (unlikely (!subTable.serialize (c, num_subtables))) return_trace (false);
696 if (lookupFlag & LookupFlag::UseMarkFilteringSet)
697 {
698 if (unlikely (!c->extend (*this))) return_trace (false);
699 HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
700 markFilteringSet.set (lookup_props >> 16);
701 }
702 return_trace (true);
703 }
704
705 /* Older compileres need this to NOT be locally defined in a function. */
706 template <typename TSubTable>
707 struct SubTableSubsetWrapper
708 {
709 inline SubTableSubsetWrapper (const TSubTable &subtable_,
710 unsigned int lookup_type_) :
711 subtable (subtable_),
712 lookup_type (lookup_type_) {}
713
714 inline bool subset (hb_subset_context_t *c) const
715 { return subtable.dispatch (c, lookup_type); }
716
717 private:
718 const TSubTable &subtable;
719 unsigned int lookup_type;
720 };
721
722 template <typename TSubTable>
723 inline bool subset (hb_subset_context_t *c) const
724 {
725 TRACE_SUBSET (this);
726 struct Lookup *out = c->serializer->embed (*this);
727 if (unlikely (!out)) return_trace (false);
728
729 /* Subset the actual subtables. */
730 /* TODO Drop empty ones, either by calling intersects() beforehand,
731 * or just dropping null offsets after. */
732 const OffsetArrayOf<TSubTable>& subtables = get_subtables<TSubTable> ();
733 OffsetArrayOf<TSubTable>& out_subtables = out->get_subtables<TSubTable> ();
734 unsigned int count = subTable.len;
735 for (unsigned int i = 0; i < count; i++)
736 {
737 SubTableSubsetWrapper<TSubTable> wrapper (this+subtables[i], get_type ());
738
739 out_subtables[i].serialize_subset (c, wrapper, out);
740 }
741
742 return_trace (true);
743 }
744
745 template <typename TSubTable>
746 inline bool sanitize (hb_sanitize_context_t *c) const
747 {
748 TRACE_SANITIZE (this);
749 if (!(c->check_struct (this) && subTable.sanitize (c))) return_trace (false);
750 if (lookupFlag & LookupFlag::UseMarkFilteringSet)
751 {
752 const HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
753 if (!markFilteringSet.sanitize (c)) return_trace (false);
754 }
755
756 if (unlikely (!dispatch<TSubTable> (c))) return_trace (false);
757
758 if (unlikely (get_type () == TSubTable::Extension))
759 {
760 /* The spec says all subtables of an Extension lookup should
761 * have the same type, which shall not be the Extension type
762 * itself (but we already checked for that).
763 * This is specially important if one has a reverse type! */
764 unsigned int type = get_subtable<TSubTable> (0).u.extension.get_type ();
765 unsigned int count = get_subtable_count ();
766 for (unsigned int i = 1; i < count; i++)
767 if (get_subtable<TSubTable> (i).u.extension.get_type () != type)
768 return_trace (false);
769 }
770 return_trace (true);
771 return_trace (true);
772 }
773
774 private:
775 HBUINT16 lookupType; /* Different enumerations for GSUB and GPOS */
776 HBUINT16 lookupFlag; /* Lookup qualifiers */
777 ArrayOf<Offset16>
778 subTable; /* Array of SubTables */
779 HBUINT16 markFilteringSetX[VAR]; /* Index (base 0) into GDEF mark glyph sets
780 * structure. This field is only present if bit
781 * UseMarkFilteringSet of lookup flags is set. */
782 public:
783 DEFINE_SIZE_ARRAY2 (6, subTable, markFilteringSetX);
784};
785
786typedef OffsetListOf<Lookup> LookupList;
787
788
789/*
790 * Coverage Table
791 */
792
793struct CoverageFormat1
794{
795 friend struct Coverage;
796
797 private:
798 inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
799 {
800 int i = glyphArray.bsearch (glyph_id);
801 static_assert ((((unsigned int) -1) == NOT_COVERED), "");
802 return i;
803 }
804
805 inline bool serialize (hb_serialize_context_t *c,
806 Supplier<GlyphID> &glyphs,
807 unsigned int num_glyphs)
808 {
809 TRACE_SERIALIZE (this);
810 if (unlikely (!c->extend_min (*this))) return_trace (false);
811 glyphArray.len.set (num_glyphs);
812 if (unlikely (!c->extend (glyphArray))) return_trace (false);
813 for (unsigned int i = 0; i < num_glyphs; i++)
814 glyphArray[i] = glyphs[i];
815 glyphs += num_glyphs;
816 return_trace (true);
817 }
818
819 inline bool sanitize (hb_sanitize_context_t *c) const
820 {
821 TRACE_SANITIZE (this);
822 return_trace (glyphArray.sanitize (c));
823 }
824
825 inline bool intersects (const hb_set_t *glyphs) const
826 {
827 /* TODO Speed up, using hb_set_next() and bsearch()? */
828 unsigned int count = glyphArray.len;
829 for (unsigned int i = 0; i < count; i++)
830 if (glyphs->has (glyphArray[i]))
831 return true;
832 return false;
833 }
834 inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
835 { return glyphs->has (glyphArray[index]); }
836
837 template <typename set_t>
838 inline bool add_coverage (set_t *glyphs) const {
839 return glyphs->add_sorted_array (glyphArray.arrayZ, glyphArray.len);
840 }
841
842 public:
843 /* Older compilers need this to be public. */
844 struct Iter {
845 inline void init (const struct CoverageFormat1 &c_) { c = &c_; i = 0; };
846 inline void fini (void) {};
847 inline bool more (void) { return i < c->glyphArray.len; }
848 inline void next (void) { i++; }
849 inline hb_codepoint_t get_glyph (void) { return c->glyphArray[i]; }
850 inline unsigned int get_coverage (void) { return i; }
851
852 private:
853 const struct CoverageFormat1 *c;
854 unsigned int i;
855 };
856 private:
857
858 protected:
859 HBUINT16 coverageFormat; /* Format identifier--format = 1 */
860 SortedArrayOf<GlyphID>
861 glyphArray; /* Array of GlyphIDs--in numerical order */
862 public:
863 DEFINE_SIZE_ARRAY (4, glyphArray);
864};
865
866struct CoverageFormat2
867{
868 friend struct Coverage;
869
870 private:
871 inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
872 {
873 int i = rangeRecord.bsearch (glyph_id);
874 if (i != -1) {
875 const RangeRecord &range = rangeRecord[i];
876 return (unsigned int) range.value + (glyph_id - range.start);
877 }
878 return NOT_COVERED;
879 }
880
881 inline bool serialize (hb_serialize_context_t *c,
882 Supplier<GlyphID> &glyphs,
883 unsigned int num_glyphs)
884 {
885 TRACE_SERIALIZE (this);
886 if (unlikely (!c->extend_min (*this))) return_trace (false);
887
888 if (unlikely (!num_glyphs))
889 {
890 rangeRecord.len.set (0);
891 return_trace (true);
892 }
893
894 unsigned int num_ranges = 1;
895 for (unsigned int i = 1; i < num_glyphs; i++)
896 if (glyphs[i - 1] + 1 != glyphs[i])
897 num_ranges++;
898 rangeRecord.len.set (num_ranges);
899 if (unlikely (!c->extend (rangeRecord))) return_trace (false);
900
901 unsigned int range = 0;
902 rangeRecord[range].start = glyphs[0];
903 rangeRecord[range].value.set (0);
904 for (unsigned int i = 1; i < num_glyphs; i++)
905 if (glyphs[i - 1] + 1 != glyphs[i]) {
906 range++;
907 rangeRecord[range].start = glyphs[i];
908 rangeRecord[range].value.set (i);
909 rangeRecord[range].end = glyphs[i];
910 } else {
911 rangeRecord[range].end = glyphs[i];
912 }
913 glyphs += num_glyphs;
914 return_trace (true);
915 }
916
917 inline bool sanitize (hb_sanitize_context_t *c) const
918 {
919 TRACE_SANITIZE (this);
920 return_trace (rangeRecord.sanitize (c));
921 }
922
923 inline bool intersects (const hb_set_t *glyphs) const
924 {
925 /* TODO Speed up, using hb_set_next() and bsearch()? */
926 unsigned int count = rangeRecord.len;
927 for (unsigned int i = 0; i < count; i++)
928 if (rangeRecord[i].intersects (glyphs))
929 return true;
930 return false;
931 }
932 inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
933 {
934 unsigned int i;
935 unsigned int count = rangeRecord.len;
936 for (i = 0; i < count; i++) {
937 const RangeRecord &range = rangeRecord[i];
938 if (range.value <= index &&
939 index < (unsigned int) range.value + (range.end - range.start) &&
940 range.intersects (glyphs))
941 return true;
942 else if (index < range.value)
943 return false;
944 }
945 return false;
946 }
947
948 template <typename set_t>
949 inline bool add_coverage (set_t *glyphs) const {
950 unsigned int count = rangeRecord.len;
951 for (unsigned int i = 0; i < count; i++)
952 if (unlikely (!rangeRecord[i].add_coverage (glyphs)))
953 return false;
954 return true;
955 }
956
957 public:
958 /* Older compilers need this to be public. */
959 struct Iter
960 {
961 inline void init (const CoverageFormat2 &c_)
962 {
963 c = &c_;
964 coverage = 0;
965 i = 0;
966 j = c->rangeRecord.len ? c->rangeRecord[0].start : 0;
967 if (unlikely (c->rangeRecord[0].start > c->rangeRecord[0].end))
968 {
969 /* Broken table. Skip. */
970 i = c->rangeRecord.len;
971 }
972 }
973 inline void fini (void) {};
974 inline bool more (void) { return i < c->rangeRecord.len; }
975 inline void next (void)
976 {
977 if (j >= c->rangeRecord[i].end)
978 {
979 i++;
980 if (more ())
981 {
982 hb_codepoint_t old = j;
983 j = c->rangeRecord[i].start;
984 if (unlikely (j <= old))
985 {
986 /* Broken table. Skip. Important to avoid DoS. */
987 i = c->rangeRecord.len;
988 return;
989 }
990 coverage = c->rangeRecord[i].value;
991 }
992 return;
993 }
994 coverage++;
995 j++;
996 }
997 inline hb_codepoint_t get_glyph (void) { return j; }
998 inline unsigned int get_coverage (void) { return coverage; }
999
1000 private:
1001 const struct CoverageFormat2 *c;
1002 unsigned int i, coverage;
1003 hb_codepoint_t j;
1004 };
1005 private:
1006
1007 protected:
1008 HBUINT16 coverageFormat; /* Format identifier--format = 2 */
1009 SortedArrayOf<RangeRecord>
1010 rangeRecord; /* Array of glyph ranges--ordered by
1011 * Start GlyphID. rangeCount entries
1012 * long */
1013 public:
1014 DEFINE_SIZE_ARRAY (4, rangeRecord);
1015};
1016
1017struct Coverage
1018{
1019 inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
1020 {
1021 switch (u.format) {
1022 case 1: return u.format1.get_coverage (glyph_id);
1023 case 2: return u.format2.get_coverage (glyph_id);
1024 default:return NOT_COVERED;
1025 }
1026 }
1027
1028 inline bool serialize (hb_serialize_context_t *c,
1029 Supplier<GlyphID> &glyphs,
1030 unsigned int num_glyphs)
1031 {
1032 TRACE_SERIALIZE (this);
1033 if (unlikely (!c->extend_min (*this))) return_trace (false);
1034 unsigned int num_ranges = 1;
1035 for (unsigned int i = 1; i < num_glyphs; i++)
1036 if (glyphs[i - 1] + 1 != glyphs[i])
1037 num_ranges++;
1038 u.format.set (num_glyphs * 2 < num_ranges * 3 ? 1 : 2);
1039 switch (u.format)
1040 {
1041 case 1: return_trace (u.format1.serialize (c, glyphs, num_glyphs));
1042 case 2: return_trace (u.format2.serialize (c, glyphs, num_glyphs));
1043 default:return_trace (false);
1044 }
1045 }
1046
1047 inline bool sanitize (hb_sanitize_context_t *c) const
1048 {
1049 TRACE_SANITIZE (this);
1050 if (!u.format.sanitize (c)) return_trace (false);
1051 switch (u.format)
1052 {
1053 case 1: return_trace (u.format1.sanitize (c));
1054 case 2: return_trace (u.format2.sanitize (c));
1055 default:return_trace (true);
1056 }
1057 }
1058
1059 inline bool intersects (const hb_set_t *glyphs) const
1060 {
1061 switch (u.format)
1062 {
1063 case 1: return u.format1.intersects (glyphs);
1064 case 2: return u.format2.intersects (glyphs);
1065 default:return false;
1066 }
1067 }
1068 inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
1069 {
1070 switch (u.format)
1071 {
1072 case 1: return u.format1.intersects_coverage (glyphs, index);
1073 case 2: return u.format2.intersects_coverage (glyphs, index);
1074 default:return false;
1075 }
1076 }
1077
1078 /* Might return false if array looks unsorted.
1079 * Used for faster rejection of corrupt data. */
1080 template <typename set_t>
1081 inline bool add_coverage (set_t *glyphs) const
1082 {
1083 switch (u.format)
1084 {
1085 case 1: return u.format1.add_coverage (glyphs);
1086 case 2: return u.format2.add_coverage (glyphs);
1087 default:return false;
1088 }
1089 }
1090
1091 struct Iter
1092 {
1093 Iter (void) : format (0), u () {};
1094 inline void init (const Coverage &c_)
1095 {
1096 format = c_.u.format;
1097 switch (format)
1098 {
1099 case 1: u.format1.init (c_.u.format1); return;
1100 case 2: u.format2.init (c_.u.format2); return;
1101 default: return;
1102 }
1103 }
1104 inline void fini (void) {}
1105 inline bool more (void)
1106 {
1107 switch (format)
1108 {
1109 case 1: return u.format1.more ();
1110 case 2: return u.format2.more ();
1111 default:return false;
1112 }
1113 }
1114 inline void next (void)
1115 {
1116 switch (format)
1117 {
1118 case 1: u.format1.next (); break;
1119 case 2: u.format2.next (); break;
1120 default: break;
1121 }
1122 }
1123 inline hb_codepoint_t get_glyph (void)
1124 {
1125 switch (format)
1126 {
1127 case 1: return u.format1.get_glyph ();
1128 case 2: return u.format2.get_glyph ();
1129 default:return 0;
1130 }
1131 }
1132 inline unsigned int get_coverage (void)
1133 {
1134 switch (format)
1135 {
1136 case 1: return u.format1.get_coverage ();
1137 case 2: return u.format2.get_coverage ();
1138 default:return -1;
1139 }
1140 }
1141
1142 private:
1143 unsigned int format;
1144 union {
1145 CoverageFormat2::Iter format2; /* Put this one first since it's larger; helps shut up compiler. */
1146 CoverageFormat1::Iter format1;
1147 } u;
1148 };
1149
1150 protected:
1151 union {
1152 HBUINT16 format; /* Format identifier */
1153 CoverageFormat1 format1;
1154 CoverageFormat2 format2;
1155 } u;
1156 public:
1157 DEFINE_SIZE_UNION (2, format);
1158};
1159
1160
1161/*
1162 * Class Definition Table
1163 */
1164
1165struct ClassDefFormat1
1166{
1167 friend struct ClassDef;
1168
1169 private:
1170 inline unsigned int get_class (hb_codepoint_t glyph_id) const
1171 {
1172 unsigned int i = (unsigned int) (glyph_id - startGlyph);
1173 if (unlikely (i < classValue.len))
1174 return classValue[i];
1175 return 0;
1176 }
1177
1178 inline bool sanitize (hb_sanitize_context_t *c) const
1179 {
1180 TRACE_SANITIZE (this);
1181 return_trace (c->check_struct (this) && classValue.sanitize (c));
1182 }
1183
1184 template <typename set_t>
1185 inline bool add_coverage (set_t *glyphs) const {
1186 unsigned int start = 0;
1187 unsigned int count = classValue.len;
1188 for (unsigned int i = 0; i < count; i++)
1189 {
1190 if (classValue[i])
1191 continue;
1192
1193 if (start != i)
1194 if (unlikely (!glyphs->add_range (startGlyph + start, startGlyph + i)))
1195 return false;
1196
1197 start = i + 1;
1198 }
1199 if (start != count)
1200 if (unlikely (!glyphs->add_range (startGlyph + start, startGlyph + count)))
1201 return false;
1202
1203 return true;
1204 }
1205
1206 template <typename set_t>
1207 inline bool add_class (set_t *glyphs, unsigned int klass) const {
1208 unsigned int count = classValue.len;
1209 for (unsigned int i = 0; i < count; i++)
1210 {
1211 if (classValue[i] == klass)
1212 glyphs->add (startGlyph + i);
1213 }
1214 return true;
1215 }
1216
1217 inline bool intersects (const hb_set_t *glyphs) const
1218 {
1219 /* TODO Speed up, using hb_set_next()? */
1220 hb_codepoint_t start = startGlyph;
1221 hb_codepoint_t end = startGlyph + classValue.len;
1222 for (hb_codepoint_t iter = startGlyph - 1;
1223 hb_set_next (glyphs, &iter) && iter < end;)
1224 if (classValue[iter - start])
1225 return true;
1226 return false;
1227 }
1228 inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
1229 unsigned int count = classValue.len;
1230 if (klass == 0)
1231 {
1232 /* Match if there's any glyph that is not listed! */
1233 hb_codepoint_t g = HB_SET_VALUE_INVALID;
1234 if (!hb_set_next (glyphs, &g))
1235 return false;
1236 if (g < startGlyph)
1237 return true;
1238 g = startGlyph + count - 1;
1239 if (hb_set_next (glyphs, &g))
1240 return true;
1241 /* Fall through. */
1242 }
1243 for (unsigned int i = 0; i < count; i++)
1244 if (classValue[i] == klass && glyphs->has (startGlyph + i))
1245 return true;
1246 return false;
1247 }
1248
1249 protected:
1250 HBUINT16 classFormat; /* Format identifier--format = 1 */
1251 GlyphID startGlyph; /* First GlyphID of the classValueArray */
1252 ArrayOf<HBUINT16>
1253 classValue; /* Array of Class Values--one per GlyphID */
1254 public:
1255 DEFINE_SIZE_ARRAY (6, classValue);
1256};
1257
1258struct ClassDefFormat2
1259{
1260 friend struct ClassDef;
1261
1262 private:
1263 inline unsigned int get_class (hb_codepoint_t glyph_id) const
1264 {
1265 int i = rangeRecord.bsearch (glyph_id);
1266 if (unlikely (i != -1))
1267 return rangeRecord[i].value;
1268 return 0;
1269 }
1270
1271 inline bool sanitize (hb_sanitize_context_t *c) const
1272 {
1273 TRACE_SANITIZE (this);
1274 return_trace (rangeRecord.sanitize (c));
1275 }
1276
1277 template <typename set_t>
1278 inline bool add_coverage (set_t *glyphs) const
1279 {
1280 unsigned int count = rangeRecord.len;
1281 for (unsigned int i = 0; i < count; i++)
1282 if (rangeRecord[i].value)
1283 if (unlikely (!rangeRecord[i].add_coverage (glyphs)))
1284 return false;
1285 return true;
1286 }
1287
1288 template <typename set_t>
1289 inline bool add_class (set_t *glyphs, unsigned int klass) const
1290 {
1291 unsigned int count = rangeRecord.len;
1292 for (unsigned int i = 0; i < count; i++)
1293 {
1294 if (rangeRecord[i].value == klass)
1295 if (unlikely (!rangeRecord[i].add_coverage (glyphs)))
1296 return false;
1297 }
1298 return true;
1299 }
1300
1301 inline bool intersects (const hb_set_t *glyphs) const
1302 {
1303 /* TODO Speed up, using hb_set_next() and bsearch()? */
1304 unsigned int count = rangeRecord.len;
1305 for (unsigned int i = 0; i < count; i++)
1306 if (rangeRecord[i].intersects (glyphs))
1307 return true;
1308 return false;
1309 }
1310 inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const
1311 {
1312 unsigned int count = rangeRecord.len;
1313 if (klass == 0)
1314 {
1315 /* Match if there's any glyph that is not listed! */
1316 hb_codepoint_t g = HB_SET_VALUE_INVALID;
1317 for (unsigned int i = 0; i < count; i++)
1318 {
1319 if (!hb_set_next (glyphs, &g))
1320 break;
1321 if (g < rangeRecord[i].start)
1322 return true;
1323 g = rangeRecord[i].end;
1324 }
1325 if (g != HB_SET_VALUE_INVALID && hb_set_next (glyphs, &g))
1326 return true;
1327 /* Fall through. */
1328 }
1329 for (unsigned int i = 0; i < count; i++)
1330 if (rangeRecord[i].value == klass && rangeRecord[i].intersects (glyphs))
1331 return true;
1332 return false;
1333 }
1334
1335 protected:
1336 HBUINT16 classFormat; /* Format identifier--format = 2 */
1337 SortedArrayOf<RangeRecord>
1338 rangeRecord; /* Array of glyph ranges--ordered by
1339 * Start GlyphID */
1340 public:
1341 DEFINE_SIZE_ARRAY (4, rangeRecord);
1342};
1343
1344struct ClassDef
1345{
1346 inline unsigned int get_class (hb_codepoint_t glyph_id) const
1347 {
1348 switch (u.format) {
1349 case 1: return u.format1.get_class (glyph_id);
1350 case 2: return u.format2.get_class (glyph_id);
1351 default:return 0;
1352 }
1353 }
1354
1355 inline bool sanitize (hb_sanitize_context_t *c) const
1356 {
1357 TRACE_SANITIZE (this);
1358 if (!u.format.sanitize (c)) return_trace (false);
1359 switch (u.format) {
1360 case 1: return_trace (u.format1.sanitize (c));
1361 case 2: return_trace (u.format2.sanitize (c));
1362 default:return_trace (true);
1363 }
1364 }
1365
1366 /* Might return false if array looks unsorted.
1367 * Used for faster rejection of corrupt data. */
1368 template <typename set_t>
1369 inline bool add_coverage (set_t *glyphs) const {
1370 switch (u.format) {
1371 case 1: return u.format1.add_coverage (glyphs);
1372 case 2: return u.format2.add_coverage (glyphs);
1373 default:return false;
1374 }
1375 }
1376
1377 /* Might return false if array looks unsorted.
1378 * Used for faster rejection of corrupt data. */
1379 template <typename set_t>
1380 inline bool add_class (set_t *glyphs, unsigned int klass) const {
1381 switch (u.format) {
1382 case 1: return u.format1.add_class (glyphs, klass);
1383 case 2: return u.format2.add_class (glyphs, klass);
1384 default:return false;
1385 }
1386 }
1387
1388 inline bool intersects (const hb_set_t *glyphs) const {
1389 switch (u.format) {
1390 case 1: return u.format1.intersects (glyphs);
1391 case 2: return u.format2.intersects (glyphs);
1392 default:return false;
1393 }
1394 }
1395 inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
1396 switch (u.format) {
1397 case 1: return u.format1.intersects_class (glyphs, klass);
1398 case 2: return u.format2.intersects_class (glyphs, klass);
1399 default:return false;
1400 }
1401 }
1402
1403 protected:
1404 union {
1405 HBUINT16 format; /* Format identifier */
1406 ClassDefFormat1 format1;
1407 ClassDefFormat2 format2;
1408 } u;
1409 public:
1410 DEFINE_SIZE_UNION (2, format);
1411};
1412
1413
1414/*
1415 * Item Variation Store
1416 */
1417
1418struct VarRegionAxis
1419{
1420 inline float evaluate (int coord) const
1421 {
1422 int start = startCoord, peak = peakCoord, end = endCoord;
1423
1424 /* TODO Move these to sanitize(). */
1425 if (unlikely (start > peak || peak > end))
1426 return 1.;
1427 if (unlikely (start < 0 && end > 0 && peak != 0))
1428 return 1.;
1429
1430 if (peak == 0 || coord == peak)
1431 return 1.;
1432
1433 if (coord <= start || end <= coord)
1434 return 0.;
1435
1436 /* Interpolate */
1437 if (coord < peak)
1438 return float (coord - start) / (peak - start);
1439 else
1440 return float (end - coord) / (end - peak);
1441 }
1442
1443 inline bool sanitize (hb_sanitize_context_t *c) const
1444 {
1445 TRACE_SANITIZE (this);
1446 return_trace (c->check_struct (this));
1447 /* TODO Handle invalid start/peak/end configs, so we don't
1448 * have to do that at runtime. */
1449 }
1450
1451 public:
1452 F2DOT14 startCoord;
1453 F2DOT14 peakCoord;
1454 F2DOT14 endCoord;
1455 public:
1456 DEFINE_SIZE_STATIC (6);
1457};
1458
1459struct VarRegionList
1460{
1461 inline float evaluate (unsigned int region_index,
1462 int *coords, unsigned int coord_len) const
1463 {
1464 if (unlikely (region_index >= regionCount))
1465 return 0.;
1466
1467 const VarRegionAxis *axes = axesZ.arrayZ + (region_index * axisCount);
1468
1469 float v = 1.;
1470 unsigned int count = axisCount;
1471 for (unsigned int i = 0; i < count; i++)
1472 {
1473 int coord = i < coord_len ? coords[i] : 0;
1474 float factor = axes[i].evaluate (coord);
1475 if (factor == 0.f)
1476 return 0.;
1477 v *= factor;
1478 }
1479 return v;
1480 }
1481
1482 inline bool sanitize (hb_sanitize_context_t *c) const
1483 {
1484 TRACE_SANITIZE (this);
1485 return_trace (c->check_struct (this) &&
1486 axesZ.sanitize (c, (unsigned int) axisCount * (unsigned int) regionCount));
1487 }
1488
1489 protected:
1490 HBUINT16 axisCount;
1491 HBUINT16 regionCount;
1492 UnsizedArrayOf<VarRegionAxis>
1493 axesZ;
1494 public:
1495 DEFINE_SIZE_ARRAY (4, axesZ);
1496};
1497
1498struct VarData
1499{
1500 inline unsigned int get_row_size (void) const
1501 { return shortCount + regionIndices.len; }
1502
1503 inline unsigned int get_size (void) const
1504 { return itemCount * get_row_size (); }
1505
1506 inline float get_delta (unsigned int inner,
1507 int *coords, unsigned int coord_count,
1508 const VarRegionList &regions) const
1509 {
1510 if (unlikely (inner >= itemCount))
1511 return 0.;
1512
1513 unsigned int count = regionIndices.len;
1514 unsigned int scount = shortCount;
1515
1516 const HBUINT8 *bytes = &StructAfter<HBUINT8> (regionIndices);
1517 const HBUINT8 *row = bytes + inner * (scount + count);
1518
1519 float delta = 0.;
1520 unsigned int i = 0;
1521
1522 const HBINT16 *scursor = reinterpret_cast<const HBINT16 *> (row);
1523 for (; i < scount; i++)
1524 {
1525 float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count);
1526 delta += scalar * *scursor++;
1527 }
1528 const HBINT8 *bcursor = reinterpret_cast<const HBINT8 *> (scursor);
1529 for (; i < count; i++)
1530 {
1531 float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count);
1532 delta += scalar * *bcursor++;
1533 }
1534
1535 return delta;
1536 }
1537
1538 inline bool sanitize (hb_sanitize_context_t *c) const
1539 {
1540 TRACE_SANITIZE (this);
1541 return_trace (c->check_struct (this) &&
1542 regionIndices.sanitize(c) &&
1543 shortCount <= regionIndices.len &&
1544 c->check_array (&StructAfter<HBUINT8> (regionIndices),
1545 get_row_size (), itemCount));
1546 }
1547
1548 protected:
1549 HBUINT16 itemCount;
1550 HBUINT16 shortCount;
1551 ArrayOf<HBUINT16> regionIndices;
1552 HBUINT8 bytesX[VAR];
1553 public:
1554 DEFINE_SIZE_ARRAY2 (6, regionIndices, bytesX);
1555};
1556
1557struct VariationStore
1558{
1559 inline float get_delta (unsigned int outer, unsigned int inner,
1560 int *coords, unsigned int coord_count) const
1561 {
1562 if (unlikely (outer >= dataSets.len))
1563 return 0.;
1564
1565 return (this+dataSets[outer]).get_delta (inner,
1566 coords, coord_count,
1567 this+regions);
1568 }
1569
1570 inline float get_delta (unsigned int index,
1571 int *coords, unsigned int coord_count) const
1572 {
1573 unsigned int outer = index >> 16;
1574 unsigned int inner = index & 0xFFFF;
1575 return get_delta (outer, inner, coords, coord_count);
1576 }
1577
1578 inline bool sanitize (hb_sanitize_context_t *c) const
1579 {
1580 TRACE_SANITIZE (this);
1581 return_trace (c->check_struct (this) &&
1582 format == 1 &&
1583 regions.sanitize (c, this) &&
1584 dataSets.sanitize (c, this));
1585 }
1586
1587 protected:
1588 HBUINT16 format;
1589 LOffsetTo<VarRegionList> regions;
1590 OffsetArrayOf<VarData, HBUINT32> dataSets;
1591 public:
1592 DEFINE_SIZE_ARRAY (8, dataSets);
1593};
1594
1595/*
1596 * Feature Variations
1597 */
1598
1599struct ConditionFormat1
1600{
1601 friend struct Condition;
1602
1603 private:
1604 inline bool evaluate (const int *coords, unsigned int coord_len) const
1605 {
1606 int coord = axisIndex < coord_len ? coords[axisIndex] : 0;
1607 return filterRangeMinValue <= coord && coord <= filterRangeMaxValue;
1608 }
1609
1610 inline bool sanitize (hb_sanitize_context_t *c) const
1611 {
1612 TRACE_SANITIZE (this);
1613 return_trace (c->check_struct (this));
1614 }
1615
1616 protected:
1617 HBUINT16 format; /* Format identifier--format = 1 */
1618 HBUINT16 axisIndex;
1619 F2DOT14 filterRangeMinValue;
1620 F2DOT14 filterRangeMaxValue;
1621 public:
1622 DEFINE_SIZE_STATIC (8);
1623};
1624
1625struct Condition
1626{
1627 inline bool evaluate (const int *coords, unsigned int coord_len) const
1628 {
1629 switch (u.format) {
1630 case 1: return u.format1.evaluate (coords, coord_len);
1631 default:return false;
1632 }
1633 }
1634
1635 inline bool sanitize (hb_sanitize_context_t *c) const
1636 {
1637 TRACE_SANITIZE (this);
1638 if (!u.format.sanitize (c)) return_trace (false);
1639 switch (u.format) {
1640 case 1: return_trace (u.format1.sanitize (c));
1641 default:return_trace (true);
1642 }
1643 }
1644
1645 protected:
1646 union {
1647 HBUINT16 format; /* Format identifier */
1648 ConditionFormat1 format1;
1649 } u;
1650 public:
1651 DEFINE_SIZE_UNION (2, format);
1652};
1653
1654struct ConditionSet
1655{
1656 inline bool evaluate (const int *coords, unsigned int coord_len) const
1657 {
1658 unsigned int count = conditions.len;
1659 for (unsigned int i = 0; i < count; i++)
1660 if (!(this+conditions.arrayZ[i]).evaluate (coords, coord_len))
1661 return false;
1662 return true;
1663 }
1664
1665 inline bool sanitize (hb_sanitize_context_t *c) const
1666 {
1667 TRACE_SANITIZE (this);
1668 return_trace (conditions.sanitize (c, this));
1669 }
1670
1671 protected:
1672 OffsetArrayOf<Condition, HBUINT32> conditions;
1673 public:
1674 DEFINE_SIZE_ARRAY (2, conditions);
1675};
1676
1677struct FeatureTableSubstitutionRecord
1678{
1679 friend struct FeatureTableSubstitution;
1680
1681 inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
1682 {
1683 TRACE_SANITIZE (this);
1684 return_trace (c->check_struct (this) && feature.sanitize (c, base));
1685 }
1686
1687 protected:
1688 HBUINT16 featureIndex;
1689 LOffsetTo<Feature> feature;
1690 public:
1691 DEFINE_SIZE_STATIC (6);
1692};
1693
1694struct FeatureTableSubstitution
1695{
1696 inline const Feature *find_substitute (unsigned int feature_index) const
1697 {
1698 unsigned int count = substitutions.len;
1699 for (unsigned int i = 0; i < count; i++)
1700 {
1701 const FeatureTableSubstitutionRecord &record = substitutions.arrayZ[i];
1702 if (record.featureIndex == feature_index)
1703 return &(this+record.feature);
1704 }
1705 return nullptr;
1706 }
1707
1708 inline bool sanitize (hb_sanitize_context_t *c) const
1709 {
1710 TRACE_SANITIZE (this);
1711 return_trace (version.sanitize (c) &&
1712 likely (version.major == 1) &&
1713 substitutions.sanitize (c, this));
1714 }
1715
1716 protected:
1717 FixedVersion<> version; /* Version--0x00010000u */
1718 ArrayOf<FeatureTableSubstitutionRecord>
1719 substitutions;
1720 public:
1721 DEFINE_SIZE_ARRAY (6, substitutions);
1722};
1723
1724struct FeatureVariationRecord
1725{
1726 friend struct FeatureVariations;
1727
1728 inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
1729 {
1730 TRACE_SANITIZE (this);
1731 return_trace (conditions.sanitize (c, base) &&
1732 substitutions.sanitize (c, base));
1733 }
1734
1735 protected:
1736 LOffsetTo<ConditionSet>
1737 conditions;
1738 LOffsetTo<FeatureTableSubstitution>
1739 substitutions;
1740 public:
1741 DEFINE_SIZE_STATIC (8);
1742};
1743
1744struct FeatureVariations
1745{
1746 enum { NOT_FOUND_INDEX = 0xFFFFFFFFu };
1747
1748 inline bool find_index (const int *coords, unsigned int coord_len,
1749 unsigned int *index) const
1750 {
1751 unsigned int count = varRecords.len;
1752 for (unsigned int i = 0; i < count; i++)
1753 {
1754 const FeatureVariationRecord &record = varRecords.arrayZ[i];
1755 if ((this+record.conditions).evaluate (coords, coord_len))
1756 {
1757 *index = i;
1758 return true;
1759 }
1760 }
1761 *index = NOT_FOUND_INDEX;
1762 return false;
1763 }
1764
1765 inline const Feature *find_substitute (unsigned int variations_index,
1766 unsigned int feature_index) const
1767 {
1768 const FeatureVariationRecord &record = varRecords[variations_index];
1769 return (this+record.substitutions).find_substitute (feature_index);
1770 }
1771
1772 inline bool subset (hb_subset_context_t *c) const
1773 {
1774 TRACE_SUBSET (this);
1775 return_trace (c->serializer->embed (*this));
1776 }
1777
1778 inline bool sanitize (hb_sanitize_context_t *c) const
1779 {
1780 TRACE_SANITIZE (this);
1781 return_trace (version.sanitize (c) &&
1782 likely (version.major == 1) &&
1783 varRecords.sanitize (c, this));
1784 }
1785
1786 protected:
1787 FixedVersion<> version; /* Version--0x00010000u */
1788 LArrayOf<FeatureVariationRecord>
1789 varRecords;
1790 public:
1791 DEFINE_SIZE_ARRAY_SIZED (8, varRecords);
1792};
1793
1794
1795/*
1796 * Device Tables
1797 */
1798
1799struct HintingDevice
1800{
1801 friend struct Device;
1802
1803 private:
1804
1805 inline hb_position_t get_x_delta (hb_font_t *font) const
1806 { return get_delta (font->x_ppem, font->x_scale); }
1807
1808 inline hb_position_t get_y_delta (hb_font_t *font) const
1809 { return get_delta (font->y_ppem, font->y_scale); }
1810
1811 inline unsigned int get_size (void) const
1812 {
1813 unsigned int f = deltaFormat;
1814 if (unlikely (f < 1 || f > 3 || startSize > endSize)) return 3 * HBUINT16::static_size;
1815 return HBUINT16::static_size * (4 + ((endSize - startSize) >> (4 - f)));
1816 }
1817
1818 inline bool sanitize (hb_sanitize_context_t *c) const
1819 {
1820 TRACE_SANITIZE (this);
1821 return_trace (c->check_struct (this) && c->check_range (this, this->get_size ()));
1822 }
1823
1824 private:
1825
1826 inline int get_delta (unsigned int ppem, int scale) const
1827 {
1828 if (!ppem) return 0;
1829
1830 int pixels = get_delta_pixels (ppem);
1831
1832 if (!pixels) return 0;
1833
1834 return (int) (pixels * (int64_t) scale / ppem);
1835 }
1836 inline int get_delta_pixels (unsigned int ppem_size) const
1837 {
1838 unsigned int f = deltaFormat;
1839 if (unlikely (f < 1 || f > 3))
1840 return 0;
1841
1842 if (ppem_size < startSize || ppem_size > endSize)
1843 return 0;
1844
1845 unsigned int s = ppem_size - startSize;
1846
1847 unsigned int byte = deltaValue[s >> (4 - f)];
1848 unsigned int bits = (byte >> (16 - (((s & ((1 << (4 - f)) - 1)) + 1) << f)));
1849 unsigned int mask = (0xFFFFu >> (16 - (1 << f)));
1850
1851 int delta = bits & mask;
1852
1853 if ((unsigned int) delta >= ((mask + 1) >> 1))
1854 delta -= mask + 1;
1855
1856 return delta;
1857 }
1858
1859 protected:
1860 HBUINT16 startSize; /* Smallest size to correct--in ppem */
1861 HBUINT16 endSize; /* Largest size to correct--in ppem */
1862 HBUINT16 deltaFormat; /* Format of DeltaValue array data: 1, 2, or 3
1863 * 1 Signed 2-bit value, 8 values per uint16
1864 * 2 Signed 4-bit value, 4 values per uint16
1865 * 3 Signed 8-bit value, 2 values per uint16
1866 */
1867 HBUINT16 deltaValue[VAR]; /* Array of compressed data */
1868 public:
1869 DEFINE_SIZE_ARRAY (6, deltaValue);
1870};
1871
1872struct VariationDevice
1873{
1874 friend struct Device;
1875
1876 private:
1877
1878 inline hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store) const
1879 { return font->em_scalef_x (get_delta (font, store)); }
1880
1881 inline hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store) const
1882 { return font->em_scalef_y (get_delta (font, store)); }
1883
1884 inline bool sanitize (hb_sanitize_context_t *c) const
1885 {
1886 TRACE_SANITIZE (this);
1887 return_trace (c->check_struct (this));
1888 }
1889
1890 private:
1891
1892 inline float get_delta (hb_font_t *font, const VariationStore &store) const
1893 {
1894 return store.get_delta (outerIndex, innerIndex, font->coords, font->num_coords);
1895 }
1896
1897 protected:
1898 HBUINT16 outerIndex;
1899 HBUINT16 innerIndex;
1900 HBUINT16 deltaFormat; /* Format identifier for this table: 0x0x8000 */
1901 public:
1902 DEFINE_SIZE_STATIC (6);
1903};
1904
1905struct DeviceHeader
1906{
1907 protected:
1908 HBUINT16 reserved1;
1909 HBUINT16 reserved2;
1910 public:
1911 HBUINT16 format; /* Format identifier */
1912 public:
1913 DEFINE_SIZE_STATIC (6);
1914};
1915
1916struct Device
1917{
1918 inline hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store=Null(VariationStore)) const
1919 {
1920 switch (u.b.format)
1921 {
1922 case 1: case 2: case 3:
1923 return u.hinting.get_x_delta (font);
1924 case 0x8000:
1925 return u.variation.get_x_delta (font, store);
1926 default:
1927 return 0;
1928 }
1929 }
1930 inline hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store=Null(VariationStore)) const
1931 {
1932 switch (u.b.format)
1933 {
1934 case 1: case 2: case 3:
1935 return u.hinting.get_y_delta (font);
1936 case 0x8000:
1937 return u.variation.get_y_delta (font, store);
1938 default:
1939 return 0;
1940 }
1941 }
1942
1943 inline bool sanitize (hb_sanitize_context_t *c) const
1944 {
1945 TRACE_SANITIZE (this);
1946 if (!u.b.format.sanitize (c)) return_trace (false);
1947 switch (u.b.format) {
1948 case 1: case 2: case 3:
1949 return_trace (u.hinting.sanitize (c));
1950 case 0x8000:
1951 return_trace (u.variation.sanitize (c));
1952 default:
1953 return_trace (true);
1954 }
1955 }
1956
1957 protected:
1958 union {
1959 DeviceHeader b;
1960 HintingDevice hinting;
1961 VariationDevice variation;
1962 } u;
1963 public:
1964 DEFINE_SIZE_UNION (6, b);
1965};
1966
1967
1968} /* namespace OT */
1969
1970
1971#endif /* HB_OT_LAYOUT_COMMON_HH */
1972