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