|
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 namespace OT { |
|
38 |
|
39 |
|
40 #define TRACE_DISPATCH(this, format) \ |
|
41 hb_auto_trace_t<context_t::max_debug_depth, typename context_t::return_t> trace \ |
|
42 (&c->debug_depth, c->get_name (), this, HB_FUNC, \ |
|
43 "format %d", (int) format); |
|
44 |
|
45 |
|
46 #define NOT_COVERED ((unsigned int) -1) |
|
47 #define MAX_NESTING_LEVEL 6 |
|
48 #define MAX_CONTEXT_LENGTH 64 |
|
49 |
|
50 |
|
51 |
|
52 /* |
|
53 * |
|
54 * OpenType Layout Common Table Formats |
|
55 * |
|
56 */ |
|
57 |
|
58 |
|
59 /* |
|
60 * Script, ScriptList, LangSys, Feature, FeatureList, Lookup, LookupList |
|
61 */ |
|
62 |
|
63 template <typename Type> |
|
64 struct Record |
|
65 { |
|
66 inline int cmp (hb_tag_t a) const { |
|
67 return tag.cmp (a); |
|
68 } |
|
69 |
|
70 struct sanitize_closure_t { |
|
71 hb_tag_t tag; |
|
72 const void *list_base; |
|
73 }; |
|
74 inline bool sanitize (hb_sanitize_context_t *c, const void *base) const |
|
75 { |
|
76 TRACE_SANITIZE (this); |
|
77 const sanitize_closure_t closure = {tag, base}; |
|
78 return_trace (c->check_struct (this) && offset.sanitize (c, base, &closure)); |
|
79 } |
|
80 |
|
81 Tag tag; /* 4-byte Tag identifier */ |
|
82 OffsetTo<Type> |
|
83 offset; /* Offset from beginning of object holding |
|
84 * the Record */ |
|
85 public: |
|
86 DEFINE_SIZE_STATIC (6); |
|
87 }; |
|
88 |
|
89 template <typename Type> |
|
90 struct RecordArrayOf : SortedArrayOf<Record<Type> > { |
|
91 inline const Tag& get_tag (unsigned int i) const |
|
92 { |
|
93 /* We cheat slightly and don't define separate Null objects |
|
94 * for Record types. Instead, we return the correct Null(Tag) |
|
95 * here. */ |
|
96 if (unlikely (i >= this->len)) return Null(Tag); |
|
97 return (*this)[i].tag; |
|
98 } |
|
99 inline unsigned int get_tags (unsigned int start_offset, |
|
100 unsigned int *record_count /* IN/OUT */, |
|
101 hb_tag_t *record_tags /* OUT */) const |
|
102 { |
|
103 if (record_count) { |
|
104 const Record<Type> *arr = this->sub_array (start_offset, record_count); |
|
105 unsigned int count = *record_count; |
|
106 for (unsigned int i = 0; i < count; i++) |
|
107 record_tags[i] = arr[i].tag; |
|
108 } |
|
109 return this->len; |
|
110 } |
|
111 inline bool find_index (hb_tag_t tag, unsigned int *index) const |
|
112 { |
|
113 /* If we want to allow non-sorted data, we can lsearch(). */ |
|
114 int i = this->/*lsearch*/bsearch (tag); |
|
115 if (i != -1) { |
|
116 if (index) *index = i; |
|
117 return true; |
|
118 } else { |
|
119 if (index) *index = Index::NOT_FOUND_INDEX; |
|
120 return false; |
|
121 } |
|
122 } |
|
123 }; |
|
124 |
|
125 template <typename Type> |
|
126 struct RecordListOf : RecordArrayOf<Type> |
|
127 { |
|
128 inline const Type& operator [] (unsigned int i) const |
|
129 { return this+RecordArrayOf<Type>::operator [](i).offset; } |
|
130 |
|
131 inline bool sanitize (hb_sanitize_context_t *c) const |
|
132 { |
|
133 TRACE_SANITIZE (this); |
|
134 return_trace (RecordArrayOf<Type>::sanitize (c, this)); |
|
135 } |
|
136 }; |
|
137 |
|
138 |
|
139 struct RangeRecord |
|
140 { |
|
141 inline int cmp (hb_codepoint_t g) const { |
|
142 return g < start ? -1 : g <= end ? 0 : +1 ; |
|
143 } |
|
144 |
|
145 inline bool sanitize (hb_sanitize_context_t *c) const |
|
146 { |
|
147 TRACE_SANITIZE (this); |
|
148 return_trace (c->check_struct (this)); |
|
149 } |
|
150 |
|
151 inline bool intersects (const hb_set_t *glyphs) const { |
|
152 return glyphs->intersects (start, end); |
|
153 } |
|
154 |
|
155 template <typename set_t> |
|
156 inline void add_coverage (set_t *glyphs) const { |
|
157 glyphs->add_range (start, end); |
|
158 } |
|
159 |
|
160 GlyphID start; /* First GlyphID in the range */ |
|
161 GlyphID end; /* Last GlyphID in the range */ |
|
162 USHORT value; /* Value */ |
|
163 public: |
|
164 DEFINE_SIZE_STATIC (6); |
|
165 }; |
|
166 DEFINE_NULL_DATA (RangeRecord, "\000\001"); |
|
167 |
|
168 |
|
169 struct IndexArray : ArrayOf<Index> |
|
170 { |
|
171 inline unsigned int get_indexes (unsigned int start_offset, |
|
172 unsigned int *_count /* IN/OUT */, |
|
173 unsigned int *_indexes /* OUT */) const |
|
174 { |
|
175 if (_count) { |
|
176 const USHORT *arr = this->sub_array (start_offset, _count); |
|
177 unsigned int count = *_count; |
|
178 for (unsigned int i = 0; i < count; i++) |
|
179 _indexes[i] = arr[i]; |
|
180 } |
|
181 return this->len; |
|
182 } |
|
183 }; |
|
184 |
|
185 |
|
186 struct Script; |
|
187 struct LangSys; |
|
188 struct Feature; |
|
189 |
|
190 |
|
191 struct LangSys |
|
192 { |
|
193 inline unsigned int get_feature_count (void) const |
|
194 { return featureIndex.len; } |
|
195 inline hb_tag_t get_feature_index (unsigned int i) const |
|
196 { return featureIndex[i]; } |
|
197 inline unsigned int get_feature_indexes (unsigned int start_offset, |
|
198 unsigned int *feature_count /* IN/OUT */, |
|
199 unsigned int *feature_indexes /* OUT */) const |
|
200 { return featureIndex.get_indexes (start_offset, feature_count, feature_indexes); } |
|
201 |
|
202 inline bool has_required_feature (void) const { return reqFeatureIndex != 0xFFFFu; } |
|
203 inline unsigned int get_required_feature_index (void) const |
|
204 { |
|
205 if (reqFeatureIndex == 0xFFFFu) |
|
206 return Index::NOT_FOUND_INDEX; |
|
207 return reqFeatureIndex;; |
|
208 } |
|
209 |
|
210 inline bool sanitize (hb_sanitize_context_t *c, |
|
211 const Record<LangSys>::sanitize_closure_t * = NULL) const |
|
212 { |
|
213 TRACE_SANITIZE (this); |
|
214 return_trace (c->check_struct (this) && featureIndex.sanitize (c)); |
|
215 } |
|
216 |
|
217 Offset<> lookupOrderZ; /* = Null (reserved for an offset to a |
|
218 * reordering table) */ |
|
219 USHORT reqFeatureIndex;/* Index of a feature required for this |
|
220 * language system--if no required features |
|
221 * = 0xFFFFu */ |
|
222 IndexArray featureIndex; /* Array of indices into the FeatureList */ |
|
223 public: |
|
224 DEFINE_SIZE_ARRAY (6, featureIndex); |
|
225 }; |
|
226 DEFINE_NULL_DATA (LangSys, "\0\0\xFF\xFF"); |
|
227 |
|
228 |
|
229 struct Script |
|
230 { |
|
231 inline unsigned int get_lang_sys_count (void) const |
|
232 { return langSys.len; } |
|
233 inline const Tag& get_lang_sys_tag (unsigned int i) const |
|
234 { return langSys.get_tag (i); } |
|
235 inline unsigned int get_lang_sys_tags (unsigned int start_offset, |
|
236 unsigned int *lang_sys_count /* IN/OUT */, |
|
237 hb_tag_t *lang_sys_tags /* OUT */) const |
|
238 { return langSys.get_tags (start_offset, lang_sys_count, lang_sys_tags); } |
|
239 inline const LangSys& get_lang_sys (unsigned int i) const |
|
240 { |
|
241 if (i == Index::NOT_FOUND_INDEX) return get_default_lang_sys (); |
|
242 return this+langSys[i].offset; |
|
243 } |
|
244 inline bool find_lang_sys_index (hb_tag_t tag, unsigned int *index) const |
|
245 { return langSys.find_index (tag, index); } |
|
246 |
|
247 inline bool has_default_lang_sys (void) const { return defaultLangSys != 0; } |
|
248 inline const LangSys& get_default_lang_sys (void) const { return this+defaultLangSys; } |
|
249 |
|
250 inline bool sanitize (hb_sanitize_context_t *c, |
|
251 const Record<Script>::sanitize_closure_t * = NULL) const |
|
252 { |
|
253 TRACE_SANITIZE (this); |
|
254 return_trace (defaultLangSys.sanitize (c, this) && langSys.sanitize (c, this)); |
|
255 } |
|
256 |
|
257 protected: |
|
258 OffsetTo<LangSys> |
|
259 defaultLangSys; /* Offset to DefaultLangSys table--from |
|
260 * beginning of Script table--may be Null */ |
|
261 RecordArrayOf<LangSys> |
|
262 langSys; /* Array of LangSysRecords--listed |
|
263 * alphabetically by LangSysTag */ |
|
264 public: |
|
265 DEFINE_SIZE_ARRAY (4, langSys); |
|
266 }; |
|
267 |
|
268 typedef RecordListOf<Script> ScriptList; |
|
269 |
|
270 |
|
271 /* http://www.microsoft.com/typography/otspec/features_pt.htm#size */ |
|
272 struct FeatureParamsSize |
|
273 { |
|
274 inline bool sanitize (hb_sanitize_context_t *c) const |
|
275 { |
|
276 TRACE_SANITIZE (this); |
|
277 if (unlikely (!c->check_struct (this))) return_trace (false); |
|
278 |
|
279 /* This subtable has some "history", if you will. Some earlier versions of |
|
280 * Adobe tools calculated the offset of the FeatureParams sutable from the |
|
281 * beginning of the FeatureList table! Now, that is dealt with in the |
|
282 * Feature implementation. But we still need to be able to tell junk from |
|
283 * real data. Note: We don't check that the nameID actually exists. |
|
284 * |
|
285 * Read Roberts wrote on 9/15/06 on opentype-list@indx.co.uk : |
|
286 * |
|
287 * Yes, it is correct that a new version of the AFDKO (version 2.0) will be |
|
288 * coming out soon, and that the makeotf program will build a font with a |
|
289 * 'size' feature that is correct by the specification. |
|
290 * |
|
291 * The specification for this feature tag is in the "OpenType Layout Tag |
|
292 * Registry". You can see a copy of this at: |
|
293 * http://partners.adobe.com/public/developer/opentype/index_tag8.html#size |
|
294 * |
|
295 * Here is one set of rules to determine if the 'size' feature is built |
|
296 * correctly, or as by the older versions of MakeOTF. You may be able to do |
|
297 * better. |
|
298 * |
|
299 * Assume that the offset to the size feature is according to specification, |
|
300 * and make the following value checks. If it fails, assume the the size |
|
301 * feature is calculated as versions of MakeOTF before the AFDKO 2.0 built it. |
|
302 * If this fails, reject the 'size' feature. The older makeOTF's calculated the |
|
303 * offset from the beginning of the FeatureList table, rather than from the |
|
304 * beginning of the 'size' Feature table. |
|
305 * |
|
306 * If "design size" == 0: |
|
307 * fails check |
|
308 * |
|
309 * Else if ("subfamily identifier" == 0 and |
|
310 * "range start" == 0 and |
|
311 * "range end" == 0 and |
|
312 * "range start" == 0 and |
|
313 * "menu name ID" == 0) |
|
314 * passes check: this is the format used when there is a design size |
|
315 * specified, but there is no recommended size range. |
|
316 * |
|
317 * Else if ("design size" < "range start" or |
|
318 * "design size" > "range end" or |
|
319 * "range end" <= "range start" or |
|
320 * "menu name ID" < 256 or |
|
321 * "menu name ID" > 32767 or |
|
322 * menu name ID is not a name ID which is actually in the name table) |
|
323 * fails test |
|
324 * Else |
|
325 * passes test. |
|
326 */ |
|
327 |
|
328 if (!designSize) |
|
329 return_trace (false); |
|
330 else if (subfamilyID == 0 && |
|
331 subfamilyNameID == 0 && |
|
332 rangeStart == 0 && |
|
333 rangeEnd == 0) |
|
334 return_trace (true); |
|
335 else if (designSize < rangeStart || |
|
336 designSize > rangeEnd || |
|
337 subfamilyNameID < 256 || |
|
338 subfamilyNameID > 32767) |
|
339 return_trace (false); |
|
340 else |
|
341 return_trace (true); |
|
342 } |
|
343 |
|
344 USHORT designSize; /* Represents the design size in 720/inch |
|
345 * units (decipoints). The design size entry |
|
346 * must be non-zero. When there is a design |
|
347 * size but no recommended size range, the |
|
348 * rest of the array will consist of zeros. */ |
|
349 USHORT subfamilyID; /* Has no independent meaning, but serves |
|
350 * as an identifier that associates fonts |
|
351 * in a subfamily. All fonts which share a |
|
352 * Preferred or Font Family name and which |
|
353 * differ only by size range shall have the |
|
354 * same subfamily value, and no fonts which |
|
355 * differ in weight or style shall have the |
|
356 * same subfamily value. If this value is |
|
357 * zero, the remaining fields in the array |
|
358 * will be ignored. */ |
|
359 USHORT subfamilyNameID;/* If the preceding value is non-zero, this |
|
360 * value must be set in the range 256 - 32767 |
|
361 * (inclusive). It records the value of a |
|
362 * field in the name table, which must |
|
363 * contain English-language strings encoded |
|
364 * in Windows Unicode and Macintosh Roman, |
|
365 * and may contain additional strings |
|
366 * localized to other scripts and languages. |
|
367 * Each of these strings is the name an |
|
368 * application should use, in combination |
|
369 * with the family name, to represent the |
|
370 * subfamily in a menu. Applications will |
|
371 * choose the appropriate version based on |
|
372 * their selection criteria. */ |
|
373 USHORT rangeStart; /* Large end of the recommended usage range |
|
374 * (inclusive), stored in 720/inch units |
|
375 * (decipoints). */ |
|
376 USHORT rangeEnd; /* Small end of the recommended usage range |
|
377 (exclusive), stored in 720/inch units |
|
378 * (decipoints). */ |
|
379 public: |
|
380 DEFINE_SIZE_STATIC (10); |
|
381 }; |
|
382 |
|
383 /* http://www.microsoft.com/typography/otspec/features_pt.htm#ssxx */ |
|
384 struct FeatureParamsStylisticSet |
|
385 { |
|
386 inline bool sanitize (hb_sanitize_context_t *c) const |
|
387 { |
|
388 TRACE_SANITIZE (this); |
|
389 /* Right now minorVersion is at zero. Which means, any table supports |
|
390 * the uiNameID field. */ |
|
391 return_trace (c->check_struct (this)); |
|
392 } |
|
393 |
|
394 USHORT version; /* (set to 0): This corresponds to a “minor” |
|
395 * version number. Additional data may be |
|
396 * added to the end of this Feature Parameters |
|
397 * table in the future. */ |
|
398 |
|
399 USHORT uiNameID; /* The 'name' table name ID that specifies a |
|
400 * string (or strings, for multiple languages) |
|
401 * for a user-interface label for this |
|
402 * feature. The values of uiLabelNameId and |
|
403 * sampleTextNameId are expected to be in the |
|
404 * font-specific name ID range (256-32767), |
|
405 * though that is not a requirement in this |
|
406 * Feature Parameters specification. The |
|
407 * user-interface label for the feature can |
|
408 * be provided in multiple languages. An |
|
409 * English string should be included as a |
|
410 * fallback. The string should be kept to a |
|
411 * minimal length to fit comfortably with |
|
412 * different application interfaces. */ |
|
413 public: |
|
414 DEFINE_SIZE_STATIC (4); |
|
415 }; |
|
416 |
|
417 /* http://www.microsoft.com/typography/otspec/features_ae.htm#cv01-cv99 */ |
|
418 struct FeatureParamsCharacterVariants |
|
419 { |
|
420 inline bool sanitize (hb_sanitize_context_t *c) const |
|
421 { |
|
422 TRACE_SANITIZE (this); |
|
423 return_trace (c->check_struct (this) && |
|
424 characters.sanitize (c)); |
|
425 } |
|
426 |
|
427 USHORT format; /* Format number is set to 0. */ |
|
428 USHORT featUILableNameID; /* The ‘name’ table name ID that |
|
429 * specifies a string (or strings, |
|
430 * for multiple languages) for a |
|
431 * user-interface label for this |
|
432 * feature. (May be NULL.) */ |
|
433 USHORT featUITooltipTextNameID;/* The ‘name’ table name ID that |
|
434 * specifies a string (or strings, |
|
435 * for multiple languages) that an |
|
436 * application can use for tooltip |
|
437 * text for this feature. (May be |
|
438 * NULL.) */ |
|
439 USHORT sampleTextNameID; /* The ‘name’ table name ID that |
|
440 * specifies sample text that |
|
441 * illustrates the effect of this |
|
442 * feature. (May be NULL.) */ |
|
443 USHORT numNamedParameters; /* Number of named parameters. (May |
|
444 * be zero.) */ |
|
445 USHORT firstParamUILabelNameID;/* The first ‘name’ table name ID |
|
446 * used to specify strings for |
|
447 * user-interface labels for the |
|
448 * feature parameters. (Must be zero |
|
449 * if numParameters is zero.) */ |
|
450 ArrayOf<UINT24> |
|
451 characters; /* Array of the Unicode Scalar Value |
|
452 * of the characters for which this |
|
453 * feature provides glyph variants. |
|
454 * (May be zero.) */ |
|
455 public: |
|
456 DEFINE_SIZE_ARRAY (14, characters); |
|
457 }; |
|
458 |
|
459 struct FeatureParams |
|
460 { |
|
461 inline bool sanitize (hb_sanitize_context_t *c, hb_tag_t tag) const |
|
462 { |
|
463 TRACE_SANITIZE (this); |
|
464 if (tag == HB_TAG ('s','i','z','e')) |
|
465 return_trace (u.size.sanitize (c)); |
|
466 if ((tag & 0xFFFF0000u) == HB_TAG ('s','s','\0','\0')) /* ssXX */ |
|
467 return_trace (u.stylisticSet.sanitize (c)); |
|
468 if ((tag & 0xFFFF0000u) == HB_TAG ('c','v','\0','\0')) /* cvXX */ |
|
469 return_trace (u.characterVariants.sanitize (c)); |
|
470 return_trace (true); |
|
471 } |
|
472 |
|
473 inline const FeatureParamsSize& get_size_params (hb_tag_t tag) const |
|
474 { |
|
475 if (tag == HB_TAG ('s','i','z','e')) |
|
476 return u.size; |
|
477 return Null(FeatureParamsSize); |
|
478 } |
|
479 |
|
480 private: |
|
481 union { |
|
482 FeatureParamsSize size; |
|
483 FeatureParamsStylisticSet stylisticSet; |
|
484 FeatureParamsCharacterVariants characterVariants; |
|
485 } u; |
|
486 DEFINE_SIZE_STATIC (17); |
|
487 }; |
|
488 |
|
489 struct Feature |
|
490 { |
|
491 inline unsigned int get_lookup_count (void) const |
|
492 { return lookupIndex.len; } |
|
493 inline hb_tag_t get_lookup_index (unsigned int i) const |
|
494 { return lookupIndex[i]; } |
|
495 inline unsigned int get_lookup_indexes (unsigned int start_index, |
|
496 unsigned int *lookup_count /* IN/OUT */, |
|
497 unsigned int *lookup_tags /* OUT */) const |
|
498 { return lookupIndex.get_indexes (start_index, lookup_count, lookup_tags); } |
|
499 |
|
500 inline const FeatureParams &get_feature_params (void) const |
|
501 { return this+featureParams; } |
|
502 |
|
503 inline bool sanitize (hb_sanitize_context_t *c, |
|
504 const Record<Feature>::sanitize_closure_t *closure) const |
|
505 { |
|
506 TRACE_SANITIZE (this); |
|
507 if (unlikely (!(c->check_struct (this) && lookupIndex.sanitize (c)))) |
|
508 return_trace (false); |
|
509 |
|
510 /* Some earlier versions of Adobe tools calculated the offset of the |
|
511 * FeatureParams subtable from the beginning of the FeatureList table! |
|
512 * |
|
513 * If sanitizing "failed" for the FeatureParams subtable, try it with the |
|
514 * alternative location. We would know sanitize "failed" if old value |
|
515 * of the offset was non-zero, but it's zeroed now. |
|
516 * |
|
517 * Only do this for the 'size' feature, since at the time of the faulty |
|
518 * Adobe tools, only the 'size' feature had FeatureParams defined. |
|
519 */ |
|
520 |
|
521 OffsetTo<FeatureParams> orig_offset = featureParams; |
|
522 if (unlikely (!featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE))) |
|
523 return_trace (false); |
|
524 |
|
525 if (likely (orig_offset.is_null ())) |
|
526 return_trace (true); |
|
527 |
|
528 if (featureParams == 0 && closure && |
|
529 closure->tag == HB_TAG ('s','i','z','e') && |
|
530 closure->list_base && closure->list_base < this) |
|
531 { |
|
532 unsigned int new_offset_int = (unsigned int) orig_offset - |
|
533 (((char *) this) - ((char *) closure->list_base)); |
|
534 |
|
535 OffsetTo<FeatureParams> new_offset; |
|
536 /* Check that it did not overflow. */ |
|
537 new_offset.set (new_offset_int); |
|
538 if (new_offset == new_offset_int && |
|
539 c->try_set (&featureParams, new_offset) && |
|
540 !featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE)) |
|
541 return_trace (false); |
|
542 } |
|
543 |
|
544 return_trace (true); |
|
545 } |
|
546 |
|
547 OffsetTo<FeatureParams> |
|
548 featureParams; /* Offset to Feature Parameters table (if one |
|
549 * has been defined for the feature), relative |
|
550 * to the beginning of the Feature Table; = Null |
|
551 * if not required */ |
|
552 IndexArray lookupIndex; /* Array of LookupList indices */ |
|
553 public: |
|
554 DEFINE_SIZE_ARRAY (4, lookupIndex); |
|
555 }; |
|
556 |
|
557 typedef RecordListOf<Feature> FeatureList; |
|
558 |
|
559 |
|
560 struct LookupFlag : USHORT |
|
561 { |
|
562 enum Flags { |
|
563 RightToLeft = 0x0001u, |
|
564 IgnoreBaseGlyphs = 0x0002u, |
|
565 IgnoreLigatures = 0x0004u, |
|
566 IgnoreMarks = 0x0008u, |
|
567 IgnoreFlags = 0x000Eu, |
|
568 UseMarkFilteringSet = 0x0010u, |
|
569 Reserved = 0x00E0u, |
|
570 MarkAttachmentType = 0xFF00u |
|
571 }; |
|
572 public: |
|
573 DEFINE_SIZE_STATIC (2); |
|
574 }; |
|
575 |
|
576 struct Lookup |
|
577 { |
|
578 inline unsigned int get_subtable_count (void) const { return subTable.len; } |
|
579 |
|
580 template <typename SubTableType> |
|
581 inline const SubTableType& get_subtable (unsigned int i) const |
|
582 { return this+CastR<OffsetArrayOf<SubTableType> > (subTable)[i]; } |
|
583 |
|
584 template <typename SubTableType> |
|
585 inline const OffsetArrayOf<SubTableType>& get_subtables (void) const |
|
586 { return CastR<OffsetArrayOf<SubTableType> > (subTable); } |
|
587 template <typename SubTableType> |
|
588 inline OffsetArrayOf<SubTableType>& get_subtables (void) |
|
589 { return CastR<OffsetArrayOf<SubTableType> > (subTable); } |
|
590 |
|
591 inline unsigned int get_type (void) const { return lookupType; } |
|
592 |
|
593 /* lookup_props is a 32-bit integer where the lower 16-bit is LookupFlag and |
|
594 * higher 16-bit is mark-filtering-set if the lookup uses one. |
|
595 * Not to be confused with glyph_props which is very similar. */ |
|
596 inline uint32_t get_props (void) const |
|
597 { |
|
598 unsigned int flag = lookupFlag; |
|
599 if (unlikely (flag & LookupFlag::UseMarkFilteringSet)) |
|
600 { |
|
601 const USHORT &markFilteringSet = StructAfter<USHORT> (subTable); |
|
602 flag += (markFilteringSet << 16); |
|
603 } |
|
604 return flag; |
|
605 } |
|
606 |
|
607 template <typename SubTableType, typename context_t> |
|
608 inline typename context_t::return_t dispatch (context_t *c) const |
|
609 { |
|
610 unsigned int lookup_type = get_type (); |
|
611 TRACE_DISPATCH (this, lookup_type); |
|
612 unsigned int count = get_subtable_count (); |
|
613 for (unsigned int i = 0; i < count; i++) { |
|
614 typename context_t::return_t r = get_subtable<SubTableType> (i).dispatch (c, lookup_type); |
|
615 if (c->stop_sublookup_iteration (r)) |
|
616 return_trace (r); |
|
617 } |
|
618 return_trace (c->default_return_value ()); |
|
619 } |
|
620 |
|
621 inline bool serialize (hb_serialize_context_t *c, |
|
622 unsigned int lookup_type, |
|
623 uint32_t lookup_props, |
|
624 unsigned int num_subtables) |
|
625 { |
|
626 TRACE_SERIALIZE (this); |
|
627 if (unlikely (!c->extend_min (*this))) return_trace (false); |
|
628 lookupType.set (lookup_type); |
|
629 lookupFlag.set (lookup_props & 0xFFFFu); |
|
630 if (unlikely (!subTable.serialize (c, num_subtables))) return_trace (false); |
|
631 if (lookupFlag & LookupFlag::UseMarkFilteringSet) |
|
632 { |
|
633 USHORT &markFilteringSet = StructAfter<USHORT> (subTable); |
|
634 markFilteringSet.set (lookup_props >> 16); |
|
635 } |
|
636 return_trace (true); |
|
637 } |
|
638 |
|
639 inline bool sanitize (hb_sanitize_context_t *c) const |
|
640 { |
|
641 TRACE_SANITIZE (this); |
|
642 /* Real sanitize of the subtables is done by GSUB/GPOS/... */ |
|
643 if (!(c->check_struct (this) && subTable.sanitize (c))) return_trace (false); |
|
644 if (lookupFlag & LookupFlag::UseMarkFilteringSet) |
|
645 { |
|
646 const USHORT &markFilteringSet = StructAfter<USHORT> (subTable); |
|
647 if (!markFilteringSet.sanitize (c)) return_trace (false); |
|
648 } |
|
649 return_trace (true); |
|
650 } |
|
651 |
|
652 private: |
|
653 USHORT lookupType; /* Different enumerations for GSUB and GPOS */ |
|
654 USHORT lookupFlag; /* Lookup qualifiers */ |
|
655 ArrayOf<Offset<> > |
|
656 subTable; /* Array of SubTables */ |
|
657 USHORT markFilteringSetX[VAR]; /* Index (base 0) into GDEF mark glyph sets |
|
658 * structure. This field is only present if bit |
|
659 * UseMarkFilteringSet of lookup flags is set. */ |
|
660 public: |
|
661 DEFINE_SIZE_ARRAY2 (6, subTable, markFilteringSetX); |
|
662 }; |
|
663 |
|
664 typedef OffsetListOf<Lookup> LookupList; |
|
665 |
|
666 |
|
667 /* |
|
668 * Coverage Table |
|
669 */ |
|
670 |
|
671 struct CoverageFormat1 |
|
672 { |
|
673 friend struct Coverage; |
|
674 |
|
675 private: |
|
676 inline unsigned int get_coverage (hb_codepoint_t glyph_id) const |
|
677 { |
|
678 int i = glyphArray.bsearch (glyph_id); |
|
679 ASSERT_STATIC (((unsigned int) -1) == NOT_COVERED); |
|
680 return i; |
|
681 } |
|
682 |
|
683 inline bool serialize (hb_serialize_context_t *c, |
|
684 Supplier<GlyphID> &glyphs, |
|
685 unsigned int num_glyphs) |
|
686 { |
|
687 TRACE_SERIALIZE (this); |
|
688 if (unlikely (!c->extend_min (*this))) return_trace (false); |
|
689 glyphArray.len.set (num_glyphs); |
|
690 if (unlikely (!c->extend (glyphArray))) return_trace (false); |
|
691 for (unsigned int i = 0; i < num_glyphs; i++) |
|
692 glyphArray[i] = glyphs[i]; |
|
693 glyphs.advance (num_glyphs); |
|
694 return_trace (true); |
|
695 } |
|
696 |
|
697 inline bool sanitize (hb_sanitize_context_t *c) const |
|
698 { |
|
699 TRACE_SANITIZE (this); |
|
700 return_trace (glyphArray.sanitize (c)); |
|
701 } |
|
702 |
|
703 inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const { |
|
704 return glyphs->has (glyphArray[index]); |
|
705 } |
|
706 |
|
707 template <typename set_t> |
|
708 inline void add_coverage (set_t *glyphs) const { |
|
709 unsigned int count = glyphArray.len; |
|
710 for (unsigned int i = 0; i < count; i++) |
|
711 glyphs->add (glyphArray[i]); |
|
712 } |
|
713 |
|
714 public: |
|
715 /* Older compilers need this to be public. */ |
|
716 struct Iter { |
|
717 inline void init (const struct CoverageFormat1 &c_) { c = &c_; i = 0; }; |
|
718 inline bool more (void) { return i < c->glyphArray.len; } |
|
719 inline void next (void) { i++; } |
|
720 inline uint16_t get_glyph (void) { return c->glyphArray[i]; } |
|
721 inline uint16_t get_coverage (void) { return i; } |
|
722 |
|
723 private: |
|
724 const struct CoverageFormat1 *c; |
|
725 unsigned int i; |
|
726 }; |
|
727 private: |
|
728 |
|
729 protected: |
|
730 USHORT coverageFormat; /* Format identifier--format = 1 */ |
|
731 SortedArrayOf<GlyphID> |
|
732 glyphArray; /* Array of GlyphIDs--in numerical order */ |
|
733 public: |
|
734 DEFINE_SIZE_ARRAY (4, glyphArray); |
|
735 }; |
|
736 |
|
737 struct CoverageFormat2 |
|
738 { |
|
739 friend struct Coverage; |
|
740 |
|
741 private: |
|
742 inline unsigned int get_coverage (hb_codepoint_t glyph_id) const |
|
743 { |
|
744 int i = rangeRecord.bsearch (glyph_id); |
|
745 if (i != -1) { |
|
746 const RangeRecord &range = rangeRecord[i]; |
|
747 return (unsigned int) range.value + (glyph_id - range.start); |
|
748 } |
|
749 return NOT_COVERED; |
|
750 } |
|
751 |
|
752 inline bool serialize (hb_serialize_context_t *c, |
|
753 Supplier<GlyphID> &glyphs, |
|
754 unsigned int num_glyphs) |
|
755 { |
|
756 TRACE_SERIALIZE (this); |
|
757 if (unlikely (!c->extend_min (*this))) return_trace (false); |
|
758 |
|
759 if (unlikely (!num_glyphs)) return_trace (true); |
|
760 |
|
761 unsigned int num_ranges = 1; |
|
762 for (unsigned int i = 1; i < num_glyphs; i++) |
|
763 if (glyphs[i - 1] + 1 != glyphs[i]) |
|
764 num_ranges++; |
|
765 rangeRecord.len.set (num_ranges); |
|
766 if (unlikely (!c->extend (rangeRecord))) return_trace (false); |
|
767 |
|
768 unsigned int range = 0; |
|
769 rangeRecord[range].start = glyphs[0]; |
|
770 rangeRecord[range].value.set (0); |
|
771 for (unsigned int i = 1; i < num_glyphs; i++) |
|
772 if (glyphs[i - 1] + 1 != glyphs[i]) { |
|
773 range++; |
|
774 rangeRecord[range].start = glyphs[i]; |
|
775 rangeRecord[range].value.set (i); |
|
776 rangeRecord[range].end = glyphs[i]; |
|
777 } else { |
|
778 rangeRecord[range].end = glyphs[i]; |
|
779 } |
|
780 glyphs.advance (num_glyphs); |
|
781 return_trace (true); |
|
782 } |
|
783 |
|
784 inline bool sanitize (hb_sanitize_context_t *c) const |
|
785 { |
|
786 TRACE_SANITIZE (this); |
|
787 return_trace (rangeRecord.sanitize (c)); |
|
788 } |
|
789 |
|
790 inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const { |
|
791 unsigned int i; |
|
792 unsigned int count = rangeRecord.len; |
|
793 for (i = 0; i < count; i++) { |
|
794 const RangeRecord &range = rangeRecord[i]; |
|
795 if (range.value <= index && |
|
796 index < (unsigned int) range.value + (range.end - range.start) && |
|
797 range.intersects (glyphs)) |
|
798 return true; |
|
799 else if (index < range.value) |
|
800 return false; |
|
801 } |
|
802 return false; |
|
803 } |
|
804 |
|
805 template <typename set_t> |
|
806 inline void add_coverage (set_t *glyphs) const { |
|
807 unsigned int count = rangeRecord.len; |
|
808 for (unsigned int i = 0; i < count; i++) |
|
809 rangeRecord[i].add_coverage (glyphs); |
|
810 } |
|
811 |
|
812 public: |
|
813 /* Older compilers need this to be public. */ |
|
814 struct Iter { |
|
815 inline void init (const CoverageFormat2 &c_) { |
|
816 c = &c_; |
|
817 coverage = 0; |
|
818 i = 0; |
|
819 j = c->rangeRecord.len ? c_.rangeRecord[0].start : 0; |
|
820 } |
|
821 inline bool more (void) { return i < c->rangeRecord.len; } |
|
822 inline void next (void) { |
|
823 coverage++; |
|
824 if (j == c->rangeRecord[i].end) { |
|
825 i++; |
|
826 if (more ()) |
|
827 j = c->rangeRecord[i].start; |
|
828 return; |
|
829 } |
|
830 j++; |
|
831 } |
|
832 inline uint16_t get_glyph (void) { return j; } |
|
833 inline uint16_t get_coverage (void) { return coverage; } |
|
834 |
|
835 private: |
|
836 const struct CoverageFormat2 *c; |
|
837 unsigned int i, j, coverage; |
|
838 }; |
|
839 private: |
|
840 |
|
841 protected: |
|
842 USHORT coverageFormat; /* Format identifier--format = 2 */ |
|
843 SortedArrayOf<RangeRecord> |
|
844 rangeRecord; /* Array of glyph ranges--ordered by |
|
845 * Start GlyphID. rangeCount entries |
|
846 * long */ |
|
847 public: |
|
848 DEFINE_SIZE_ARRAY (4, rangeRecord); |
|
849 }; |
|
850 |
|
851 struct Coverage |
|
852 { |
|
853 inline unsigned int get_coverage (hb_codepoint_t glyph_id) const |
|
854 { |
|
855 switch (u.format) { |
|
856 case 1: return u.format1.get_coverage(glyph_id); |
|
857 case 2: return u.format2.get_coverage(glyph_id); |
|
858 default:return NOT_COVERED; |
|
859 } |
|
860 } |
|
861 |
|
862 inline bool serialize (hb_serialize_context_t *c, |
|
863 Supplier<GlyphID> &glyphs, |
|
864 unsigned int num_glyphs) |
|
865 { |
|
866 TRACE_SERIALIZE (this); |
|
867 if (unlikely (!c->extend_min (*this))) return_trace (false); |
|
868 unsigned int num_ranges = 1; |
|
869 for (unsigned int i = 1; i < num_glyphs; i++) |
|
870 if (glyphs[i - 1] + 1 != glyphs[i]) |
|
871 num_ranges++; |
|
872 u.format.set (num_glyphs * 2 < num_ranges * 3 ? 1 : 2); |
|
873 switch (u.format) { |
|
874 case 1: return_trace (u.format1.serialize (c, glyphs, num_glyphs)); |
|
875 case 2: return_trace (u.format2.serialize (c, glyphs, num_glyphs)); |
|
876 default:return_trace (false); |
|
877 } |
|
878 } |
|
879 |
|
880 inline bool sanitize (hb_sanitize_context_t *c) const |
|
881 { |
|
882 TRACE_SANITIZE (this); |
|
883 if (!u.format.sanitize (c)) return_trace (false); |
|
884 switch (u.format) { |
|
885 case 1: return_trace (u.format1.sanitize (c)); |
|
886 case 2: return_trace (u.format2.sanitize (c)); |
|
887 default:return_trace (true); |
|
888 } |
|
889 } |
|
890 |
|
891 inline bool intersects (const hb_set_t *glyphs) const { |
|
892 /* TODO speed this up */ |
|
893 Coverage::Iter iter; |
|
894 for (iter.init (*this); iter.more (); iter.next ()) { |
|
895 if (glyphs->has (iter.get_glyph ())) |
|
896 return true; |
|
897 } |
|
898 return false; |
|
899 } |
|
900 |
|
901 inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const { |
|
902 switch (u.format) { |
|
903 case 1: return u.format1.intersects_coverage (glyphs, index); |
|
904 case 2: return u.format2.intersects_coverage (glyphs, index); |
|
905 default:return false; |
|
906 } |
|
907 } |
|
908 |
|
909 template <typename set_t> |
|
910 inline void add_coverage (set_t *glyphs) const { |
|
911 switch (u.format) { |
|
912 case 1: u.format1.add_coverage (glyphs); break; |
|
913 case 2: u.format2.add_coverage (glyphs); break; |
|
914 default: break; |
|
915 } |
|
916 } |
|
917 |
|
918 struct Iter { |
|
919 Iter (void) : format (0) {}; |
|
920 inline void init (const Coverage &c_) { |
|
921 format = c_.u.format; |
|
922 switch (format) { |
|
923 case 1: u.format1.init (c_.u.format1); return; |
|
924 case 2: u.format2.init (c_.u.format2); return; |
|
925 default: return; |
|
926 } |
|
927 } |
|
928 inline bool more (void) { |
|
929 switch (format) { |
|
930 case 1: return u.format1.more (); |
|
931 case 2: return u.format2.more (); |
|
932 default:return false; |
|
933 } |
|
934 } |
|
935 inline void next (void) { |
|
936 switch (format) { |
|
937 case 1: u.format1.next (); break; |
|
938 case 2: u.format2.next (); break; |
|
939 default: break; |
|
940 } |
|
941 } |
|
942 inline uint16_t get_glyph (void) { |
|
943 switch (format) { |
|
944 case 1: return u.format1.get_glyph (); |
|
945 case 2: return u.format2.get_glyph (); |
|
946 default:return 0; |
|
947 } |
|
948 } |
|
949 inline uint16_t get_coverage (void) { |
|
950 switch (format) { |
|
951 case 1: return u.format1.get_coverage (); |
|
952 case 2: return u.format2.get_coverage (); |
|
953 default:return -1; |
|
954 } |
|
955 } |
|
956 |
|
957 private: |
|
958 unsigned int format; |
|
959 union { |
|
960 CoverageFormat1::Iter format1; |
|
961 CoverageFormat2::Iter format2; |
|
962 } u; |
|
963 }; |
|
964 |
|
965 protected: |
|
966 union { |
|
967 USHORT format; /* Format identifier */ |
|
968 CoverageFormat1 format1; |
|
969 CoverageFormat2 format2; |
|
970 } u; |
|
971 public: |
|
972 DEFINE_SIZE_UNION (2, format); |
|
973 }; |
|
974 |
|
975 |
|
976 /* |
|
977 * Class Definition Table |
|
978 */ |
|
979 |
|
980 struct ClassDefFormat1 |
|
981 { |
|
982 friend struct ClassDef; |
|
983 |
|
984 private: |
|
985 inline unsigned int get_class (hb_codepoint_t glyph_id) const |
|
986 { |
|
987 unsigned int i = (unsigned int) (glyph_id - startGlyph); |
|
988 if (unlikely (i < classValue.len)) |
|
989 return classValue[i]; |
|
990 return 0; |
|
991 } |
|
992 |
|
993 inline bool sanitize (hb_sanitize_context_t *c) const |
|
994 { |
|
995 TRACE_SANITIZE (this); |
|
996 return_trace (c->check_struct (this) && classValue.sanitize (c)); |
|
997 } |
|
998 |
|
999 template <typename set_t> |
|
1000 inline void add_class (set_t *glyphs, unsigned int klass) const { |
|
1001 unsigned int count = classValue.len; |
|
1002 for (unsigned int i = 0; i < count; i++) |
|
1003 if (classValue[i] == klass) |
|
1004 glyphs->add (startGlyph + i); |
|
1005 } |
|
1006 |
|
1007 inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const { |
|
1008 unsigned int count = classValue.len; |
|
1009 if (klass == 0) |
|
1010 { |
|
1011 /* Match if there's any glyph that is not listed! */ |
|
1012 hb_codepoint_t g = -1; |
|
1013 if (!hb_set_next (glyphs, &g)) |
|
1014 return false; |
|
1015 if (g < startGlyph) |
|
1016 return true; |
|
1017 g = startGlyph + count - 1; |
|
1018 if (hb_set_next (glyphs, &g)) |
|
1019 return true; |
|
1020 /* Fall through. */ |
|
1021 } |
|
1022 for (unsigned int i = 0; i < count; i++) |
|
1023 if (classValue[i] == klass && glyphs->has (startGlyph + i)) |
|
1024 return true; |
|
1025 return false; |
|
1026 } |
|
1027 |
|
1028 protected: |
|
1029 USHORT classFormat; /* Format identifier--format = 1 */ |
|
1030 GlyphID startGlyph; /* First GlyphID of the classValueArray */ |
|
1031 ArrayOf<USHORT> |
|
1032 classValue; /* Array of Class Values--one per GlyphID */ |
|
1033 public: |
|
1034 DEFINE_SIZE_ARRAY (6, classValue); |
|
1035 }; |
|
1036 |
|
1037 struct ClassDefFormat2 |
|
1038 { |
|
1039 friend struct ClassDef; |
|
1040 |
|
1041 private: |
|
1042 inline unsigned int get_class (hb_codepoint_t glyph_id) const |
|
1043 { |
|
1044 int i = rangeRecord.bsearch (glyph_id); |
|
1045 if (unlikely (i != -1)) |
|
1046 return rangeRecord[i].value; |
|
1047 return 0; |
|
1048 } |
|
1049 |
|
1050 inline bool sanitize (hb_sanitize_context_t *c) const |
|
1051 { |
|
1052 TRACE_SANITIZE (this); |
|
1053 return_trace (rangeRecord.sanitize (c)); |
|
1054 } |
|
1055 |
|
1056 template <typename set_t> |
|
1057 inline void add_class (set_t *glyphs, unsigned int klass) const { |
|
1058 unsigned int count = rangeRecord.len; |
|
1059 for (unsigned int i = 0; i < count; i++) |
|
1060 if (rangeRecord[i].value == klass) |
|
1061 rangeRecord[i].add_coverage (glyphs); |
|
1062 } |
|
1063 |
|
1064 inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const { |
|
1065 unsigned int count = rangeRecord.len; |
|
1066 if (klass == 0) |
|
1067 { |
|
1068 /* Match if there's any glyph that is not listed! */ |
|
1069 hb_codepoint_t g = (hb_codepoint_t) -1; |
|
1070 for (unsigned int i = 0; i < count; i++) |
|
1071 { |
|
1072 if (!hb_set_next (glyphs, &g)) |
|
1073 break; |
|
1074 if (g < rangeRecord[i].start) |
|
1075 return true; |
|
1076 g = rangeRecord[i].end; |
|
1077 } |
|
1078 if (g != (hb_codepoint_t) -1 && hb_set_next (glyphs, &g)) |
|
1079 return true; |
|
1080 /* Fall through. */ |
|
1081 } |
|
1082 for (unsigned int i = 0; i < count; i++) |
|
1083 if (rangeRecord[i].value == klass && rangeRecord[i].intersects (glyphs)) |
|
1084 return true; |
|
1085 return false; |
|
1086 } |
|
1087 |
|
1088 protected: |
|
1089 USHORT classFormat; /* Format identifier--format = 2 */ |
|
1090 SortedArrayOf<RangeRecord> |
|
1091 rangeRecord; /* Array of glyph ranges--ordered by |
|
1092 * Start GlyphID */ |
|
1093 public: |
|
1094 DEFINE_SIZE_ARRAY (4, rangeRecord); |
|
1095 }; |
|
1096 |
|
1097 struct ClassDef |
|
1098 { |
|
1099 inline unsigned int get_class (hb_codepoint_t glyph_id) const |
|
1100 { |
|
1101 switch (u.format) { |
|
1102 case 1: return u.format1.get_class(glyph_id); |
|
1103 case 2: return u.format2.get_class(glyph_id); |
|
1104 default:return 0; |
|
1105 } |
|
1106 } |
|
1107 |
|
1108 inline bool sanitize (hb_sanitize_context_t *c) const |
|
1109 { |
|
1110 TRACE_SANITIZE (this); |
|
1111 if (!u.format.sanitize (c)) return_trace (false); |
|
1112 switch (u.format) { |
|
1113 case 1: return_trace (u.format1.sanitize (c)); |
|
1114 case 2: return_trace (u.format2.sanitize (c)); |
|
1115 default:return_trace (true); |
|
1116 } |
|
1117 } |
|
1118 |
|
1119 inline void add_class (hb_set_t *glyphs, unsigned int klass) const { |
|
1120 switch (u.format) { |
|
1121 case 1: u.format1.add_class (glyphs, klass); return; |
|
1122 case 2: u.format2.add_class (glyphs, klass); return; |
|
1123 default:return; |
|
1124 } |
|
1125 } |
|
1126 |
|
1127 inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const { |
|
1128 switch (u.format) { |
|
1129 case 1: return u.format1.intersects_class (glyphs, klass); |
|
1130 case 2: return u.format2.intersects_class (glyphs, klass); |
|
1131 default:return false; |
|
1132 } |
|
1133 } |
|
1134 |
|
1135 protected: |
|
1136 union { |
|
1137 USHORT format; /* Format identifier */ |
|
1138 ClassDefFormat1 format1; |
|
1139 ClassDefFormat2 format2; |
|
1140 } u; |
|
1141 public: |
|
1142 DEFINE_SIZE_UNION (2, format); |
|
1143 }; |
|
1144 |
|
1145 |
|
1146 /* |
|
1147 * Device Tables |
|
1148 */ |
|
1149 |
|
1150 struct Device |
|
1151 { |
|
1152 |
|
1153 inline hb_position_t get_x_delta (hb_font_t *font) const |
|
1154 { return get_delta (font->x_ppem, font->x_scale); } |
|
1155 |
|
1156 inline hb_position_t get_y_delta (hb_font_t *font) const |
|
1157 { return get_delta (font->y_ppem, font->y_scale); } |
|
1158 |
|
1159 inline int get_delta (unsigned int ppem, int scale) const |
|
1160 { |
|
1161 if (!ppem) return 0; |
|
1162 |
|
1163 int pixels = get_delta_pixels (ppem); |
|
1164 |
|
1165 if (!pixels) return 0; |
|
1166 |
|
1167 return (int) (pixels * (int64_t) scale / ppem); |
|
1168 } |
|
1169 |
|
1170 |
|
1171 inline int get_delta_pixels (unsigned int ppem_size) const |
|
1172 { |
|
1173 unsigned int f = deltaFormat; |
|
1174 if (unlikely (f < 1 || f > 3)) |
|
1175 return 0; |
|
1176 |
|
1177 if (ppem_size < startSize || ppem_size > endSize) |
|
1178 return 0; |
|
1179 |
|
1180 unsigned int s = ppem_size - startSize; |
|
1181 |
|
1182 unsigned int byte = deltaValue[s >> (4 - f)]; |
|
1183 unsigned int bits = (byte >> (16 - (((s & ((1 << (4 - f)) - 1)) + 1) << f))); |
|
1184 unsigned int mask = (0xFFFFu >> (16 - (1 << f))); |
|
1185 |
|
1186 int delta = bits & mask; |
|
1187 |
|
1188 if ((unsigned int) delta >= ((mask + 1) >> 1)) |
|
1189 delta -= mask + 1; |
|
1190 |
|
1191 return delta; |
|
1192 } |
|
1193 |
|
1194 inline unsigned int get_size (void) const |
|
1195 { |
|
1196 unsigned int f = deltaFormat; |
|
1197 if (unlikely (f < 1 || f > 3 || startSize > endSize)) return 3 * USHORT::static_size; |
|
1198 return USHORT::static_size * (4 + ((endSize - startSize) >> (4 - f))); |
|
1199 } |
|
1200 |
|
1201 inline bool sanitize (hb_sanitize_context_t *c) const |
|
1202 { |
|
1203 TRACE_SANITIZE (this); |
|
1204 return_trace (c->check_struct (this) && c->check_range (this, this->get_size ())); |
|
1205 } |
|
1206 |
|
1207 protected: |
|
1208 USHORT startSize; /* Smallest size to correct--in ppem */ |
|
1209 USHORT endSize; /* Largest size to correct--in ppem */ |
|
1210 USHORT deltaFormat; /* Format of DeltaValue array data: 1, 2, or 3 |
|
1211 * 1 Signed 2-bit value, 8 values per uint16 |
|
1212 * 2 Signed 4-bit value, 4 values per uint16 |
|
1213 * 3 Signed 8-bit value, 2 values per uint16 |
|
1214 */ |
|
1215 USHORT deltaValue[VAR]; /* Array of compressed data */ |
|
1216 public: |
|
1217 DEFINE_SIZE_ARRAY (6, deltaValue); |
|
1218 }; |
|
1219 |
|
1220 |
|
1221 } /* namespace OT */ |
|
1222 |
|
1223 |
|
1224 #endif /* HB_OT_LAYOUT_COMMON_PRIVATE_HH */ |