|
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 inline int cmp (hb_tag_t a) const { |
|
73 return tag.cmp (a); |
|
74 } |
|
75 |
|
76 struct sanitize_closure_t { |
|
77 hb_tag_t tag; |
|
78 const void *list_base; |
|
79 }; |
|
80 inline bool sanitize (hb_sanitize_context_t *c, const void *base) const |
|
81 { |
|
82 TRACE_SANITIZE (this); |
|
83 const sanitize_closure_t closure = {tag, base}; |
|
84 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 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 if (unlikely (i >= this->len)) return Null(Tag); |
|
103 return (*this)[i].tag; |
|
104 } |
|
105 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 if (record_count) { |
|
110 const Record<Type> *arr = this->sub_array (start_offset, record_count); |
|
111 unsigned int count = *record_count; |
|
112 for (unsigned int i = 0; i < count; i++) |
|
113 record_tags[i] = arr[i].tag; |
|
114 } |
|
115 return this->len; |
|
116 } |
|
117 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 int i = this->/*lsearch*/bsearch (tag); |
|
121 if (i != -1) { |
|
122 if (index) *index = i; |
|
123 return true; |
|
124 } else { |
|
125 if (index) *index = Index::NOT_FOUND_INDEX; |
|
126 return false; |
|
127 } |
|
128 } |
|
129 }; |
|
130 |
|
131 template <typename Type> |
|
132 struct RecordListOf : RecordArrayOf<Type> |
|
133 { |
|
134 inline const Type& operator [] (unsigned int i) const |
|
135 { return this+RecordArrayOf<Type>::operator [](i).offset; } |
|
136 |
|
137 inline bool sanitize (hb_sanitize_context_t *c) const |
|
138 { |
|
139 TRACE_SANITIZE (this); |
|
140 return_trace (RecordArrayOf<Type>::sanitize (c, this)); |
|
141 } |
|
142 }; |
|
143 |
|
144 |
|
145 struct RangeRecord |
|
146 { |
|
147 inline int cmp (hb_codepoint_t g) const { |
|
148 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 inline bool intersects (const hb_set_t *glyphs) const { |
|
158 return glyphs->intersects (start, end); |
|
159 } |
|
160 |
|
161 template <typename set_t> |
|
162 inline void add_coverage (set_t *glyphs) const { |
|
163 glyphs->add_range (start, end); |
|
164 } |
|
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 DEFINE_NULL_DATA (RangeRecord, "\000\001"); |
|
173 |
|
174 |
|
175 struct IndexArray : ArrayOf<Index> |
|
176 { |
|
177 inline unsigned int get_indexes (unsigned int start_offset, |
|
178 unsigned int *_count /* IN/OUT */, |
|
179 unsigned int *_indexes /* OUT */) const |
|
180 { |
|
181 if (_count) { |
|
182 const USHORT *arr = this->sub_array (start_offset, _count); |
|
183 unsigned int count = *_count; |
|
184 for (unsigned int i = 0; i < count; i++) |
|
185 _indexes[i] = arr[i]; |
|
186 } |
|
187 return this->len; |
|
188 } |
|
189 }; |
|
190 |
|
191 |
|
192 struct Script; |
|
193 struct LangSys; |
|
194 struct Feature; |
|
195 |
|
196 |
|
197 struct LangSys |
|
198 { |
|
199 inline unsigned int get_feature_count (void) const |
|
200 { return featureIndex.len; } |
|
201 inline hb_tag_t get_feature_index (unsigned int i) const |
|
202 { return featureIndex[i]; } |
|
203 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 { return featureIndex.get_indexes (start_offset, feature_count, feature_indexes); } |
|
207 |
|
208 inline bool has_required_feature (void) const { return reqFeatureIndex != 0xFFFFu; } |
|
209 inline unsigned int get_required_feature_index (void) const |
|
210 { |
|
211 if (reqFeatureIndex == 0xFFFFu) |
|
212 return Index::NOT_FOUND_INDEX; |
|
213 return reqFeatureIndex;; |
|
214 } |
|
215 |
|
216 inline bool sanitize (hb_sanitize_context_t *c, |
|
217 const Record<LangSys>::sanitize_closure_t * = NULL) const |
|
218 { |
|
219 TRACE_SANITIZE (this); |
|
220 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 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 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 { return langSys.get_tags (start_offset, lang_sys_count, lang_sys_tags); } |
|
245 inline const LangSys& get_lang_sys (unsigned int i) const |
|
246 { |
|
247 if (i == Index::NOT_FOUND_INDEX) return get_default_lang_sys (); |
|
248 return this+langSys[i].offset; |
|
249 } |
|
250 inline bool find_lang_sys_index (hb_tag_t tag, unsigned int *index) const |
|
251 { return langSys.find_index (tag, index); } |
|
252 |
|
253 inline bool has_default_lang_sys (void) const { return defaultLangSys != 0; } |
|
254 inline const LangSys& get_default_lang_sys (void) const { return this+defaultLangSys; } |
|
255 |
|
256 inline bool sanitize (hb_sanitize_context_t *c, |
|
257 const Record<Script>::sanitize_closure_t * = NULL) const |
|
258 { |
|
259 TRACE_SANITIZE (this); |
|
260 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 inline bool sanitize (hb_sanitize_context_t *c) const |
|
281 { |
|
282 TRACE_SANITIZE (this); |
|
283 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 if (!designSize) |
|
335 return_trace (false); |
|
336 else if (subfamilyID == 0 && |
|
337 subfamilyNameID == 0 && |
|
338 rangeStart == 0 && |
|
339 rangeEnd == 0) |
|
340 return_trace (true); |
|
341 else if (designSize < rangeStart || |
|
342 designSize > rangeEnd || |
|
343 subfamilyNameID < 256 || |
|
344 subfamilyNameID > 32767) |
|
345 return_trace (false); |
|
346 else |
|
347 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 inline bool sanitize (hb_sanitize_context_t *c) const |
|
393 { |
|
394 TRACE_SANITIZE (this); |
|
395 /* Right now minorVersion is at zero. Which means, any table supports |
|
396 * the uiNameID field. */ |
|
397 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 inline bool sanitize (hb_sanitize_context_t *c) const |
|
427 { |
|
428 TRACE_SANITIZE (this); |
|
429 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 inline bool sanitize (hb_sanitize_context_t *c, hb_tag_t tag) const |
|
468 { |
|
469 TRACE_SANITIZE (this); |
|
470 if (tag == HB_TAG ('s','i','z','e')) |
|
471 return_trace (u.size.sanitize (c)); |
|
472 if ((tag & 0xFFFF0000u) == HB_TAG ('s','s','\0','\0')) /* ssXX */ |
|
473 return_trace (u.stylisticSet.sanitize (c)); |
|
474 if ((tag & 0xFFFF0000u) == HB_TAG ('c','v','\0','\0')) /* cvXX */ |
|
475 return_trace (u.characterVariants.sanitize (c)); |
|
476 return_trace (true); |
|
477 } |
|
478 |
|
479 inline const FeatureParamsSize& get_size_params (hb_tag_t tag) const |
|
480 { |
|
481 if (tag == HB_TAG ('s','i','z','e')) |
|
482 return u.size; |
|
483 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 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 { return lookupIndex.get_indexes (start_index, lookup_count, lookup_tags); } |
|
505 |
|
506 inline const FeatureParams &get_feature_params (void) const |
|
507 { return this+featureParams; } |
|
508 |
|
509 inline bool sanitize (hb_sanitize_context_t *c, |
|
510 const Record<Feature>::sanitize_closure_t *closure = NULL) const |
|
511 { |
|
512 TRACE_SANITIZE (this); |
|
513 if (unlikely (!(c->check_struct (this) && lookupIndex.sanitize (c)))) |
|
514 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 OffsetTo<FeatureParams> orig_offset = featureParams; |
|
528 if (unlikely (!featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE))) |
|
529 return_trace (false); |
|
530 |
|
531 if (likely (orig_offset.is_null ())) |
|
532 return_trace (true); |
|
533 |
|
534 if (featureParams == 0 && closure && |
|
535 closure->tag == HB_TAG ('s','i','z','e') && |
|
536 closure->list_base && closure->list_base < this) |
|
537 { |
|
538 unsigned int new_offset_int = (unsigned int) orig_offset - |
|
539 (((char *) this) - ((char *) closure->list_base)); |
|
540 |
|
541 OffsetTo<FeatureParams> new_offset; |
|
542 /* Check that it did not overflow. */ |
|
543 new_offset.set (new_offset_int); |
|
544 if (new_offset == new_offset_int && |
|
545 c->try_set (&featureParams, new_offset) && |
|
546 !featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE)) |
|
547 return_trace (false); |
|
548 |
|
549 if (c->edit_count > 1) |
|
550 c->edit_count--; /* This was a "legitimate" edit; don't contribute to error count. */ |
|
551 } |
|
552 |
|
553 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 HB_MARK_AS_FLAG_T (OT::LookupFlag::Flags); |
|
588 namespace OT { |
|
589 |
|
590 struct Lookup |
|
591 { |
|
592 inline unsigned int get_subtable_count (void) const { return subTable.len; } |
|
593 |
|
594 template <typename SubTableType> |
|
595 inline const SubTableType& get_subtable (unsigned int i) const |
|
596 { 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 inline OffsetArrayOf<SubTableType>& get_subtables (void) |
|
603 { return CastR<OffsetArrayOf<SubTableType> > (subTable); } |
|
604 |
|
605 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 inline uint32_t get_props (void) const |
|
611 { |
|
612 unsigned int flag = lookupFlag; |
|
613 if (unlikely (flag & LookupFlag::UseMarkFilteringSet)) |
|
614 { |
|
615 const USHORT &markFilteringSet = StructAfter<USHORT> (subTable); |
|
616 flag += (markFilteringSet << 16); |
|
617 } |
|
618 return flag; |
|
619 } |
|
620 |
|
621 template <typename SubTableType, typename context_t> |
|
622 inline typename context_t::return_t dispatch (context_t *c) const |
|
623 { |
|
624 unsigned int lookup_type = get_type (); |
|
625 TRACE_DISPATCH (this, lookup_type); |
|
626 unsigned int count = get_subtable_count (); |
|
627 for (unsigned int i = 0; i < count; i++) { |
|
628 typename context_t::return_t r = get_subtable<SubTableType> (i).dispatch (c, lookup_type); |
|
629 if (c->stop_sublookup_iteration (r)) |
|
630 return_trace (r); |
|
631 } |
|
632 return_trace (c->default_return_value ()); |
|
633 } |
|
634 |
|
635 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 TRACE_SERIALIZE (this); |
|
641 if (unlikely (!c->extend_min (*this))) return_trace (false); |
|
642 lookupType.set (lookup_type); |
|
643 lookupFlag.set (lookup_props & 0xFFFFu); |
|
644 if (unlikely (!subTable.serialize (c, num_subtables))) return_trace (false); |
|
645 if (lookupFlag & LookupFlag::UseMarkFilteringSet) |
|
646 { |
|
647 USHORT &markFilteringSet = StructAfter<USHORT> (subTable); |
|
648 markFilteringSet.set (lookup_props >> 16); |
|
649 } |
|
650 return_trace (true); |
|
651 } |
|
652 |
|
653 inline bool sanitize (hb_sanitize_context_t *c) const |
|
654 { |
|
655 TRACE_SANITIZE (this); |
|
656 /* Real sanitize of the subtables is done by GSUB/GPOS/... */ |
|
657 if (!(c->check_struct (this) && subTable.sanitize (c))) return_trace (false); |
|
658 if (lookupFlag & LookupFlag::UseMarkFilteringSet) |
|
659 { |
|
660 const USHORT &markFilteringSet = StructAfter<USHORT> (subTable); |
|
661 if (!markFilteringSet.sanitize (c)) return_trace (false); |
|
662 } |
|
663 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 inline unsigned int get_coverage (hb_codepoint_t glyph_id) const |
|
691 { |
|
692 int i = glyphArray.bsearch (glyph_id); |
|
693 ASSERT_STATIC (((unsigned int) -1) == NOT_COVERED); |
|
694 return i; |
|
695 } |
|
696 |
|
697 inline bool serialize (hb_serialize_context_t *c, |
|
698 Supplier<GlyphID> &glyphs, |
|
699 unsigned int num_glyphs) |
|
700 { |
|
701 TRACE_SERIALIZE (this); |
|
702 if (unlikely (!c->extend_min (*this))) return_trace (false); |
|
703 glyphArray.len.set (num_glyphs); |
|
704 if (unlikely (!c->extend (glyphArray))) return_trace (false); |
|
705 for (unsigned int i = 0; i < num_glyphs; i++) |
|
706 glyphArray[i] = glyphs[i]; |
|
707 glyphs.advance (num_glyphs); |
|
708 return_trace (true); |
|
709 } |
|
710 |
|
711 inline bool sanitize (hb_sanitize_context_t *c) const |
|
712 { |
|
713 TRACE_SANITIZE (this); |
|
714 return_trace (glyphArray.sanitize (c)); |
|
715 } |
|
716 |
|
717 inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const { |
|
718 return glyphs->has (glyphArray[index]); |
|
719 } |
|
720 |
|
721 template <typename set_t> |
|
722 inline void add_coverage (set_t *glyphs) const { |
|
723 unsigned int count = glyphArray.len; |
|
724 for (unsigned int i = 0; i < count; i++) |
|
725 glyphs->add (glyphArray[i]); |
|
726 } |
|
727 |
|
728 public: |
|
729 /* Older compilers need this to be public. */ |
|
730 struct Iter { |
|
731 inline void init (const struct CoverageFormat1 &c_) { c = &c_; i = 0; }; |
|
732 inline bool more (void) { return i < c->glyphArray.len; } |
|
733 inline void next (void) { i++; } |
|
734 inline hb_codepoint_t get_glyph (void) { return c->glyphArray[i]; } |
|
735 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 inline unsigned int get_coverage (hb_codepoint_t glyph_id) const |
|
757 { |
|
758 int i = rangeRecord.bsearch (glyph_id); |
|
759 if (i != -1) { |
|
760 const RangeRecord &range = rangeRecord[i]; |
|
761 return (unsigned int) range.value + (glyph_id - range.start); |
|
762 } |
|
763 return NOT_COVERED; |
|
764 } |
|
765 |
|
766 inline bool serialize (hb_serialize_context_t *c, |
|
767 Supplier<GlyphID> &glyphs, |
|
768 unsigned int num_glyphs) |
|
769 { |
|
770 TRACE_SERIALIZE (this); |
|
771 if (unlikely (!c->extend_min (*this))) return_trace (false); |
|
772 |
|
773 if (unlikely (!num_glyphs)) |
|
774 { |
|
775 rangeRecord.len.set (0); |
|
776 return_trace (true); |
|
777 } |
|
778 |
|
779 unsigned int num_ranges = 1; |
|
780 for (unsigned int i = 1; i < num_glyphs; i++) |
|
781 if (glyphs[i - 1] + 1 != glyphs[i]) |
|
782 num_ranges++; |
|
783 rangeRecord.len.set (num_ranges); |
|
784 if (unlikely (!c->extend (rangeRecord))) return_trace (false); |
|
785 |
|
786 unsigned int range = 0; |
|
787 rangeRecord[range].start = glyphs[0]; |
|
788 rangeRecord[range].value.set (0); |
|
789 for (unsigned int i = 1; i < num_glyphs; i++) |
|
790 if (glyphs[i - 1] + 1 != glyphs[i]) { |
|
791 range++; |
|
792 rangeRecord[range].start = glyphs[i]; |
|
793 rangeRecord[range].value.set (i); |
|
794 rangeRecord[range].end = glyphs[i]; |
|
795 } else { |
|
796 rangeRecord[range].end = glyphs[i]; |
|
797 } |
|
798 glyphs.advance (num_glyphs); |
|
799 return_trace (true); |
|
800 } |
|
801 |
|
802 inline bool sanitize (hb_sanitize_context_t *c) const |
|
803 { |
|
804 TRACE_SANITIZE (this); |
|
805 return_trace (rangeRecord.sanitize (c)); |
|
806 } |
|
807 |
|
808 inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const { |
|
809 unsigned int i; |
|
810 unsigned int count = rangeRecord.len; |
|
811 for (i = 0; i < count; i++) { |
|
812 const RangeRecord &range = rangeRecord[i]; |
|
813 if (range.value <= index && |
|
814 index < (unsigned int) range.value + (range.end - range.start) && |
|
815 range.intersects (glyphs)) |
|
816 return true; |
|
817 else if (index < range.value) |
|
818 return false; |
|
819 } |
|
820 return false; |
|
821 } |
|
822 |
|
823 template <typename set_t> |
|
824 inline void add_coverage (set_t *glyphs) const { |
|
825 unsigned int count = rangeRecord.len; |
|
826 for (unsigned int i = 0; i < count; i++) |
|
827 rangeRecord[i].add_coverage (glyphs); |
|
828 } |
|
829 |
|
830 public: |
|
831 /* Older compilers need this to be public. */ |
|
832 struct Iter |
|
833 { |
|
834 inline void init (const CoverageFormat2 &c_) |
|
835 { |
|
836 c = &c_; |
|
837 coverage = 0; |
|
838 i = 0; |
|
839 j = c->rangeRecord.len ? c_.rangeRecord[0].start : 0; |
|
840 } |
|
841 inline bool more (void) { return i < c->rangeRecord.len; } |
|
842 inline void next (void) |
|
843 { |
|
844 if (j >= c->rangeRecord[i].end) |
|
845 { |
|
846 i++; |
|
847 if (more ()) |
|
848 { |
|
849 j = c->rangeRecord[i].start; |
|
850 coverage = c->rangeRecord[i].value; |
|
851 } |
|
852 return; |
|
853 } |
|
854 coverage++; |
|
855 j++; |
|
856 } |
|
857 inline hb_codepoint_t get_glyph (void) { return j; } |
|
858 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 inline unsigned int get_coverage (hb_codepoint_t glyph_id) const |
|
879 { |
|
880 switch (u.format) { |
|
881 case 1: return u.format1.get_coverage(glyph_id); |
|
882 case 2: return u.format2.get_coverage(glyph_id); |
|
883 default:return NOT_COVERED; |
|
884 } |
|
885 } |
|
886 |
|
887 inline bool serialize (hb_serialize_context_t *c, |
|
888 Supplier<GlyphID> &glyphs, |
|
889 unsigned int num_glyphs) |
|
890 { |
|
891 TRACE_SERIALIZE (this); |
|
892 if (unlikely (!c->extend_min (*this))) return_trace (false); |
|
893 unsigned int num_ranges = 1; |
|
894 for (unsigned int i = 1; i < num_glyphs; i++) |
|
895 if (glyphs[i - 1] + 1 != glyphs[i]) |
|
896 num_ranges++; |
|
897 u.format.set (num_glyphs * 2 < num_ranges * 3 ? 1 : 2); |
|
898 switch (u.format) { |
|
899 case 1: return_trace (u.format1.serialize (c, glyphs, num_glyphs)); |
|
900 case 2: return_trace (u.format2.serialize (c, glyphs, num_glyphs)); |
|
901 default:return_trace (false); |
|
902 } |
|
903 } |
|
904 |
|
905 inline bool sanitize (hb_sanitize_context_t *c) const |
|
906 { |
|
907 TRACE_SANITIZE (this); |
|
908 if (!u.format.sanitize (c)) return_trace (false); |
|
909 switch (u.format) { |
|
910 case 1: return_trace (u.format1.sanitize (c)); |
|
911 case 2: return_trace (u.format2.sanitize (c)); |
|
912 default:return_trace (true); |
|
913 } |
|
914 } |
|
915 |
|
916 inline bool intersects (const hb_set_t *glyphs) const { |
|
917 /* TODO speed this up */ |
|
918 Coverage::Iter iter; |
|
919 for (iter.init (*this); iter.more (); iter.next ()) { |
|
920 if (glyphs->has (iter.get_glyph ())) |
|
921 return true; |
|
922 } |
|
923 return false; |
|
924 } |
|
925 |
|
926 inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const { |
|
927 switch (u.format) { |
|
928 case 1: return u.format1.intersects_coverage (glyphs, index); |
|
929 case 2: return u.format2.intersects_coverage (glyphs, index); |
|
930 default:return false; |
|
931 } |
|
932 } |
|
933 |
|
934 template <typename set_t> |
|
935 inline void add_coverage (set_t *glyphs) const { |
|
936 switch (u.format) { |
|
937 case 1: u.format1.add_coverage (glyphs); break; |
|
938 case 2: u.format2.add_coverage (glyphs); break; |
|
939 default: break; |
|
940 } |
|
941 } |
|
942 |
|
943 struct Iter { |
|
944 Iter (void) : format (0) {}; |
|
945 inline void init (const Coverage &c_) { |
|
946 format = c_.u.format; |
|
947 switch (format) { |
|
948 case 1: u.format1.init (c_.u.format1); return; |
|
949 case 2: u.format2.init (c_.u.format2); return; |
|
950 default: return; |
|
951 } |
|
952 } |
|
953 inline bool more (void) { |
|
954 switch (format) { |
|
955 case 1: return u.format1.more (); |
|
956 case 2: return u.format2.more (); |
|
957 default:return false; |
|
958 } |
|
959 } |
|
960 inline void next (void) { |
|
961 switch (format) { |
|
962 case 1: u.format1.next (); break; |
|
963 case 2: u.format2.next (); break; |
|
964 default: break; |
|
965 } |
|
966 } |
|
967 inline hb_codepoint_t get_glyph (void) { |
|
968 switch (format) { |
|
969 case 1: return u.format1.get_glyph (); |
|
970 case 2: return u.format2.get_glyph (); |
|
971 default:return 0; |
|
972 } |
|
973 } |
|
974 inline unsigned int get_coverage (void) { |
|
975 switch (format) { |
|
976 case 1: return u.format1.get_coverage (); |
|
977 case 2: return u.format2.get_coverage (); |
|
978 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 inline unsigned int get_class (hb_codepoint_t glyph_id) const |
|
1011 { |
|
1012 unsigned int i = (unsigned int) (glyph_id - startGlyph); |
|
1013 if (unlikely (i < classValue.len)) |
|
1014 return classValue[i]; |
|
1015 return 0; |
|
1016 } |
|
1017 |
|
1018 inline bool sanitize (hb_sanitize_context_t *c) const |
|
1019 { |
|
1020 TRACE_SANITIZE (this); |
|
1021 return_trace (c->check_struct (this) && classValue.sanitize (c)); |
|
1022 } |
|
1023 |
|
1024 template <typename set_t> |
|
1025 inline void add_class (set_t *glyphs, unsigned int klass) const { |
|
1026 unsigned int count = classValue.len; |
|
1027 for (unsigned int i = 0; i < count; i++) |
|
1028 if (classValue[i] == klass) |
|
1029 glyphs->add (startGlyph + i); |
|
1030 } |
|
1031 |
|
1032 inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const { |
|
1033 unsigned int count = classValue.len; |
|
1034 if (klass == 0) |
|
1035 { |
|
1036 /* Match if there's any glyph that is not listed! */ |
|
1037 hb_codepoint_t g = -1; |
|
1038 if (!hb_set_next (glyphs, &g)) |
|
1039 return false; |
|
1040 if (g < startGlyph) |
|
1041 return true; |
|
1042 g = startGlyph + count - 1; |
|
1043 if (hb_set_next (glyphs, &g)) |
|
1044 return true; |
|
1045 /* Fall through. */ |
|
1046 } |
|
1047 for (unsigned int i = 0; i < count; i++) |
|
1048 if (classValue[i] == klass && glyphs->has (startGlyph + i)) |
|
1049 return true; |
|
1050 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 inline unsigned int get_class (hb_codepoint_t glyph_id) const |
|
1068 { |
|
1069 int i = rangeRecord.bsearch (glyph_id); |
|
1070 if (unlikely (i != -1)) |
|
1071 return rangeRecord[i].value; |
|
1072 return 0; |
|
1073 } |
|
1074 |
|
1075 inline bool sanitize (hb_sanitize_context_t *c) const |
|
1076 { |
|
1077 TRACE_SANITIZE (this); |
|
1078 return_trace (rangeRecord.sanitize (c)); |
|
1079 } |
|
1080 |
|
1081 template <typename set_t> |
|
1082 inline void add_class (set_t *glyphs, unsigned int klass) const { |
|
1083 unsigned int count = rangeRecord.len; |
|
1084 for (unsigned int i = 0; i < count; i++) |
|
1085 if (rangeRecord[i].value == klass) |
|
1086 rangeRecord[i].add_coverage (glyphs); |
|
1087 } |
|
1088 |
|
1089 inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const { |
|
1090 unsigned int count = rangeRecord.len; |
|
1091 if (klass == 0) |
|
1092 { |
|
1093 /* Match if there's any glyph that is not listed! */ |
|
1094 hb_codepoint_t g = (hb_codepoint_t) -1; |
|
1095 for (unsigned int i = 0; i < count; i++) |
|
1096 { |
|
1097 if (!hb_set_next (glyphs, &g)) |
|
1098 break; |
|
1099 if (g < rangeRecord[i].start) |
|
1100 return true; |
|
1101 g = rangeRecord[i].end; |
|
1102 } |
|
1103 if (g != (hb_codepoint_t) -1 && hb_set_next (glyphs, &g)) |
|
1104 return true; |
|
1105 /* Fall through. */ |
|
1106 } |
|
1107 for (unsigned int i = 0; i < count; i++) |
|
1108 if (rangeRecord[i].value == klass && rangeRecord[i].intersects (glyphs)) |
|
1109 return true; |
|
1110 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 inline unsigned int get_class (hb_codepoint_t glyph_id) const |
|
1125 { |
|
1126 switch (u.format) { |
|
1127 case 1: return u.format1.get_class(glyph_id); |
|
1128 case 2: return u.format2.get_class(glyph_id); |
|
1129 default:return 0; |
|
1130 } |
|
1131 } |
|
1132 |
|
1133 inline bool sanitize (hb_sanitize_context_t *c) const |
|
1134 { |
|
1135 TRACE_SANITIZE (this); |
|
1136 if (!u.format.sanitize (c)) return_trace (false); |
|
1137 switch (u.format) { |
|
1138 case 1: return_trace (u.format1.sanitize (c)); |
|
1139 case 2: return_trace (u.format2.sanitize (c)); |
|
1140 default:return_trace (true); |
|
1141 } |
|
1142 } |
|
1143 |
|
1144 inline void add_class (hb_set_t *glyphs, unsigned int klass) const { |
|
1145 switch (u.format) { |
|
1146 case 1: u.format1.add_class (glyphs, klass); return; |
|
1147 case 2: u.format2.add_class (glyphs, klass); return; |
|
1148 default:return; |
|
1149 } |
|
1150 } |
|
1151 |
|
1152 inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const { |
|
1153 switch (u.format) { |
|
1154 case 1: return u.format1.intersects_class (glyphs, klass); |
|
1155 case 2: return u.format2.intersects_class (glyphs, klass); |
|
1156 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 inline float evaluate (int coord) const |
|
1178 { |
|
1179 int start = startCoord, peak = peakCoord, end = endCoord; |
|
1180 |
|
1181 /* TODO Move these to sanitize(). */ |
|
1182 if (unlikely (start > peak || peak > end)) |
|
1183 return 1.; |
|
1184 if (unlikely (start < 0 && end > 0 && peak != 0)) |
|
1185 return 1.; |
|
1186 |
|
1187 if (peak == 0 || coord == peak) |
|
1188 return 1.; |
|
1189 |
|
1190 if (coord <= start || end <= coord) |
|
1191 return 0.; |
|
1192 |
|
1193 /* Interpolate */ |
|
1194 if (coord < peak) |
|
1195 return float (coord - start) / (peak - start); |
|
1196 else |
|
1197 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 inline float evaluate (unsigned int region_index, |
|
1219 int *coords, unsigned int coord_len) const |
|
1220 { |
|
1221 if (unlikely (region_index >= regionCount)) |
|
1222 return 0.; |
|
1223 |
|
1224 const VarRegionAxis *axes = axesZ + (region_index * axisCount); |
|
1225 |
|
1226 float v = 1.; |
|
1227 unsigned int count = MIN (coord_len, (unsigned int) axisCount); |
|
1228 for (unsigned int i = 0; i < count; i++) |
|
1229 { |
|
1230 float factor = axes[i].evaluate (coords[i]); |
|
1231 if (factor == 0.) |
|
1232 return 0.; |
|
1233 v *= factor; |
|
1234 } |
|
1235 return v; |
|
1236 } |
|
1237 |
|
1238 inline bool sanitize (hb_sanitize_context_t *c) const |
|
1239 { |
|
1240 TRACE_SANITIZE (this); |
|
1241 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 inline unsigned int get_row_size (void) const |
|
1257 { return shortCount + regionIndices.len; } |
|
1258 |
|
1259 inline unsigned int get_size (void) const |
|
1260 { return itemCount * get_row_size (); } |
|
1261 |
|
1262 inline float get_delta (unsigned int inner, |
|
1263 int *coords, unsigned int coord_count, |
|
1264 const VarRegionList ®ions) const |
|
1265 { |
|
1266 if (unlikely (inner >= itemCount)) |
|
1267 return 0.; |
|
1268 |
|
1269 unsigned int count = regionIndices.len; |
|
1270 unsigned int scount = shortCount; |
|
1271 |
|
1272 const BYTE *bytes = &StructAfter<BYTE> (regionIndices); |
|
1273 const BYTE *row = bytes + inner * (scount + count); |
|
1274 |
|
1275 float delta = 0.; |
|
1276 unsigned int i = 0; |
|
1277 |
|
1278 const SHORT *scursor = reinterpret_cast<const SHORT *> (row); |
|
1279 for (; i < scount; i++) |
|
1280 { |
|
1281 float scalar = regions.evaluate (regionIndices.array[i], coords, coord_count); |
|
1282 delta += scalar * *scursor++; |
|
1283 } |
|
1284 const INT8 *bcursor = reinterpret_cast<const INT8 *> (scursor); |
|
1285 for (; i < count; i++) |
|
1286 { |
|
1287 float scalar = regions.evaluate (regionIndices.array[i], coords, coord_count); |
|
1288 delta += scalar * *bcursor++; |
|
1289 } |
|
1290 |
|
1291 return delta; |
|
1292 } |
|
1293 |
|
1294 inline bool sanitize (hb_sanitize_context_t *c) const |
|
1295 { |
|
1296 TRACE_SANITIZE (this); |
|
1297 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 inline float get_delta (unsigned int outer, unsigned int inner, |
|
1316 int *coords, unsigned int coord_count) const |
|
1317 { |
|
1318 if (unlikely (outer >= dataSets.len)) |
|
1319 return 0.; |
|
1320 |
|
1321 return (this+dataSets[outer]).get_delta (inner, |
|
1322 coords, coord_count, |
|
1323 this+regions); |
|
1324 } |
|
1325 |
|
1326 inline bool sanitize (hb_sanitize_context_t *c) const |
|
1327 { |
|
1328 TRACE_SANITIZE (this); |
|
1329 return_trace (c->check_struct (this) && |
|
1330 format == 1 && |
|
1331 regions.sanitize (c, this) && |
|
1332 dataSets.sanitize (c, this)); |
|
1333 } |
|
1334 |
|
1335 protected: |
|
1336 USHORT format; |
|
1337 OffsetTo<VarRegionList, ULONG> regions; |
|
1338 OffsetArrayOf<VarData, ULONG> dataSets; |
|
1339 public: |
|
1340 DEFINE_SIZE_ARRAY (8, dataSets); |
|
1341 }; |
|
1342 |
|
1343 /* |
|
1344 * Feature Variations |
|
1345 */ |
|
1346 |
|
1347 struct ConditionFormat1 |
|
1348 { |
|
1349 friend struct Condition; |
|
1350 |
|
1351 private: |
|
1352 inline bool evaluate (const int *coords, unsigned int coord_len) const |
|
1353 { |
|
1354 int coord = axisIndex < coord_len ? coords[axisIndex] : 0; |
|
1355 return filterRangeMinValue <= coord && coord <= filterRangeMaxValue; |
|
1356 } |
|
1357 |
|
1358 inline bool sanitize (hb_sanitize_context_t *c) const |
|
1359 { |
|
1360 TRACE_SANITIZE (this); |
|
1361 return_trace (c->check_struct (this)); |
|
1362 } |
|
1363 |
|
1364 protected: |
|
1365 USHORT format; /* Format identifier--format = 1 */ |
|
1366 USHORT axisIndex; |
|
1367 F2DOT14 filterRangeMinValue; |
|
1368 F2DOT14 filterRangeMaxValue; |
|
1369 public: |
|
1370 DEFINE_SIZE_STATIC (8); |
|
1371 }; |
|
1372 |
|
1373 struct Condition |
|
1374 { |
|
1375 inline bool evaluate (const int *coords, unsigned int coord_len) const |
|
1376 { |
|
1377 switch (u.format) { |
|
1378 case 1: return u.format1.evaluate (coords, coord_len); |
|
1379 default:return false; |
|
1380 } |
|
1381 } |
|
1382 |
|
1383 inline bool sanitize (hb_sanitize_context_t *c) const |
|
1384 { |
|
1385 TRACE_SANITIZE (this); |
|
1386 if (!u.format.sanitize (c)) return_trace (false); |
|
1387 switch (u.format) { |
|
1388 case 1: return_trace (u.format1.sanitize (c)); |
|
1389 default:return_trace (true); |
|
1390 } |
|
1391 } |
|
1392 |
|
1393 protected: |
|
1394 union { |
|
1395 USHORT format; /* Format identifier */ |
|
1396 ConditionFormat1 format1; |
|
1397 } u; |
|
1398 public: |
|
1399 DEFINE_SIZE_UNION (2, format); |
|
1400 }; |
|
1401 |
|
1402 struct ConditionSet |
|
1403 { |
|
1404 inline bool evaluate (const int *coords, unsigned int coord_len) const |
|
1405 { |
|
1406 unsigned int count = conditions.len; |
|
1407 for (unsigned int i = 0; i < count; i++) |
|
1408 if (!(this+conditions.array[i]).evaluate (coords, coord_len)) |
|
1409 return false; |
|
1410 return true; |
|
1411 } |
|
1412 |
|
1413 inline bool sanitize (hb_sanitize_context_t *c) const |
|
1414 { |
|
1415 TRACE_SANITIZE (this); |
|
1416 return_trace (conditions.sanitize (c, this)); |
|
1417 } |
|
1418 |
|
1419 protected: |
|
1420 OffsetArrayOf<Condition, ULONG> conditions; |
|
1421 public: |
|
1422 DEFINE_SIZE_ARRAY (2, conditions); |
|
1423 }; |
|
1424 |
|
1425 struct FeatureTableSubstitutionRecord |
|
1426 { |
|
1427 friend struct FeatureTableSubstitution; |
|
1428 |
|
1429 inline bool sanitize (hb_sanitize_context_t *c, const void *base) const |
|
1430 { |
|
1431 TRACE_SANITIZE (this); |
|
1432 return_trace (c->check_struct (this) && feature.sanitize (c, base)); |
|
1433 } |
|
1434 |
|
1435 protected: |
|
1436 USHORT featureIndex; |
|
1437 OffsetTo<Feature, ULONG> feature; |
|
1438 public: |
|
1439 DEFINE_SIZE_STATIC (6); |
|
1440 }; |
|
1441 |
|
1442 struct FeatureTableSubstitution |
|
1443 { |
|
1444 inline const Feature *find_substitute (unsigned int feature_index) const |
|
1445 { |
|
1446 unsigned int count = substitutions.len; |
|
1447 for (unsigned int i = 0; i < count; i++) |
|
1448 { |
|
1449 const FeatureTableSubstitutionRecord &record = substitutions.array[i]; |
|
1450 if (record.featureIndex == feature_index) |
|
1451 return &(this+record.feature); |
|
1452 } |
|
1453 return NULL; |
|
1454 } |
|
1455 |
|
1456 inline bool sanitize (hb_sanitize_context_t *c) const |
|
1457 { |
|
1458 TRACE_SANITIZE (this); |
|
1459 return_trace (version.sanitize (c) && |
|
1460 likely (version.major == 1) && |
|
1461 substitutions.sanitize (c, this)); |
|
1462 } |
|
1463 |
|
1464 protected: |
|
1465 FixedVersion<> version; /* Version--0x00010000u */ |
|
1466 ArrayOf<FeatureTableSubstitutionRecord> |
|
1467 substitutions; |
|
1468 public: |
|
1469 DEFINE_SIZE_ARRAY (6, substitutions); |
|
1470 }; |
|
1471 |
|
1472 struct FeatureVariationRecord |
|
1473 { |
|
1474 friend struct FeatureVariations; |
|
1475 |
|
1476 inline bool sanitize (hb_sanitize_context_t *c, const void *base) const |
|
1477 { |
|
1478 TRACE_SANITIZE (this); |
|
1479 return_trace (conditions.sanitize (c, base) && |
|
1480 substitutions.sanitize (c, base)); |
|
1481 } |
|
1482 |
|
1483 protected: |
|
1484 OffsetTo<ConditionSet, ULONG> |
|
1485 conditions; |
|
1486 OffsetTo<FeatureTableSubstitution, ULONG> |
|
1487 substitutions; |
|
1488 public: |
|
1489 DEFINE_SIZE_STATIC (8); |
|
1490 }; |
|
1491 |
|
1492 struct FeatureVariations |
|
1493 { |
|
1494 static const unsigned int NOT_FOUND_INDEX = 0xFFFFFFFFu; |
|
1495 |
|
1496 inline bool find_index (const int *coords, unsigned int coord_len, |
|
1497 unsigned int *index) const |
|
1498 { |
|
1499 unsigned int count = varRecords.len; |
|
1500 for (unsigned int i = 0; i < count; i++) |
|
1501 { |
|
1502 const FeatureVariationRecord &record = varRecords.array[i]; |
|
1503 if ((this+record.conditions).evaluate (coords, coord_len)) |
|
1504 { |
|
1505 *index = i; |
|
1506 return true; |
|
1507 } |
|
1508 } |
|
1509 *index = NOT_FOUND_INDEX; |
|
1510 return false; |
|
1511 } |
|
1512 |
|
1513 inline const Feature *find_substitute (unsigned int variations_index, |
|
1514 unsigned int feature_index) const |
|
1515 { |
|
1516 const FeatureVariationRecord &record = varRecords[variations_index]; |
|
1517 return (this+record.substitutions).find_substitute (feature_index); |
|
1518 } |
|
1519 |
|
1520 inline bool sanitize (hb_sanitize_context_t *c) const |
|
1521 { |
|
1522 TRACE_SANITIZE (this); |
|
1523 return_trace (version.sanitize (c) && |
|
1524 likely (version.major == 1) && |
|
1525 varRecords.sanitize (c, this)); |
|
1526 } |
|
1527 |
|
1528 protected: |
|
1529 FixedVersion<> version; /* Version--0x00010000u */ |
|
1530 ArrayOf<FeatureVariationRecord, ULONG> |
|
1531 varRecords; |
|
1532 public: |
|
1533 DEFINE_SIZE_ARRAY (8, varRecords); |
|
1534 }; |
|
1535 |
|
1536 |
|
1537 /* |
|
1538 * Device Tables |
|
1539 */ |
|
1540 |
|
1541 struct HintingDevice |
|
1542 { |
|
1543 friend struct Device; |
|
1544 |
|
1545 private: |
|
1546 |
|
1547 inline hb_position_t get_x_delta (hb_font_t *font) const |
|
1548 { return get_delta (font->x_ppem, font->x_scale); } |
|
1549 |
|
1550 inline hb_position_t get_y_delta (hb_font_t *font) const |
|
1551 { return get_delta (font->y_ppem, font->y_scale); } |
|
1552 |
|
1553 inline unsigned int get_size (void) const |
|
1554 { |
|
1555 unsigned int f = deltaFormat; |
|
1556 if (unlikely (f < 1 || f > 3 || startSize > endSize)) return 3 * USHORT::static_size; |
|
1557 return USHORT::static_size * (4 + ((endSize - startSize) >> (4 - f))); |
|
1558 } |
|
1559 |
|
1560 inline bool sanitize (hb_sanitize_context_t *c) const |
|
1561 { |
|
1562 TRACE_SANITIZE (this); |
|
1563 return_trace (c->check_struct (this) && c->check_range (this, this->get_size ())); |
|
1564 } |
|
1565 |
|
1566 private: |
|
1567 |
|
1568 inline int get_delta (unsigned int ppem, int scale) const |
|
1569 { |
|
1570 if (!ppem) return 0; |
|
1571 |
|
1572 int pixels = get_delta_pixels (ppem); |
|
1573 |
|
1574 if (!pixels) return 0; |
|
1575 |
|
1576 return (int) (pixels * (int64_t) scale / ppem); |
|
1577 } |
|
1578 inline int get_delta_pixels (unsigned int ppem_size) const |
|
1579 { |
|
1580 unsigned int f = deltaFormat; |
|
1581 if (unlikely (f < 1 || f > 3)) |
|
1582 return 0; |
|
1583 |
|
1584 if (ppem_size < startSize || ppem_size > endSize) |
|
1585 return 0; |
|
1586 |
|
1587 unsigned int s = ppem_size - startSize; |
|
1588 |
|
1589 unsigned int byte = deltaValue[s >> (4 - f)]; |
|
1590 unsigned int bits = (byte >> (16 - (((s & ((1 << (4 - f)) - 1)) + 1) << f))); |
|
1591 unsigned int mask = (0xFFFFu >> (16 - (1 << f))); |
|
1592 |
|
1593 int delta = bits & mask; |
|
1594 |
|
1595 if ((unsigned int) delta >= ((mask + 1) >> 1)) |
|
1596 delta -= mask + 1; |
|
1597 |
|
1598 return delta; |
|
1599 } |
|
1600 |
|
1601 protected: |
|
1602 USHORT startSize; /* Smallest size to correct--in ppem */ |
|
1603 USHORT endSize; /* Largest size to correct--in ppem */ |
|
1604 USHORT deltaFormat; /* Format of DeltaValue array data: 1, 2, or 3 |
|
1605 * 1 Signed 2-bit value, 8 values per uint16 |
|
1606 * 2 Signed 4-bit value, 4 values per uint16 |
|
1607 * 3 Signed 8-bit value, 2 values per uint16 |
|
1608 */ |
|
1609 USHORT deltaValue[VAR]; /* Array of compressed data */ |
|
1610 public: |
|
1611 DEFINE_SIZE_ARRAY (6, deltaValue); |
|
1612 }; |
|
1613 |
|
1614 struct VariationDevice |
|
1615 { |
|
1616 friend struct Device; |
|
1617 |
|
1618 private: |
|
1619 |
|
1620 inline hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store) const |
|
1621 { return font->em_scalef_x (get_delta (font, store)); } |
|
1622 |
|
1623 inline hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store) const |
|
1624 { return font->em_scalef_y (get_delta (font, store)); } |
|
1625 |
|
1626 inline bool sanitize (hb_sanitize_context_t *c) const |
|
1627 { |
|
1628 TRACE_SANITIZE (this); |
|
1629 return_trace (c->check_struct (this)); |
|
1630 } |
|
1631 |
|
1632 private: |
|
1633 |
|
1634 inline float get_delta (hb_font_t *font, const VariationStore &store) const |
|
1635 { |
|
1636 return store.get_delta (outerIndex, innerIndex, font->coords, font->num_coords); |
|
1637 } |
|
1638 |
|
1639 protected: |
|
1640 USHORT outerIndex; |
|
1641 USHORT innerIndex; |
|
1642 USHORT deltaFormat; /* Format identifier for this table: 0x0x8000 */ |
|
1643 public: |
|
1644 DEFINE_SIZE_STATIC (6); |
|
1645 }; |
|
1646 |
|
1647 struct DeviceHeader |
|
1648 { |
|
1649 protected: |
|
1650 USHORT reserved1; |
|
1651 USHORT reserved2; |
|
1652 public: |
|
1653 USHORT format; /* Format identifier */ |
|
1654 public: |
|
1655 DEFINE_SIZE_STATIC (6); |
|
1656 }; |
|
1657 |
|
1658 struct Device |
|
1659 { |
|
1660 inline hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store=Null(VariationStore)) const |
|
1661 { |
|
1662 switch (u.b.format) |
|
1663 { |
|
1664 case 1: case 2: case 3: |
|
1665 return u.hinting.get_x_delta (font); |
|
1666 case 0x8000: |
|
1667 return u.variation.get_x_delta (font, store); |
|
1668 default: |
|
1669 return 0; |
|
1670 } |
|
1671 } |
|
1672 inline hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store=Null(VariationStore)) const |
|
1673 { |
|
1674 switch (u.b.format) |
|
1675 { |
|
1676 case 1: case 2: case 3: |
|
1677 return u.hinting.get_y_delta (font); |
|
1678 case 0x8000: |
|
1679 return u.variation.get_y_delta (font, store); |
|
1680 default: |
|
1681 return 0; |
|
1682 } |
|
1683 } |
|
1684 |
|
1685 inline bool sanitize (hb_sanitize_context_t *c) const |
|
1686 { |
|
1687 TRACE_SANITIZE (this); |
|
1688 if (!u.b.format.sanitize (c)) return_trace (false); |
|
1689 switch (u.b.format) { |
|
1690 case 1: case 2: case 3: |
|
1691 return_trace (u.hinting.sanitize (c)); |
|
1692 case 0x8000: |
|
1693 return_trace (u.variation.sanitize (c)); |
|
1694 default: |
|
1695 return_trace (true); |
|
1696 } |
|
1697 } |
|
1698 |
|
1699 protected: |
|
1700 union { |
|
1701 DeviceHeader b; |
|
1702 HintingDevice hinting; |
|
1703 VariationDevice variation; |
|
1704 } u; |
|
1705 public: |
|
1706 DEFINE_SIZE_UNION (6, b); |
|
1707 }; |
|
1708 |
|
1709 |
|
1710 } /* namespace OT */ |
|
1711 |
|
1712 |
|
1713 #endif /* HB_OT_LAYOUT_COMMON_PRIVATE_HH */ |