1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/harfbuzz/src/hb-ot-layout-common-private.hh Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1172 @@ 1.4 +/* 1.5 + * Copyright © 2007,2008,2009 Red Hat, Inc. 1.6 + * Copyright © 2010,2012 Google, Inc. 1.7 + * 1.8 + * This is part of HarfBuzz, a text shaping library. 1.9 + * 1.10 + * Permission is hereby granted, without written agreement and without 1.11 + * license or royalty fees, to use, copy, modify, and distribute this 1.12 + * software and its documentation for any purpose, provided that the 1.13 + * above copyright notice and the following two paragraphs appear in 1.14 + * all copies of this software. 1.15 + * 1.16 + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 1.17 + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 1.18 + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 1.19 + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 1.20 + * DAMAGE. 1.21 + * 1.22 + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 1.23 + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 1.24 + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 1.25 + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 1.26 + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 1.27 + * 1.28 + * Red Hat Author(s): Behdad Esfahbod 1.29 + * Google Author(s): Behdad Esfahbod 1.30 + */ 1.31 + 1.32 +#ifndef HB_OT_LAYOUT_COMMON_PRIVATE_HH 1.33 +#define HB_OT_LAYOUT_COMMON_PRIVATE_HH 1.34 + 1.35 +#include "hb-ot-layout-private.hh" 1.36 +#include "hb-open-type-private.hh" 1.37 +#include "hb-set-private.hh" 1.38 + 1.39 + 1.40 +namespace OT { 1.41 + 1.42 + 1.43 +#define NOT_COVERED ((unsigned int) -1) 1.44 +#define MAX_NESTING_LEVEL 8 1.45 +#define MAX_CONTEXT_LENGTH 64 1.46 + 1.47 + 1.48 + 1.49 +/* 1.50 + * 1.51 + * OpenType Layout Common Table Formats 1.52 + * 1.53 + */ 1.54 + 1.55 + 1.56 +/* 1.57 + * Script, ScriptList, LangSys, Feature, FeatureList, Lookup, LookupList 1.58 + */ 1.59 + 1.60 +template <typename Type> 1.61 +struct Record 1.62 +{ 1.63 + inline int cmp (hb_tag_t a) const { 1.64 + return tag.cmp (a); 1.65 + } 1.66 + 1.67 + struct sanitize_closure_t { 1.68 + hb_tag_t tag; 1.69 + void *list_base; 1.70 + }; 1.71 + inline bool sanitize (hb_sanitize_context_t *c, void *base) { 1.72 + TRACE_SANITIZE (this); 1.73 + const sanitize_closure_t closure = {tag, base}; 1.74 + return TRACE_RETURN (c->check_struct (this) && offset.sanitize (c, base, &closure)); 1.75 + } 1.76 + 1.77 + Tag tag; /* 4-byte Tag identifier */ 1.78 + OffsetTo<Type> 1.79 + offset; /* Offset from beginning of object holding 1.80 + * the Record */ 1.81 + public: 1.82 + DEFINE_SIZE_STATIC (6); 1.83 +}; 1.84 + 1.85 +template <typename Type> 1.86 +struct RecordArrayOf : SortedArrayOf<Record<Type> > { 1.87 + inline const Tag& get_tag (unsigned int i) const 1.88 + { 1.89 + /* We cheat slightly and don't define separate Null objects 1.90 + * for Record types. Instead, we return the correct Null(Tag) 1.91 + * here. */ 1.92 + if (unlikely (i >= this->len)) return Null(Tag); 1.93 + return (*this)[i].tag; 1.94 + } 1.95 + inline unsigned int get_tags (unsigned int start_offset, 1.96 + unsigned int *record_count /* IN/OUT */, 1.97 + hb_tag_t *record_tags /* OUT */) const 1.98 + { 1.99 + if (record_count) { 1.100 + const Record<Type> *arr = this->sub_array (start_offset, record_count); 1.101 + unsigned int count = *record_count; 1.102 + for (unsigned int i = 0; i < count; i++) 1.103 + record_tags[i] = arr[i].tag; 1.104 + } 1.105 + return this->len; 1.106 + } 1.107 + inline bool find_index (hb_tag_t tag, unsigned int *index) const 1.108 + { 1.109 + int i = this->search (tag); 1.110 + if (i != -1) { 1.111 + if (index) *index = i; 1.112 + return true; 1.113 + } else { 1.114 + if (index) *index = Index::NOT_FOUND_INDEX; 1.115 + return false; 1.116 + } 1.117 + } 1.118 +}; 1.119 + 1.120 +template <typename Type> 1.121 +struct RecordListOf : RecordArrayOf<Type> 1.122 +{ 1.123 + inline const Type& operator [] (unsigned int i) const 1.124 + { return this+RecordArrayOf<Type>::operator [](i).offset; } 1.125 + 1.126 + inline bool sanitize (hb_sanitize_context_t *c) { 1.127 + TRACE_SANITIZE (this); 1.128 + return TRACE_RETURN (RecordArrayOf<Type>::sanitize (c, this)); 1.129 + } 1.130 +}; 1.131 + 1.132 + 1.133 +struct RangeRecord 1.134 +{ 1.135 + inline int cmp (hb_codepoint_t g) const { 1.136 + return g < start ? -1 : g <= end ? 0 : +1 ; 1.137 + } 1.138 + 1.139 + inline bool sanitize (hb_sanitize_context_t *c) { 1.140 + TRACE_SANITIZE (this); 1.141 + return TRACE_RETURN (c->check_struct (this)); 1.142 + } 1.143 + 1.144 + inline bool intersects (const hb_set_t *glyphs) const { 1.145 + return glyphs->intersects (start, end); 1.146 + } 1.147 + 1.148 + template <typename set_t> 1.149 + inline void add_coverage (set_t *glyphs) const { 1.150 + glyphs->add_range (start, end); 1.151 + } 1.152 + 1.153 + GlyphID start; /* First GlyphID in the range */ 1.154 + GlyphID end; /* Last GlyphID in the range */ 1.155 + USHORT value; /* Value */ 1.156 + public: 1.157 + DEFINE_SIZE_STATIC (6); 1.158 +}; 1.159 +DEFINE_NULL_DATA (RangeRecord, "\000\001"); 1.160 + 1.161 + 1.162 +struct IndexArray : ArrayOf<Index> 1.163 +{ 1.164 + inline unsigned int get_indexes (unsigned int start_offset, 1.165 + unsigned int *_count /* IN/OUT */, 1.166 + unsigned int *_indexes /* OUT */) const 1.167 + { 1.168 + if (_count) { 1.169 + const USHORT *arr = this->sub_array (start_offset, _count); 1.170 + unsigned int count = *_count; 1.171 + for (unsigned int i = 0; i < count; i++) 1.172 + _indexes[i] = arr[i]; 1.173 + } 1.174 + return this->len; 1.175 + } 1.176 +}; 1.177 + 1.178 + 1.179 +struct Script; 1.180 +struct LangSys; 1.181 +struct Feature; 1.182 + 1.183 + 1.184 +struct LangSys 1.185 +{ 1.186 + inline unsigned int get_feature_count (void) const 1.187 + { return featureIndex.len; } 1.188 + inline hb_tag_t get_feature_index (unsigned int i) const 1.189 + { return featureIndex[i]; } 1.190 + inline unsigned int get_feature_indexes (unsigned int start_offset, 1.191 + unsigned int *feature_count /* IN/OUT */, 1.192 + unsigned int *feature_indexes /* OUT */) const 1.193 + { return featureIndex.get_indexes (start_offset, feature_count, feature_indexes); } 1.194 + 1.195 + inline bool has_required_feature (void) const { return reqFeatureIndex != 0xffff; } 1.196 + inline unsigned int get_required_feature_index (void) const 1.197 + { 1.198 + if (reqFeatureIndex == 0xffff) 1.199 + return Index::NOT_FOUND_INDEX; 1.200 + return reqFeatureIndex;; 1.201 + } 1.202 + 1.203 + inline bool sanitize (hb_sanitize_context_t *c, 1.204 + const Record<LangSys>::sanitize_closure_t * = NULL) { 1.205 + TRACE_SANITIZE (this); 1.206 + return TRACE_RETURN (c->check_struct (this) && featureIndex.sanitize (c)); 1.207 + } 1.208 + 1.209 + Offset lookupOrder; /* = Null (reserved for an offset to a 1.210 + * reordering table) */ 1.211 + USHORT reqFeatureIndex;/* Index of a feature required for this 1.212 + * language system--if no required features 1.213 + * = 0xFFFF */ 1.214 + IndexArray featureIndex; /* Array of indices into the FeatureList */ 1.215 + public: 1.216 + DEFINE_SIZE_ARRAY (6, featureIndex); 1.217 +}; 1.218 +DEFINE_NULL_DATA (LangSys, "\0\0\xFF\xFF"); 1.219 + 1.220 + 1.221 +struct Script 1.222 +{ 1.223 + inline unsigned int get_lang_sys_count (void) const 1.224 + { return langSys.len; } 1.225 + inline const Tag& get_lang_sys_tag (unsigned int i) const 1.226 + { return langSys.get_tag (i); } 1.227 + inline unsigned int get_lang_sys_tags (unsigned int start_offset, 1.228 + unsigned int *lang_sys_count /* IN/OUT */, 1.229 + hb_tag_t *lang_sys_tags /* OUT */) const 1.230 + { return langSys.get_tags (start_offset, lang_sys_count, lang_sys_tags); } 1.231 + inline const LangSys& get_lang_sys (unsigned int i) const 1.232 + { 1.233 + if (i == Index::NOT_FOUND_INDEX) return get_default_lang_sys (); 1.234 + return this+langSys[i].offset; 1.235 + } 1.236 + inline bool find_lang_sys_index (hb_tag_t tag, unsigned int *index) const 1.237 + { return langSys.find_index (tag, index); } 1.238 + 1.239 + inline bool has_default_lang_sys (void) const { return defaultLangSys != 0; } 1.240 + inline const LangSys& get_default_lang_sys (void) const { return this+defaultLangSys; } 1.241 + 1.242 + inline bool sanitize (hb_sanitize_context_t *c, 1.243 + const Record<Script>::sanitize_closure_t * = NULL) { 1.244 + TRACE_SANITIZE (this); 1.245 + return TRACE_RETURN (defaultLangSys.sanitize (c, this) && langSys.sanitize (c, this)); 1.246 + } 1.247 + 1.248 + protected: 1.249 + OffsetTo<LangSys> 1.250 + defaultLangSys; /* Offset to DefaultLangSys table--from 1.251 + * beginning of Script table--may be Null */ 1.252 + RecordArrayOf<LangSys> 1.253 + langSys; /* Array of LangSysRecords--listed 1.254 + * alphabetically by LangSysTag */ 1.255 + public: 1.256 + DEFINE_SIZE_ARRAY (4, langSys); 1.257 +}; 1.258 + 1.259 +typedef RecordListOf<Script> ScriptList; 1.260 + 1.261 + 1.262 +/* http://www.microsoft.com/typography/otspec/features_pt.htm#size */ 1.263 +struct FeatureParamsSize 1.264 +{ 1.265 + inline bool sanitize (hb_sanitize_context_t *c) { 1.266 + TRACE_SANITIZE (this); 1.267 + if (unlikely (!c->check_struct (this))) return TRACE_RETURN (false); 1.268 + 1.269 + /* This subtable has some "history", if you will. Some earlier versions of 1.270 + * Adobe tools calculated the offset of the FeatureParams sutable from the 1.271 + * beginning of the FeatureList table! Now, that is dealt with in the 1.272 + * Feature implementation. But we still need to be able to tell junk from 1.273 + * real data. Note: We don't check that the nameID actually exists. 1.274 + * 1.275 + * Read Roberts wrote on 9/15/06 on opentype-list@indx.co.uk : 1.276 + * 1.277 + * Yes, it is correct that a new version of the AFDKO (version 2.0) will be 1.278 + * coming out soon, and that the makeotf program will build a font with a 1.279 + * 'size' feature that is correct by the specification. 1.280 + * 1.281 + * The specification for this feature tag is in the "OpenType Layout Tag 1.282 + * Registry". You can see a copy of this at: 1.283 + * http://partners.adobe.com/public/developer/opentype/index_tag8.html#size 1.284 + * 1.285 + * Here is one set of rules to determine if the 'size' feature is built 1.286 + * correctly, or as by the older versions of MakeOTF. You may be able to do 1.287 + * better. 1.288 + * 1.289 + * Assume that the offset to the size feature is according to specification, 1.290 + * and make the following value checks. If it fails, assume the the size 1.291 + * feature is calculated as versions of MakeOTF before the AFDKO 2.0 built it. 1.292 + * If this fails, reject the 'size' feature. The older makeOTF's calculated the 1.293 + * offset from the beginning of the FeatureList table, rather than from the 1.294 + * beginning of the 'size' Feature table. 1.295 + * 1.296 + * If "design size" == 0: 1.297 + * fails check 1.298 + * 1.299 + * Else if ("subfamily identifier" == 0 and 1.300 + * "range start" == 0 and 1.301 + * "range end" == 0 and 1.302 + * "range start" == 0 and 1.303 + * "menu name ID" == 0) 1.304 + * passes check: this is the format used when there is a design size 1.305 + * specified, but there is no recommended size range. 1.306 + * 1.307 + * Else if ("design size" < "range start" or 1.308 + * "design size" > "range end" or 1.309 + * "range end" <= "range start" or 1.310 + * "menu name ID" < 256 or 1.311 + * "menu name ID" > 32767 or 1.312 + * menu name ID is not a name ID which is actually in the name table) 1.313 + * fails test 1.314 + * Else 1.315 + * passes test. 1.316 + */ 1.317 + 1.318 + if (!designSize) 1.319 + return TRACE_RETURN (false); 1.320 + else if (subfamilyID == 0 && 1.321 + subfamilyNameID == 0 && 1.322 + rangeStart == 0 && 1.323 + rangeEnd == 0) 1.324 + return TRACE_RETURN (true); 1.325 + else if (designSize < rangeStart || 1.326 + designSize > rangeEnd || 1.327 + subfamilyNameID < 256 || 1.328 + subfamilyNameID > 32767) 1.329 + return TRACE_RETURN (false); 1.330 + else 1.331 + return TRACE_RETURN (true); 1.332 + } 1.333 + 1.334 + USHORT designSize; /* Represents the design size in 720/inch 1.335 + * units (decipoints). The design size entry 1.336 + * must be non-zero. When there is a design 1.337 + * size but no recommended size range, the 1.338 + * rest of the array will consist of zeros. */ 1.339 + USHORT subfamilyID; /* Has no independent meaning, but serves 1.340 + * as an identifier that associates fonts 1.341 + * in a subfamily. All fonts which share a 1.342 + * Preferred or Font Family name and which 1.343 + * differ only by size range shall have the 1.344 + * same subfamily value, and no fonts which 1.345 + * differ in weight or style shall have the 1.346 + * same subfamily value. If this value is 1.347 + * zero, the remaining fields in the array 1.348 + * will be ignored. */ 1.349 + USHORT subfamilyNameID;/* If the preceding value is non-zero, this 1.350 + * value must be set in the range 256 - 32767 1.351 + * (inclusive). It records the value of a 1.352 + * field in the name table, which must 1.353 + * contain English-language strings encoded 1.354 + * in Windows Unicode and Macintosh Roman, 1.355 + * and may contain additional strings 1.356 + * localized to other scripts and languages. 1.357 + * Each of these strings is the name an 1.358 + * application should use, in combination 1.359 + * with the family name, to represent the 1.360 + * subfamily in a menu. Applications will 1.361 + * choose the appropriate version based on 1.362 + * their selection criteria. */ 1.363 + USHORT rangeStart; /* Large end of the recommended usage range 1.364 + * (inclusive), stored in 720/inch units 1.365 + * (decipoints). */ 1.366 + USHORT rangeEnd; /* Small end of the recommended usage range 1.367 + (exclusive), stored in 720/inch units 1.368 + * (decipoints). */ 1.369 + public: 1.370 + DEFINE_SIZE_STATIC (10); 1.371 +}; 1.372 + 1.373 +/* http://www.microsoft.com/typography/otspec/features_pt.htm#ssxx */ 1.374 +struct FeatureParamsStylisticSet 1.375 +{ 1.376 + inline bool sanitize (hb_sanitize_context_t *c) { 1.377 + TRACE_SANITIZE (this); 1.378 + /* Right now minorVersion is at zero. Which means, any table supports 1.379 + * the uiNameID field. */ 1.380 + return TRACE_RETURN (c->check_struct (this)); 1.381 + } 1.382 + 1.383 + USHORT version; /* (set to 0): This corresponds to a “minor” 1.384 + * version number. Additional data may be 1.385 + * added to the end of this Feature Parameters 1.386 + * table in the future. */ 1.387 + 1.388 + USHORT uiNameID; /* The 'name' table name ID that specifies a 1.389 + * string (or strings, for multiple languages) 1.390 + * for a user-interface label for this 1.391 + * feature. The values of uiLabelNameId and 1.392 + * sampleTextNameId are expected to be in the 1.393 + * font-specific name ID range (256-32767), 1.394 + * though that is not a requirement in this 1.395 + * Feature Parameters specification. The 1.396 + * user-interface label for the feature can 1.397 + * be provided in multiple languages. An 1.398 + * English string should be included as a 1.399 + * fallback. The string should be kept to a 1.400 + * minimal length to fit comfortably with 1.401 + * different application interfaces. */ 1.402 + public: 1.403 + DEFINE_SIZE_STATIC (4); 1.404 +}; 1.405 + 1.406 +/* http://www.microsoft.com/typography/otspec/features_ae.htm#cv01-cv99 */ 1.407 +struct FeatureParamsCharacterVariants 1.408 +{ 1.409 + inline bool sanitize (hb_sanitize_context_t *c) { 1.410 + TRACE_SANITIZE (this); 1.411 + return TRACE_RETURN (c->check_struct (this) && 1.412 + characters.sanitize (c)); 1.413 + } 1.414 + 1.415 + USHORT format; /* Format number is set to 0. */ 1.416 + USHORT featUILableNameID; /* The ‘name’ table name ID that 1.417 + * specifies a string (or strings, 1.418 + * for multiple languages) for a 1.419 + * user-interface label for this 1.420 + * feature. (May be NULL.) */ 1.421 + USHORT featUITooltipTextNameID;/* The ‘name’ table name ID that 1.422 + * specifies a string (or strings, 1.423 + * for multiple languages) that an 1.424 + * application can use for tooltip 1.425 + * text for this feature. (May be 1.426 + * NULL.) */ 1.427 + USHORT sampleTextNameID; /* The ‘name’ table name ID that 1.428 + * specifies sample text that 1.429 + * illustrates the effect of this 1.430 + * feature. (May be NULL.) */ 1.431 + USHORT numNamedParameters; /* Number of named parameters. (May 1.432 + * be zero.) */ 1.433 + USHORT firstParamUILabelNameID;/* The first ‘name’ table name ID 1.434 + * used to specify strings for 1.435 + * user-interface labels for the 1.436 + * feature parameters. (Must be zero 1.437 + * if numParameters is zero.) */ 1.438 + ArrayOf<UINT24> 1.439 + characters; /* Array of the Unicode Scalar Value 1.440 + * of the characters for which this 1.441 + * feature provides glyph variants. 1.442 + * (May be zero.) */ 1.443 + public: 1.444 + DEFINE_SIZE_ARRAY (14, characters); 1.445 +}; 1.446 + 1.447 +struct FeatureParams 1.448 +{ 1.449 + inline bool sanitize (hb_sanitize_context_t *c, hb_tag_t tag) { 1.450 + TRACE_SANITIZE (this); 1.451 + if (tag == HB_TAG ('s','i','z','e')) 1.452 + return TRACE_RETURN (u.size.sanitize (c)); 1.453 + if ((tag & 0xFFFF0000) == HB_TAG ('s','s','\0','\0')) /* ssXX */ 1.454 + return TRACE_RETURN (u.stylisticSet.sanitize (c)); 1.455 + if ((tag & 0xFFFF0000) == HB_TAG ('c','v','\0','\0')) /* cvXX */ 1.456 + return TRACE_RETURN (u.characterVariants.sanitize (c)); 1.457 + return TRACE_RETURN (true); 1.458 + } 1.459 + 1.460 + inline const FeatureParamsSize& get_size_params (hb_tag_t tag) const 1.461 + { 1.462 + if (tag == HB_TAG ('s','i','z','e')) 1.463 + return u.size; 1.464 + return Null(FeatureParamsSize); 1.465 + } 1.466 + 1.467 + private: 1.468 + union { 1.469 + FeatureParamsSize size; 1.470 + FeatureParamsStylisticSet stylisticSet; 1.471 + FeatureParamsCharacterVariants characterVariants; 1.472 + } u; 1.473 + DEFINE_SIZE_STATIC (17); 1.474 +}; 1.475 + 1.476 +struct Feature 1.477 +{ 1.478 + inline unsigned int get_lookup_count (void) const 1.479 + { return lookupIndex.len; } 1.480 + inline hb_tag_t get_lookup_index (unsigned int i) const 1.481 + { return lookupIndex[i]; } 1.482 + inline unsigned int get_lookup_indexes (unsigned int start_index, 1.483 + unsigned int *lookup_count /* IN/OUT */, 1.484 + unsigned int *lookup_tags /* OUT */) const 1.485 + { return lookupIndex.get_indexes (start_index, lookup_count, lookup_tags); } 1.486 + 1.487 + inline const FeatureParams &get_feature_params (void) const 1.488 + { return this+featureParams; } 1.489 + 1.490 + inline bool sanitize (hb_sanitize_context_t *c, 1.491 + const Record<Feature>::sanitize_closure_t *closure) { 1.492 + TRACE_SANITIZE (this); 1.493 + if (unlikely (!(c->check_struct (this) && lookupIndex.sanitize (c)))) 1.494 + return TRACE_RETURN (false); 1.495 + 1.496 + /* Some earlier versions of Adobe tools calculated the offset of the 1.497 + * FeatureParams subtable from the beginning of the FeatureList table! 1.498 + * 1.499 + * If sanitizing "failed" for the FeatureParams subtable, try it with the 1.500 + * alternative location. We would know sanitize "failed" if old value 1.501 + * of the offset was non-zero, but it's zeroed now. 1.502 + * 1.503 + * Only do this for the 'size' feature, since at the time of the faulty 1.504 + * Adobe tools, only the 'size' feature had FeatureParams defined. 1.505 + */ 1.506 + 1.507 + Offset orig_offset = featureParams; 1.508 + if (unlikely (!featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE))) 1.509 + return TRACE_RETURN (false); 1.510 + 1.511 + if (likely (!orig_offset)) 1.512 + return TRACE_RETURN (true); 1.513 + 1.514 + if (featureParams == 0 && closure && 1.515 + closure->tag == HB_TAG ('s','i','z','e') && 1.516 + closure->list_base && closure->list_base < this) 1.517 + { 1.518 + unsigned int new_offset_int = (unsigned int) orig_offset - 1.519 + ((char *) this - (char *) closure->list_base); 1.520 + 1.521 + Offset new_offset; 1.522 + /* Check that it did not overflow. */ 1.523 + new_offset.set (new_offset_int); 1.524 + if (new_offset == new_offset_int && 1.525 + featureParams.try_set (c, new_offset) && 1.526 + !featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE)) 1.527 + return TRACE_RETURN (false); 1.528 + } 1.529 + 1.530 + return TRACE_RETURN (true); 1.531 + } 1.532 + 1.533 + OffsetTo<FeatureParams> 1.534 + featureParams; /* Offset to Feature Parameters table (if one 1.535 + * has been defined for the feature), relative 1.536 + * to the beginning of the Feature Table; = Null 1.537 + * if not required */ 1.538 + IndexArray lookupIndex; /* Array of LookupList indices */ 1.539 + public: 1.540 + DEFINE_SIZE_ARRAY (4, lookupIndex); 1.541 +}; 1.542 + 1.543 +typedef RecordListOf<Feature> FeatureList; 1.544 + 1.545 + 1.546 +struct LookupFlag : USHORT 1.547 +{ 1.548 + enum Flags { 1.549 + RightToLeft = 0x0001u, 1.550 + IgnoreBaseGlyphs = 0x0002u, 1.551 + IgnoreLigatures = 0x0004u, 1.552 + IgnoreMarks = 0x0008u, 1.553 + IgnoreFlags = 0x000Eu, 1.554 + UseMarkFilteringSet = 0x0010u, 1.555 + Reserved = 0x00E0u, 1.556 + MarkAttachmentType = 0xFF00u 1.557 + }; 1.558 + public: 1.559 + DEFINE_SIZE_STATIC (2); 1.560 +}; 1.561 + 1.562 +struct Lookup 1.563 +{ 1.564 + inline unsigned int get_subtable_count (void) const { return subTable.len; } 1.565 + 1.566 + inline unsigned int get_type (void) const { return lookupType; } 1.567 + 1.568 + /* lookup_props is a 32-bit integer where the lower 16-bit is LookupFlag and 1.569 + * higher 16-bit is mark-filtering-set if the lookup uses one. 1.570 + * Not to be confused with glyph_props which is very similar. */ 1.571 + inline uint32_t get_props (void) const 1.572 + { 1.573 + unsigned int flag = lookupFlag; 1.574 + if (unlikely (flag & LookupFlag::UseMarkFilteringSet)) 1.575 + { 1.576 + const USHORT &markFilteringSet = StructAfter<USHORT> (subTable); 1.577 + flag += (markFilteringSet << 16); 1.578 + } 1.579 + return flag; 1.580 + } 1.581 + 1.582 + inline bool serialize (hb_serialize_context_t *c, 1.583 + unsigned int lookup_type, 1.584 + uint32_t lookup_props, 1.585 + unsigned int num_subtables) 1.586 + { 1.587 + TRACE_SERIALIZE (this); 1.588 + if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); 1.589 + lookupType.set (lookup_type); 1.590 + lookupFlag.set (lookup_props & 0xFFFF); 1.591 + if (unlikely (!subTable.serialize (c, num_subtables))) return TRACE_RETURN (false); 1.592 + if (lookupFlag & LookupFlag::UseMarkFilteringSet) 1.593 + { 1.594 + USHORT &markFilteringSet = StructAfter<USHORT> (subTable); 1.595 + markFilteringSet.set (lookup_props >> 16); 1.596 + } 1.597 + return TRACE_RETURN (true); 1.598 + } 1.599 + 1.600 + inline bool sanitize (hb_sanitize_context_t *c) { 1.601 + TRACE_SANITIZE (this); 1.602 + /* Real sanitize of the subtables is done by GSUB/GPOS/... */ 1.603 + if (!(c->check_struct (this) && subTable.sanitize (c))) return TRACE_RETURN (false); 1.604 + if (lookupFlag & LookupFlag::UseMarkFilteringSet) 1.605 + { 1.606 + USHORT &markFilteringSet = StructAfter<USHORT> (subTable); 1.607 + if (!markFilteringSet.sanitize (c)) return TRACE_RETURN (false); 1.608 + } 1.609 + return TRACE_RETURN (true); 1.610 + } 1.611 + 1.612 + USHORT lookupType; /* Different enumerations for GSUB and GPOS */ 1.613 + USHORT lookupFlag; /* Lookup qualifiers */ 1.614 + ArrayOf<Offset> 1.615 + subTable; /* Array of SubTables */ 1.616 + USHORT markFilteringSetX[VAR]; /* Index (base 0) into GDEF mark glyph sets 1.617 + * structure. This field is only present if bit 1.618 + * UseMarkFilteringSet of lookup flags is set. */ 1.619 + public: 1.620 + DEFINE_SIZE_ARRAY2 (6, subTable, markFilteringSetX); 1.621 +}; 1.622 + 1.623 +typedef OffsetListOf<Lookup> LookupList; 1.624 + 1.625 + 1.626 +/* 1.627 + * Coverage Table 1.628 + */ 1.629 + 1.630 +struct CoverageFormat1 1.631 +{ 1.632 + friend struct Coverage; 1.633 + 1.634 + private: 1.635 + inline unsigned int get_coverage (hb_codepoint_t glyph_id) const 1.636 + { 1.637 + int i = glyphArray.search (glyph_id); 1.638 + ASSERT_STATIC (((unsigned int) -1) == NOT_COVERED); 1.639 + return i; 1.640 + } 1.641 + 1.642 + inline bool serialize (hb_serialize_context_t *c, 1.643 + Supplier<GlyphID> &glyphs, 1.644 + unsigned int num_glyphs) 1.645 + { 1.646 + TRACE_SERIALIZE (this); 1.647 + if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); 1.648 + glyphArray.len.set (num_glyphs); 1.649 + if (unlikely (!c->extend (glyphArray))) return TRACE_RETURN (false); 1.650 + for (unsigned int i = 0; i < num_glyphs; i++) 1.651 + glyphArray[i] = glyphs[i]; 1.652 + glyphs.advance (num_glyphs); 1.653 + return TRACE_RETURN (true); 1.654 + } 1.655 + 1.656 + inline bool sanitize (hb_sanitize_context_t *c) { 1.657 + TRACE_SANITIZE (this); 1.658 + return TRACE_RETURN (glyphArray.sanitize (c)); 1.659 + } 1.660 + 1.661 + inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const { 1.662 + return glyphs->has (glyphArray[index]); 1.663 + } 1.664 + 1.665 + template <typename set_t> 1.666 + inline void add_coverage (set_t *glyphs) const { 1.667 + unsigned int count = glyphArray.len; 1.668 + for (unsigned int i = 0; i < count; i++) 1.669 + glyphs->add (glyphArray[i]); 1.670 + } 1.671 + 1.672 + public: 1.673 + /* Older compilers need this to be public. */ 1.674 + struct Iter { 1.675 + inline void init (const struct CoverageFormat1 &c_) { c = &c_; i = 0; }; 1.676 + inline bool more (void) { return i < c->glyphArray.len; } 1.677 + inline void next (void) { i++; } 1.678 + inline uint16_t get_glyph (void) { return c->glyphArray[i]; } 1.679 + inline uint16_t get_coverage (void) { return i; } 1.680 + 1.681 + private: 1.682 + const struct CoverageFormat1 *c; 1.683 + unsigned int i; 1.684 + }; 1.685 + private: 1.686 + 1.687 + protected: 1.688 + USHORT coverageFormat; /* Format identifier--format = 1 */ 1.689 + SortedArrayOf<GlyphID> 1.690 + glyphArray; /* Array of GlyphIDs--in numerical order */ 1.691 + public: 1.692 + DEFINE_SIZE_ARRAY (4, glyphArray); 1.693 +}; 1.694 + 1.695 +struct CoverageFormat2 1.696 +{ 1.697 + friend struct Coverage; 1.698 + 1.699 + private: 1.700 + inline unsigned int get_coverage (hb_codepoint_t glyph_id) const 1.701 + { 1.702 + int i = rangeRecord.search (glyph_id); 1.703 + if (i != -1) { 1.704 + const RangeRecord &range = rangeRecord[i]; 1.705 + return (unsigned int) range.value + (glyph_id - range.start); 1.706 + } 1.707 + return NOT_COVERED; 1.708 + } 1.709 + 1.710 + inline bool serialize (hb_serialize_context_t *c, 1.711 + Supplier<GlyphID> &glyphs, 1.712 + unsigned int num_glyphs) 1.713 + { 1.714 + TRACE_SERIALIZE (this); 1.715 + if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); 1.716 + 1.717 + if (unlikely (!num_glyphs)) return TRACE_RETURN (true); 1.718 + 1.719 + unsigned int num_ranges = 1; 1.720 + for (unsigned int i = 1; i < num_glyphs; i++) 1.721 + if (glyphs[i - 1] + 1 != glyphs[i]) 1.722 + num_ranges++; 1.723 + rangeRecord.len.set (num_ranges); 1.724 + if (unlikely (!c->extend (rangeRecord))) return TRACE_RETURN (false); 1.725 + 1.726 + unsigned int range = 0; 1.727 + rangeRecord[range].start = glyphs[0]; 1.728 + rangeRecord[range].value.set (0); 1.729 + for (unsigned int i = 1; i < num_glyphs; i++) 1.730 + if (glyphs[i - 1] + 1 != glyphs[i]) { 1.731 + range++; 1.732 + rangeRecord[range].start = glyphs[i]; 1.733 + rangeRecord[range].value.set (i); 1.734 + rangeRecord[range].end = glyphs[i]; 1.735 + } else { 1.736 + rangeRecord[range].end = glyphs[i]; 1.737 + } 1.738 + glyphs.advance (num_glyphs); 1.739 + return TRACE_RETURN (true); 1.740 + } 1.741 + 1.742 + inline bool sanitize (hb_sanitize_context_t *c) { 1.743 + TRACE_SANITIZE (this); 1.744 + return TRACE_RETURN (rangeRecord.sanitize (c)); 1.745 + } 1.746 + 1.747 + inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const { 1.748 + unsigned int i; 1.749 + unsigned int count = rangeRecord.len; 1.750 + for (i = 0; i < count; i++) { 1.751 + const RangeRecord &range = rangeRecord[i]; 1.752 + if (range.value <= index && 1.753 + index < (unsigned int) range.value + (range.end - range.start) && 1.754 + range.intersects (glyphs)) 1.755 + return true; 1.756 + else if (index < range.value) 1.757 + return false; 1.758 + } 1.759 + return false; 1.760 + } 1.761 + 1.762 + template <typename set_t> 1.763 + inline void add_coverage (set_t *glyphs) const { 1.764 + unsigned int count = rangeRecord.len; 1.765 + for (unsigned int i = 0; i < count; i++) 1.766 + rangeRecord[i].add_coverage (glyphs); 1.767 + } 1.768 + 1.769 + public: 1.770 + /* Older compilers need this to be public. */ 1.771 + struct Iter { 1.772 + inline void init (const CoverageFormat2 &c_) { 1.773 + c = &c_; 1.774 + coverage = 0; 1.775 + i = 0; 1.776 + j = c->rangeRecord.len ? c_.rangeRecord[0].start : 0; 1.777 + } 1.778 + inline bool more (void) { return i < c->rangeRecord.len; } 1.779 + inline void next (void) { 1.780 + coverage++; 1.781 + if (j == c->rangeRecord[i].end) { 1.782 + i++; 1.783 + if (more ()) 1.784 + j = c->rangeRecord[i].start; 1.785 + return; 1.786 + } 1.787 + j++; 1.788 + } 1.789 + inline uint16_t get_glyph (void) { return j; } 1.790 + inline uint16_t get_coverage (void) { return coverage; } 1.791 + 1.792 + private: 1.793 + const struct CoverageFormat2 *c; 1.794 + unsigned int i, j, coverage; 1.795 + }; 1.796 + private: 1.797 + 1.798 + protected: 1.799 + USHORT coverageFormat; /* Format identifier--format = 2 */ 1.800 + SortedArrayOf<RangeRecord> 1.801 + rangeRecord; /* Array of glyph ranges--ordered by 1.802 + * Start GlyphID. rangeCount entries 1.803 + * long */ 1.804 + public: 1.805 + DEFINE_SIZE_ARRAY (4, rangeRecord); 1.806 +}; 1.807 + 1.808 +struct Coverage 1.809 +{ 1.810 + inline unsigned int get_coverage (hb_codepoint_t glyph_id) const 1.811 + { 1.812 + switch (u.format) { 1.813 + case 1: return u.format1.get_coverage(glyph_id); 1.814 + case 2: return u.format2.get_coverage(glyph_id); 1.815 + default:return NOT_COVERED; 1.816 + } 1.817 + } 1.818 + 1.819 + inline bool serialize (hb_serialize_context_t *c, 1.820 + Supplier<GlyphID> &glyphs, 1.821 + unsigned int num_glyphs) 1.822 + { 1.823 + TRACE_SERIALIZE (this); 1.824 + if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); 1.825 + unsigned int num_ranges = 1; 1.826 + for (unsigned int i = 1; i < num_glyphs; i++) 1.827 + if (glyphs[i - 1] + 1 != glyphs[i]) 1.828 + num_ranges++; 1.829 + u.format.set (num_glyphs * 2 < num_ranges * 3 ? 1 : 2); 1.830 + switch (u.format) { 1.831 + case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, num_glyphs)); 1.832 + case 2: return TRACE_RETURN (u.format2.serialize (c, glyphs, num_glyphs)); 1.833 + default:return TRACE_RETURN (false); 1.834 + } 1.835 + } 1.836 + 1.837 + inline bool sanitize (hb_sanitize_context_t *c) { 1.838 + TRACE_SANITIZE (this); 1.839 + if (!u.format.sanitize (c)) return TRACE_RETURN (false); 1.840 + switch (u.format) { 1.841 + case 1: return TRACE_RETURN (u.format1.sanitize (c)); 1.842 + case 2: return TRACE_RETURN (u.format2.sanitize (c)); 1.843 + default:return TRACE_RETURN (true); 1.844 + } 1.845 + } 1.846 + 1.847 + inline bool intersects (const hb_set_t *glyphs) const { 1.848 + /* TODO speed this up */ 1.849 + Coverage::Iter iter; 1.850 + for (iter.init (*this); iter.more (); iter.next ()) { 1.851 + if (glyphs->has (iter.get_glyph ())) 1.852 + return true; 1.853 + } 1.854 + return false; 1.855 + } 1.856 + 1.857 + inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const { 1.858 + switch (u.format) { 1.859 + case 1: return u.format1.intersects_coverage (glyphs, index); 1.860 + case 2: return u.format2.intersects_coverage (glyphs, index); 1.861 + default:return false; 1.862 + } 1.863 + } 1.864 + 1.865 + template <typename set_t> 1.866 + inline void add_coverage (set_t *glyphs) const { 1.867 + switch (u.format) { 1.868 + case 1: u.format1.add_coverage (glyphs); break; 1.869 + case 2: u.format2.add_coverage (glyphs); break; 1.870 + default: break; 1.871 + } 1.872 + } 1.873 + 1.874 + struct Iter { 1.875 + Iter (void) : format (0) {}; 1.876 + inline void init (const Coverage &c_) { 1.877 + format = c_.u.format; 1.878 + switch (format) { 1.879 + case 1: u.format1.init (c_.u.format1); return; 1.880 + case 2: u.format2.init (c_.u.format2); return; 1.881 + default: return; 1.882 + } 1.883 + } 1.884 + inline bool more (void) { 1.885 + switch (format) { 1.886 + case 1: return u.format1.more (); 1.887 + case 2: return u.format2.more (); 1.888 + default:return false; 1.889 + } 1.890 + } 1.891 + inline void next (void) { 1.892 + switch (format) { 1.893 + case 1: u.format1.next (); break; 1.894 + case 2: u.format2.next (); break; 1.895 + default: break; 1.896 + } 1.897 + } 1.898 + inline uint16_t get_glyph (void) { 1.899 + switch (format) { 1.900 + case 1: return u.format1.get_glyph (); 1.901 + case 2: return u.format2.get_glyph (); 1.902 + default:return 0; 1.903 + } 1.904 + } 1.905 + inline uint16_t get_coverage (void) { 1.906 + switch (format) { 1.907 + case 1: return u.format1.get_coverage (); 1.908 + case 2: return u.format2.get_coverage (); 1.909 + default:return -1; 1.910 + } 1.911 + } 1.912 + 1.913 + private: 1.914 + unsigned int format; 1.915 + union { 1.916 + CoverageFormat1::Iter format1; 1.917 + CoverageFormat2::Iter format2; 1.918 + } u; 1.919 + }; 1.920 + 1.921 + protected: 1.922 + union { 1.923 + USHORT format; /* Format identifier */ 1.924 + CoverageFormat1 format1; 1.925 + CoverageFormat2 format2; 1.926 + } u; 1.927 + public: 1.928 + DEFINE_SIZE_UNION (2, format); 1.929 +}; 1.930 + 1.931 + 1.932 +/* 1.933 + * Class Definition Table 1.934 + */ 1.935 + 1.936 +struct ClassDefFormat1 1.937 +{ 1.938 + friend struct ClassDef; 1.939 + 1.940 + private: 1.941 + inline unsigned int get_class (hb_codepoint_t glyph_id) const 1.942 + { 1.943 + if (unlikely ((unsigned int) (glyph_id - startGlyph) < classValue.len)) 1.944 + return classValue[glyph_id - startGlyph]; 1.945 + return 0; 1.946 + } 1.947 + 1.948 + inline bool sanitize (hb_sanitize_context_t *c) { 1.949 + TRACE_SANITIZE (this); 1.950 + return TRACE_RETURN (c->check_struct (this) && classValue.sanitize (c)); 1.951 + } 1.952 + 1.953 + template <typename set_t> 1.954 + inline void add_class (set_t *glyphs, unsigned int klass) const { 1.955 + unsigned int count = classValue.len; 1.956 + for (unsigned int i = 0; i < count; i++) 1.957 + if (classValue[i] == klass) 1.958 + glyphs->add (startGlyph + i); 1.959 + } 1.960 + 1.961 + inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const { 1.962 + unsigned int count = classValue.len; 1.963 + if (klass == 0) 1.964 + { 1.965 + /* Match if there's any glyph that is not listed! */ 1.966 + hb_codepoint_t g = -1; 1.967 + if (!hb_set_next (glyphs, &g)) 1.968 + return false; 1.969 + if (g < startGlyph) 1.970 + return true; 1.971 + g = startGlyph + count - 1; 1.972 + if (hb_set_next (glyphs, &g)) 1.973 + return true; 1.974 + /* Fall through. */ 1.975 + } 1.976 + for (unsigned int i = 0; i < count; i++) 1.977 + if (classValue[i] == klass && glyphs->has (startGlyph + i)) 1.978 + return true; 1.979 + return false; 1.980 + } 1.981 + 1.982 + protected: 1.983 + USHORT classFormat; /* Format identifier--format = 1 */ 1.984 + GlyphID startGlyph; /* First GlyphID of the classValueArray */ 1.985 + ArrayOf<USHORT> 1.986 + classValue; /* Array of Class Values--one per GlyphID */ 1.987 + public: 1.988 + DEFINE_SIZE_ARRAY (6, classValue); 1.989 +}; 1.990 + 1.991 +struct ClassDefFormat2 1.992 +{ 1.993 + friend struct ClassDef; 1.994 + 1.995 + private: 1.996 + inline unsigned int get_class (hb_codepoint_t glyph_id) const 1.997 + { 1.998 + int i = rangeRecord.search (glyph_id); 1.999 + if (i != -1) 1.1000 + return rangeRecord[i].value; 1.1001 + return 0; 1.1002 + } 1.1003 + 1.1004 + inline bool sanitize (hb_sanitize_context_t *c) { 1.1005 + TRACE_SANITIZE (this); 1.1006 + return TRACE_RETURN (rangeRecord.sanitize (c)); 1.1007 + } 1.1008 + 1.1009 + template <typename set_t> 1.1010 + inline void add_class (set_t *glyphs, unsigned int klass) const { 1.1011 + unsigned int count = rangeRecord.len; 1.1012 + for (unsigned int i = 0; i < count; i++) 1.1013 + if (rangeRecord[i].value == klass) 1.1014 + rangeRecord[i].add_coverage (glyphs); 1.1015 + } 1.1016 + 1.1017 + inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const { 1.1018 + unsigned int count = rangeRecord.len; 1.1019 + if (klass == 0) 1.1020 + { 1.1021 + /* Match if there's any glyph that is not listed! */ 1.1022 + hb_codepoint_t g = (hb_codepoint_t) -1; 1.1023 + for (unsigned int i = 0; i < count; i++) 1.1024 + { 1.1025 + if (!hb_set_next (glyphs, &g)) 1.1026 + break; 1.1027 + if (g < rangeRecord[i].start) 1.1028 + return true; 1.1029 + g = rangeRecord[i].end; 1.1030 + } 1.1031 + if (g != (hb_codepoint_t) -1 && hb_set_next (glyphs, &g)) 1.1032 + return true; 1.1033 + /* Fall through. */ 1.1034 + } 1.1035 + for (unsigned int i = 0; i < count; i++) 1.1036 + if (rangeRecord[i].value == klass && rangeRecord[i].intersects (glyphs)) 1.1037 + return true; 1.1038 + return false; 1.1039 + } 1.1040 + 1.1041 + protected: 1.1042 + USHORT classFormat; /* Format identifier--format = 2 */ 1.1043 + SortedArrayOf<RangeRecord> 1.1044 + rangeRecord; /* Array of glyph ranges--ordered by 1.1045 + * Start GlyphID */ 1.1046 + public: 1.1047 + DEFINE_SIZE_ARRAY (4, rangeRecord); 1.1048 +}; 1.1049 + 1.1050 +struct ClassDef 1.1051 +{ 1.1052 + inline unsigned int get_class (hb_codepoint_t glyph_id) const 1.1053 + { 1.1054 + switch (u.format) { 1.1055 + case 1: return u.format1.get_class(glyph_id); 1.1056 + case 2: return u.format2.get_class(glyph_id); 1.1057 + default:return 0; 1.1058 + } 1.1059 + } 1.1060 + 1.1061 + inline bool sanitize (hb_sanitize_context_t *c) { 1.1062 + TRACE_SANITIZE (this); 1.1063 + if (!u.format.sanitize (c)) return TRACE_RETURN (false); 1.1064 + switch (u.format) { 1.1065 + case 1: return TRACE_RETURN (u.format1.sanitize (c)); 1.1066 + case 2: return TRACE_RETURN (u.format2.sanitize (c)); 1.1067 + default:return TRACE_RETURN (true); 1.1068 + } 1.1069 + } 1.1070 + 1.1071 + inline void add_class (hb_set_t *glyphs, unsigned int klass) const { 1.1072 + switch (u.format) { 1.1073 + case 1: u.format1.add_class (glyphs, klass); return; 1.1074 + case 2: u.format2.add_class (glyphs, klass); return; 1.1075 + default:return; 1.1076 + } 1.1077 + } 1.1078 + 1.1079 + inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const { 1.1080 + switch (u.format) { 1.1081 + case 1: return u.format1.intersects_class (glyphs, klass); 1.1082 + case 2: return u.format2.intersects_class (glyphs, klass); 1.1083 + default:return false; 1.1084 + } 1.1085 + } 1.1086 + 1.1087 + protected: 1.1088 + union { 1.1089 + USHORT format; /* Format identifier */ 1.1090 + ClassDefFormat1 format1; 1.1091 + ClassDefFormat2 format2; 1.1092 + } u; 1.1093 + public: 1.1094 + DEFINE_SIZE_UNION (2, format); 1.1095 +}; 1.1096 + 1.1097 + 1.1098 +/* 1.1099 + * Device Tables 1.1100 + */ 1.1101 + 1.1102 +struct Device 1.1103 +{ 1.1104 + 1.1105 + inline hb_position_t get_x_delta (hb_font_t *font) const 1.1106 + { return get_delta (font->x_ppem, font->x_scale); } 1.1107 + 1.1108 + inline hb_position_t get_y_delta (hb_font_t *font) const 1.1109 + { return get_delta (font->y_ppem, font->y_scale); } 1.1110 + 1.1111 + inline int get_delta (unsigned int ppem, int scale) const 1.1112 + { 1.1113 + if (!ppem) return 0; 1.1114 + 1.1115 + int pixels = get_delta_pixels (ppem); 1.1116 + 1.1117 + if (!pixels) return 0; 1.1118 + 1.1119 + return (int) (pixels * (int64_t) scale / ppem); 1.1120 + } 1.1121 + 1.1122 + 1.1123 + inline int get_delta_pixels (unsigned int ppem_size) const 1.1124 + { 1.1125 + unsigned int f = deltaFormat; 1.1126 + if (unlikely (f < 1 || f > 3)) 1.1127 + return 0; 1.1128 + 1.1129 + if (ppem_size < startSize || ppem_size > endSize) 1.1130 + return 0; 1.1131 + 1.1132 + unsigned int s = ppem_size - startSize; 1.1133 + 1.1134 + unsigned int byte = deltaValue[s >> (4 - f)]; 1.1135 + unsigned int bits = (byte >> (16 - (((s & ((1 << (4 - f)) - 1)) + 1) << f))); 1.1136 + unsigned int mask = (0xFFFF >> (16 - (1 << f))); 1.1137 + 1.1138 + int delta = bits & mask; 1.1139 + 1.1140 + if ((unsigned int) delta >= ((mask + 1) >> 1)) 1.1141 + delta -= mask + 1; 1.1142 + 1.1143 + return delta; 1.1144 + } 1.1145 + 1.1146 + inline unsigned int get_size (void) const 1.1147 + { 1.1148 + unsigned int f = deltaFormat; 1.1149 + if (unlikely (f < 1 || f > 3 || startSize > endSize)) return 3 * USHORT::static_size; 1.1150 + return USHORT::static_size * (4 + ((endSize - startSize) >> (4 - f))); 1.1151 + } 1.1152 + 1.1153 + inline bool sanitize (hb_sanitize_context_t *c) { 1.1154 + TRACE_SANITIZE (this); 1.1155 + return TRACE_RETURN (c->check_struct (this) && c->check_range (this, this->get_size ())); 1.1156 + } 1.1157 + 1.1158 + protected: 1.1159 + USHORT startSize; /* Smallest size to correct--in ppem */ 1.1160 + USHORT endSize; /* Largest size to correct--in ppem */ 1.1161 + USHORT deltaFormat; /* Format of DeltaValue array data: 1, 2, or 3 1.1162 + * 1 Signed 2-bit value, 8 values per uint16 1.1163 + * 2 Signed 4-bit value, 4 values per uint16 1.1164 + * 3 Signed 8-bit value, 2 values per uint16 1.1165 + */ 1.1166 + USHORT deltaValue[VAR]; /* Array of compressed data */ 1.1167 + public: 1.1168 + DEFINE_SIZE_ARRAY (6, deltaValue); 1.1169 +}; 1.1170 + 1.1171 + 1.1172 +} /* namespace OT */ 1.1173 + 1.1174 + 1.1175 +#endif /* HB_OT_LAYOUT_COMMON_PRIVATE_HH */