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

source code of qtbase/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-common-private.hh