| 1 | /* | 
|---|
| 2 | * Copyright © 2018 Adobe Inc. | 
|---|
| 3 | * | 
|---|
| 4 | *  This is part of HarfBuzz, a text shaping library. | 
|---|
| 5 | * | 
|---|
| 6 | * Permission is hereby granted, without written agreement and without | 
|---|
| 7 | * license or royalty fees, to use, copy, modify, and distribute this | 
|---|
| 8 | * software and its documentation for any purpose, provided that the | 
|---|
| 9 | * above copyright notice and the following two paragraphs appear in | 
|---|
| 10 | * all copies of this software. | 
|---|
| 11 | * | 
|---|
| 12 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR | 
|---|
| 13 | * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES | 
|---|
| 14 | * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN | 
|---|
| 15 | * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH | 
|---|
| 16 | * DAMAGE. | 
|---|
| 17 | * | 
|---|
| 18 | * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, | 
|---|
| 19 | * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND | 
|---|
| 20 | * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS | 
|---|
| 21 | * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO | 
|---|
| 22 | * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. | 
|---|
| 23 | * | 
|---|
| 24 | * Adobe Author(s): Michiharu Ariza | 
|---|
| 25 | */ | 
|---|
| 26 |  | 
|---|
| 27 | #ifndef HB_OT_CFF2_TABLE_HH | 
|---|
| 28 | #define HB_OT_CFF2_TABLE_HH | 
|---|
| 29 |  | 
|---|
| 30 | #include "hb-ot-head-table.hh" | 
|---|
| 31 | #include "hb-ot-cff-common.hh" | 
|---|
| 32 | #include "hb-subset-cff2.hh" | 
|---|
| 33 |  | 
|---|
| 34 | namespace CFF { | 
|---|
| 35 |  | 
|---|
| 36 | /* | 
|---|
| 37 | * CFF2 -- Compact Font Format (CFF) Version 2 | 
|---|
| 38 | * https://docs.microsoft.com/en-us/typography/opentype/spec/cff2 | 
|---|
| 39 | */ | 
|---|
| 40 | #define HB_OT_TAG_cff2 HB_TAG('C','F','F','2') | 
|---|
| 41 |  | 
|---|
| 42 | typedef CFFIndex<HBUINT32>  CFF2Index; | 
|---|
| 43 | template <typename Type> struct CFF2IndexOf : CFFIndexOf<HBUINT32, Type> {}; | 
|---|
| 44 |  | 
|---|
| 45 | typedef CFF2Index         CFF2CharStrings; | 
|---|
| 46 | typedef FDArray<HBUINT32> CFF2FDArray; | 
|---|
| 47 | typedef Subrs<HBUINT32>   CFF2Subrs; | 
|---|
| 48 |  | 
|---|
| 49 | typedef FDSelect3_4<HBUINT32, HBUINT16> FDSelect4; | 
|---|
| 50 | typedef FDSelect3_4_Range<HBUINT32, HBUINT16> FDSelect4_Range; | 
|---|
| 51 |  | 
|---|
| 52 | struct CFF2FDSelect | 
|---|
| 53 | { | 
|---|
| 54 | bool serialize (hb_serialize_context_t *c, const CFF2FDSelect &src, unsigned int num_glyphs) | 
|---|
| 55 | { | 
|---|
| 56 | TRACE_SERIALIZE (this); | 
|---|
| 57 | unsigned int size = src.get_size (num_glyphs); | 
|---|
| 58 | CFF2FDSelect *dest = c->allocate_size<CFF2FDSelect> (size); | 
|---|
| 59 | if (unlikely (dest == nullptr)) return_trace (false); | 
|---|
| 60 | memcpy (dest, &src, size); | 
|---|
| 61 | return_trace (true); | 
|---|
| 62 | } | 
|---|
| 63 |  | 
|---|
| 64 | unsigned int calculate_serialized_size (unsigned int num_glyphs) const | 
|---|
| 65 | { return get_size (num_glyphs); } | 
|---|
| 66 |  | 
|---|
| 67 | unsigned int get_size (unsigned int num_glyphs) const | 
|---|
| 68 | { | 
|---|
| 69 | switch (format) | 
|---|
| 70 | { | 
|---|
| 71 | case 0: return format.static_size + u.format0.get_size (num_glyphs); | 
|---|
| 72 | case 3: return format.static_size + u.format3.get_size (); | 
|---|
| 73 | case 4: return format.static_size + u.format4.get_size (); | 
|---|
| 74 | default:return 0; | 
|---|
| 75 | } | 
|---|
| 76 | } | 
|---|
| 77 |  | 
|---|
| 78 | hb_codepoint_t get_fd (hb_codepoint_t glyph) const | 
|---|
| 79 | { | 
|---|
| 80 | if (this == &Null (CFF2FDSelect)) | 
|---|
| 81 | return 0; | 
|---|
| 82 |  | 
|---|
| 83 | switch (format) | 
|---|
| 84 | { | 
|---|
| 85 | case 0: return u.format0.get_fd (glyph); | 
|---|
| 86 | case 3: return u.format3.get_fd (glyph); | 
|---|
| 87 | case 4: return u.format4.get_fd (glyph); | 
|---|
| 88 | default:return 0; | 
|---|
| 89 | } | 
|---|
| 90 | } | 
|---|
| 91 |  | 
|---|
| 92 | bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const | 
|---|
| 93 | { | 
|---|
| 94 | TRACE_SANITIZE (this); | 
|---|
| 95 | if (unlikely (!c->check_struct (this))) | 
|---|
| 96 | return_trace (false); | 
|---|
| 97 |  | 
|---|
| 98 | switch (format) | 
|---|
| 99 | { | 
|---|
| 100 | case 0: return_trace (u.format0.sanitize (c, fdcount)); | 
|---|
| 101 | case 3: return_trace (u.format3.sanitize (c, fdcount)); | 
|---|
| 102 | case 4: return_trace (u.format4.sanitize (c, fdcount)); | 
|---|
| 103 | default:return_trace (false); | 
|---|
| 104 | } | 
|---|
| 105 | } | 
|---|
| 106 |  | 
|---|
| 107 | HBUINT8	format; | 
|---|
| 108 | union { | 
|---|
| 109 | FDSelect0	format0; | 
|---|
| 110 | FDSelect3	format3; | 
|---|
| 111 | FDSelect4	format4; | 
|---|
| 112 | } u; | 
|---|
| 113 | public: | 
|---|
| 114 | DEFINE_SIZE_MIN (2); | 
|---|
| 115 | }; | 
|---|
| 116 |  | 
|---|
| 117 | struct CFF2VariationStore | 
|---|
| 118 | { | 
|---|
| 119 | bool sanitize (hb_sanitize_context_t *c) const | 
|---|
| 120 | { | 
|---|
| 121 | TRACE_SANITIZE (this); | 
|---|
| 122 | return_trace (likely (c->check_struct (this)) && c->check_range (&varStore, size) && varStore.sanitize (c)); | 
|---|
| 123 | } | 
|---|
| 124 |  | 
|---|
| 125 | bool serialize (hb_serialize_context_t *c, const CFF2VariationStore *varStore) | 
|---|
| 126 | { | 
|---|
| 127 | TRACE_SERIALIZE (this); | 
|---|
| 128 | unsigned int size_ = varStore->get_size (); | 
|---|
| 129 | CFF2VariationStore *dest = c->allocate_size<CFF2VariationStore> (size_); | 
|---|
| 130 | if (unlikely (dest == nullptr)) return_trace (false); | 
|---|
| 131 | memcpy (dest, varStore, size_); | 
|---|
| 132 | return_trace (true); | 
|---|
| 133 | } | 
|---|
| 134 |  | 
|---|
| 135 | unsigned int get_size () const { return HBUINT16::static_size + size; } | 
|---|
| 136 |  | 
|---|
| 137 | HBUINT16	size; | 
|---|
| 138 | VariationStore  varStore; | 
|---|
| 139 |  | 
|---|
| 140 | DEFINE_SIZE_MIN (2 + VariationStore::min_size); | 
|---|
| 141 | }; | 
|---|
| 142 |  | 
|---|
| 143 | struct cff2_top_dict_values_t : top_dict_values_t<> | 
|---|
| 144 | { | 
|---|
| 145 | void init () | 
|---|
| 146 | { | 
|---|
| 147 | top_dict_values_t<>::init (); | 
|---|
| 148 | vstoreOffset = 0; | 
|---|
| 149 | FDSelectOffset = 0; | 
|---|
| 150 | } | 
|---|
| 151 | void fini () { top_dict_values_t<>::fini (); } | 
|---|
| 152 |  | 
|---|
| 153 | unsigned int calculate_serialized_size () const | 
|---|
| 154 | { | 
|---|
| 155 | unsigned int size = 0; | 
|---|
| 156 | for (unsigned int i = 0; i < get_count (); i++) | 
|---|
| 157 | { | 
|---|
| 158 | op_code_t op = get_value (i).op; | 
|---|
| 159 | switch (op) | 
|---|
| 160 | { | 
|---|
| 161 | case OpCode_vstore: | 
|---|
| 162 | case OpCode_FDSelect: | 
|---|
| 163 | size += OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (op); | 
|---|
| 164 | break; | 
|---|
| 165 | default: | 
|---|
| 166 | size += top_dict_values_t<>::calculate_serialized_op_size (get_value (i)); | 
|---|
| 167 | break; | 
|---|
| 168 | } | 
|---|
| 169 | } | 
|---|
| 170 | return size; | 
|---|
| 171 | } | 
|---|
| 172 |  | 
|---|
| 173 | unsigned int  vstoreOffset; | 
|---|
| 174 | unsigned int  FDSelectOffset; | 
|---|
| 175 | }; | 
|---|
| 176 |  | 
|---|
| 177 | struct cff2_top_dict_opset_t : top_dict_opset_t<> | 
|---|
| 178 | { | 
|---|
| 179 | static void process_op (op_code_t op, num_interp_env_t& env, cff2_top_dict_values_t& dictval) | 
|---|
| 180 | { | 
|---|
| 181 | switch (op) { | 
|---|
| 182 | case OpCode_FontMatrix: | 
|---|
| 183 | { | 
|---|
| 184 | dict_val_t val; | 
|---|
| 185 | val.init (); | 
|---|
| 186 | dictval.add_op (op, env.str_ref); | 
|---|
| 187 | env.clear_args (); | 
|---|
| 188 | } | 
|---|
| 189 | break; | 
|---|
| 190 |  | 
|---|
| 191 | case OpCode_vstore: | 
|---|
| 192 | dictval.vstoreOffset = env.argStack.pop_uint (); | 
|---|
| 193 | env.clear_args (); | 
|---|
| 194 | break; | 
|---|
| 195 | case OpCode_FDSelect: | 
|---|
| 196 | dictval.FDSelectOffset = env.argStack.pop_uint (); | 
|---|
| 197 | env.clear_args (); | 
|---|
| 198 | break; | 
|---|
| 199 |  | 
|---|
| 200 | default: | 
|---|
| 201 | SUPER::process_op (op, env, dictval); | 
|---|
| 202 | /* Record this operand below if stack is empty, otherwise done */ | 
|---|
| 203 | if (!env.argStack.is_empty ()) return; | 
|---|
| 204 | } | 
|---|
| 205 |  | 
|---|
| 206 | if (unlikely (env.in_error ())) return; | 
|---|
| 207 |  | 
|---|
| 208 | dictval.add_op (op, env.str_ref); | 
|---|
| 209 | } | 
|---|
| 210 |  | 
|---|
| 211 | typedef top_dict_opset_t<> SUPER; | 
|---|
| 212 | }; | 
|---|
| 213 |  | 
|---|
| 214 | struct cff2_font_dict_values_t : dict_values_t<op_str_t> | 
|---|
| 215 | { | 
|---|
| 216 | void init () | 
|---|
| 217 | { | 
|---|
| 218 | dict_values_t<op_str_t>::init (); | 
|---|
| 219 | privateDictInfo.init (); | 
|---|
| 220 | } | 
|---|
| 221 | void fini () { dict_values_t<op_str_t>::fini (); } | 
|---|
| 222 |  | 
|---|
| 223 | table_info_t    privateDictInfo; | 
|---|
| 224 | }; | 
|---|
| 225 |  | 
|---|
| 226 | struct cff2_font_dict_opset_t : dict_opset_t | 
|---|
| 227 | { | 
|---|
| 228 | static void process_op (op_code_t op, num_interp_env_t& env, cff2_font_dict_values_t& dictval) | 
|---|
| 229 | { | 
|---|
| 230 | switch (op) { | 
|---|
| 231 | case OpCode_Private: | 
|---|
| 232 | dictval.privateDictInfo.offset = env.argStack.pop_uint (); | 
|---|
| 233 | dictval.privateDictInfo.size = env.argStack.pop_uint (); | 
|---|
| 234 | env.clear_args (); | 
|---|
| 235 | break; | 
|---|
| 236 |  | 
|---|
| 237 | default: | 
|---|
| 238 | SUPER::process_op (op, env); | 
|---|
| 239 | if (!env.argStack.is_empty ()) | 
|---|
| 240 | return; | 
|---|
| 241 | } | 
|---|
| 242 |  | 
|---|
| 243 | if (unlikely (env.in_error ())) return; | 
|---|
| 244 |  | 
|---|
| 245 | dictval.add_op (op, env.str_ref); | 
|---|
| 246 | } | 
|---|
| 247 |  | 
|---|
| 248 | private: | 
|---|
| 249 | typedef dict_opset_t SUPER; | 
|---|
| 250 | }; | 
|---|
| 251 |  | 
|---|
| 252 | template <typename VAL> | 
|---|
| 253 | struct cff2_private_dict_values_base_t : dict_values_t<VAL> | 
|---|
| 254 | { | 
|---|
| 255 | void init () | 
|---|
| 256 | { | 
|---|
| 257 | dict_values_t<VAL>::init (); | 
|---|
| 258 | subrsOffset = 0; | 
|---|
| 259 | localSubrs = &Null(CFF2Subrs); | 
|---|
| 260 | ivs = 0; | 
|---|
| 261 | } | 
|---|
| 262 | void fini () { dict_values_t<VAL>::fini (); } | 
|---|
| 263 |  | 
|---|
| 264 | unsigned int calculate_serialized_size () const | 
|---|
| 265 | { | 
|---|
| 266 | unsigned int size = 0; | 
|---|
| 267 | for (unsigned int i = 0; i < dict_values_t<VAL>::get_count; i++) | 
|---|
| 268 | if (dict_values_t<VAL>::get_value (i).op == OpCode_Subrs) | 
|---|
| 269 | size += OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Subrs); | 
|---|
| 270 | else | 
|---|
| 271 | size += dict_values_t<VAL>::get_value (i).str.length; | 
|---|
| 272 | return size; | 
|---|
| 273 | } | 
|---|
| 274 |  | 
|---|
| 275 | unsigned int      subrsOffset; | 
|---|
| 276 | const CFF2Subrs   *localSubrs; | 
|---|
| 277 | unsigned int      ivs; | 
|---|
| 278 | }; | 
|---|
| 279 |  | 
|---|
| 280 | typedef cff2_private_dict_values_base_t<op_str_t> cff2_private_dict_values_subset_t; | 
|---|
| 281 | typedef cff2_private_dict_values_base_t<num_dict_val_t> cff2_private_dict_values_t; | 
|---|
| 282 |  | 
|---|
| 283 | struct cff2_priv_dict_interp_env_t : num_interp_env_t | 
|---|
| 284 | { | 
|---|
| 285 | void init (const byte_str_t &str) | 
|---|
| 286 | { | 
|---|
| 287 | num_interp_env_t::init (str); | 
|---|
| 288 | ivs = 0; | 
|---|
| 289 | seen_vsindex = false; | 
|---|
| 290 | } | 
|---|
| 291 |  | 
|---|
| 292 | void process_vsindex () | 
|---|
| 293 | { | 
|---|
| 294 | if (likely (!seen_vsindex)) | 
|---|
| 295 | { | 
|---|
| 296 | set_ivs (argStack.pop_uint ()); | 
|---|
| 297 | } | 
|---|
| 298 | seen_vsindex = true; | 
|---|
| 299 | } | 
|---|
| 300 |  | 
|---|
| 301 | unsigned int get_ivs () const { return ivs; } | 
|---|
| 302 | void	 set_ivs (unsigned int ivs_) { ivs = ivs_; } | 
|---|
| 303 |  | 
|---|
| 304 | protected: | 
|---|
| 305 | unsigned int  ivs; | 
|---|
| 306 | bool	  seen_vsindex; | 
|---|
| 307 | }; | 
|---|
| 308 |  | 
|---|
| 309 | struct cff2_private_dict_opset_t : dict_opset_t | 
|---|
| 310 | { | 
|---|
| 311 | static void process_op (op_code_t op, cff2_priv_dict_interp_env_t& env, cff2_private_dict_values_t& dictval) | 
|---|
| 312 | { | 
|---|
| 313 | num_dict_val_t val; | 
|---|
| 314 | val.init (); | 
|---|
| 315 |  | 
|---|
| 316 | switch (op) { | 
|---|
| 317 | case OpCode_StdHW: | 
|---|
| 318 | case OpCode_StdVW: | 
|---|
| 319 | case OpCode_BlueScale: | 
|---|
| 320 | case OpCode_BlueShift: | 
|---|
| 321 | case OpCode_BlueFuzz: | 
|---|
| 322 | case OpCode_ExpansionFactor: | 
|---|
| 323 | case OpCode_LanguageGroup: | 
|---|
| 324 | val.single_val = env.argStack.pop_num (); | 
|---|
| 325 | env.clear_args (); | 
|---|
| 326 | break; | 
|---|
| 327 | case OpCode_BlueValues: | 
|---|
| 328 | case OpCode_OtherBlues: | 
|---|
| 329 | case OpCode_FamilyBlues: | 
|---|
| 330 | case OpCode_FamilyOtherBlues: | 
|---|
| 331 | case OpCode_StemSnapH: | 
|---|
| 332 | case OpCode_StemSnapV: | 
|---|
| 333 | env.clear_args (); | 
|---|
| 334 | break; | 
|---|
| 335 | case OpCode_Subrs: | 
|---|
| 336 | dictval.subrsOffset = env.argStack.pop_uint (); | 
|---|
| 337 | env.clear_args (); | 
|---|
| 338 | break; | 
|---|
| 339 | case OpCode_vsindexdict: | 
|---|
| 340 | env.process_vsindex (); | 
|---|
| 341 | dictval.ivs = env.get_ivs (); | 
|---|
| 342 | env.clear_args (); | 
|---|
| 343 | break; | 
|---|
| 344 | case OpCode_blenddict: | 
|---|
| 345 | break; | 
|---|
| 346 |  | 
|---|
| 347 | default: | 
|---|
| 348 | dict_opset_t::process_op (op, env); | 
|---|
| 349 | if (!env.argStack.is_empty ()) return; | 
|---|
| 350 | break; | 
|---|
| 351 | } | 
|---|
| 352 |  | 
|---|
| 353 | if (unlikely (env.in_error ())) return; | 
|---|
| 354 |  | 
|---|
| 355 | dictval.add_op (op, env.str_ref, val); | 
|---|
| 356 | } | 
|---|
| 357 | }; | 
|---|
| 358 |  | 
|---|
| 359 | struct cff2_private_dict_opset_subset_t : dict_opset_t | 
|---|
| 360 | { | 
|---|
| 361 | static void process_op (op_code_t op, cff2_priv_dict_interp_env_t& env, cff2_private_dict_values_subset_t& dictval) | 
|---|
| 362 | { | 
|---|
| 363 | switch (op) { | 
|---|
| 364 | case OpCode_BlueValues: | 
|---|
| 365 | case OpCode_OtherBlues: | 
|---|
| 366 | case OpCode_FamilyBlues: | 
|---|
| 367 | case OpCode_FamilyOtherBlues: | 
|---|
| 368 | case OpCode_StdHW: | 
|---|
| 369 | case OpCode_StdVW: | 
|---|
| 370 | case OpCode_BlueScale: | 
|---|
| 371 | case OpCode_BlueShift: | 
|---|
| 372 | case OpCode_BlueFuzz: | 
|---|
| 373 | case OpCode_StemSnapH: | 
|---|
| 374 | case OpCode_StemSnapV: | 
|---|
| 375 | case OpCode_LanguageGroup: | 
|---|
| 376 | case OpCode_ExpansionFactor: | 
|---|
| 377 | env.clear_args (); | 
|---|
| 378 | break; | 
|---|
| 379 |  | 
|---|
| 380 | case OpCode_blenddict: | 
|---|
| 381 | env.clear_args (); | 
|---|
| 382 | return; | 
|---|
| 383 |  | 
|---|
| 384 | case OpCode_Subrs: | 
|---|
| 385 | dictval.subrsOffset = env.argStack.pop_uint (); | 
|---|
| 386 | env.clear_args (); | 
|---|
| 387 | break; | 
|---|
| 388 |  | 
|---|
| 389 | default: | 
|---|
| 390 | SUPER::process_op (op, env); | 
|---|
| 391 | if (!env.argStack.is_empty ()) return; | 
|---|
| 392 | break; | 
|---|
| 393 | } | 
|---|
| 394 |  | 
|---|
| 395 | if (unlikely (env.in_error ())) return; | 
|---|
| 396 |  | 
|---|
| 397 | dictval.add_op (op, env.str_ref); | 
|---|
| 398 | } | 
|---|
| 399 |  | 
|---|
| 400 | private: | 
|---|
| 401 | typedef dict_opset_t SUPER; | 
|---|
| 402 | }; | 
|---|
| 403 |  | 
|---|
| 404 | typedef dict_interpreter_t<cff2_top_dict_opset_t, cff2_top_dict_values_t> cff2_top_dict_interpreter_t; | 
|---|
| 405 | typedef dict_interpreter_t<cff2_font_dict_opset_t, cff2_font_dict_values_t> cff2_font_dict_interpreter_t; | 
|---|
| 406 |  | 
|---|
| 407 | } /* namespace CFF */ | 
|---|
| 408 |  | 
|---|
| 409 | namespace OT { | 
|---|
| 410 |  | 
|---|
| 411 | using namespace CFF; | 
|---|
| 412 |  | 
|---|
| 413 | struct cff2 | 
|---|
| 414 | { | 
|---|
| 415 | static constexpr hb_tag_t tableTag = HB_OT_TAG_cff2; | 
|---|
| 416 |  | 
|---|
| 417 | bool sanitize (hb_sanitize_context_t *c) const | 
|---|
| 418 | { | 
|---|
| 419 | TRACE_SANITIZE (this); | 
|---|
| 420 | return_trace (c->check_struct (this) && | 
|---|
| 421 | likely (version.major == 2)); | 
|---|
| 422 | } | 
|---|
| 423 |  | 
|---|
| 424 | template <typename PRIVOPSET, typename PRIVDICTVAL> | 
|---|
| 425 | struct accelerator_templ_t | 
|---|
| 426 | { | 
|---|
| 427 | void init (hb_face_t *face) | 
|---|
| 428 | { | 
|---|
| 429 | topDict.init (); | 
|---|
| 430 | fontDicts.init (); | 
|---|
| 431 | privateDicts.init (); | 
|---|
| 432 |  | 
|---|
| 433 | this->blob = sc.reference_table<cff2> (face); | 
|---|
| 434 |  | 
|---|
| 435 | /* setup for run-time santization */ | 
|---|
| 436 | sc.init (this->blob); | 
|---|
| 437 | sc.start_processing (); | 
|---|
| 438 |  | 
|---|
| 439 | const OT::cff2 *cff2 = this->blob->template as<OT::cff2> (); | 
|---|
| 440 |  | 
|---|
| 441 | if (cff2 == &Null(OT::cff2)) | 
|---|
| 442 | { fini (); return; } | 
|---|
| 443 |  | 
|---|
| 444 | { /* parse top dict */ | 
|---|
| 445 | byte_str_t topDictStr (cff2 + cff2->topDict, cff2->topDictSize); | 
|---|
| 446 | if (unlikely (!topDictStr.sanitize (&sc))) { fini (); return; } | 
|---|
| 447 | cff2_top_dict_interpreter_t top_interp; | 
|---|
| 448 | top_interp.env.init (topDictStr); | 
|---|
| 449 | topDict.init (); | 
|---|
| 450 | if (unlikely (!top_interp.interpret (topDict))) { fini (); return; } | 
|---|
| 451 | } | 
|---|
| 452 |  | 
|---|
| 453 | globalSubrs = &StructAtOffset<CFF2Subrs> (cff2, cff2->topDict + cff2->topDictSize); | 
|---|
| 454 | varStore = &StructAtOffsetOrNull<CFF2VariationStore> (cff2, topDict.vstoreOffset); | 
|---|
| 455 | charStrings = &StructAtOffsetOrNull<CFF2CharStrings> (cff2, topDict.charStringsOffset); | 
|---|
| 456 | fdArray = &StructAtOffsetOrNull<CFF2FDArray> (cff2, topDict.FDArrayOffset); | 
|---|
| 457 | fdSelect = &StructAtOffsetOrNull<CFF2FDSelect> (cff2, topDict.FDSelectOffset); | 
|---|
| 458 |  | 
|---|
| 459 | if (((varStore != &Null(CFF2VariationStore)) && unlikely (!varStore->sanitize (&sc))) || | 
|---|
| 460 | (charStrings == &Null(CFF2CharStrings)) || unlikely (!charStrings->sanitize (&sc)) || | 
|---|
| 461 | (globalSubrs == &Null(CFF2Subrs)) || unlikely (!globalSubrs->sanitize (&sc)) || | 
|---|
| 462 | (fdArray == &Null(CFF2FDArray)) || unlikely (!fdArray->sanitize (&sc)) || | 
|---|
| 463 | (((fdSelect != &Null(CFF2FDSelect)) && unlikely (!fdSelect->sanitize (&sc, fdArray->count))))) | 
|---|
| 464 | { fini (); return; } | 
|---|
| 465 |  | 
|---|
| 466 | num_glyphs = charStrings->count; | 
|---|
| 467 | if (num_glyphs != sc.get_num_glyphs ()) | 
|---|
| 468 | { fini (); return; } | 
|---|
| 469 |  | 
|---|
| 470 | fdCount = fdArray->count; | 
|---|
| 471 | privateDicts.resize (fdCount); | 
|---|
| 472 |  | 
|---|
| 473 | /* parse font dicts and gather private dicts */ | 
|---|
| 474 | for (unsigned int i = 0; i < fdCount; i++) | 
|---|
| 475 | { | 
|---|
| 476 | const byte_str_t fontDictStr = (*fdArray)[i]; | 
|---|
| 477 | if (unlikely (!fontDictStr.sanitize (&sc))) { fini (); return; } | 
|---|
| 478 | cff2_font_dict_values_t  *font; | 
|---|
| 479 | cff2_font_dict_interpreter_t font_interp; | 
|---|
| 480 | font_interp.env.init (fontDictStr); | 
|---|
| 481 | font = fontDicts.push (); | 
|---|
| 482 | if (unlikely (font == &Crap(cff2_font_dict_values_t))) { fini (); return; } | 
|---|
| 483 | font->init (); | 
|---|
| 484 | if (unlikely (!font_interp.interpret (*font))) { fini (); return; } | 
|---|
| 485 |  | 
|---|
| 486 | const byte_str_t privDictStr (StructAtOffsetOrNull<UnsizedByteStr> (cff2, font->privateDictInfo.offset), font->privateDictInfo.size); | 
|---|
| 487 | if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; } | 
|---|
| 488 | dict_interpreter_t<PRIVOPSET, PRIVDICTVAL, cff2_priv_dict_interp_env_t>  priv_interp; | 
|---|
| 489 | priv_interp.env.init(privDictStr); | 
|---|
| 490 | privateDicts[i].init (); | 
|---|
| 491 | if (unlikely (!priv_interp.interpret (privateDicts[i]))) { fini (); return; } | 
|---|
| 492 |  | 
|---|
| 493 | privateDicts[i].localSubrs = &StructAtOffsetOrNull<CFF2Subrs> (&privDictStr[0], privateDicts[i].subrsOffset); | 
|---|
| 494 | if (privateDicts[i].localSubrs != &Null(CFF2Subrs) && | 
|---|
| 495 | unlikely (!privateDicts[i].localSubrs->sanitize (&sc))) | 
|---|
| 496 | { fini (); return; } | 
|---|
| 497 | } | 
|---|
| 498 | } | 
|---|
| 499 |  | 
|---|
| 500 | void fini () | 
|---|
| 501 | { | 
|---|
| 502 | sc.end_processing (); | 
|---|
| 503 | topDict.fini (); | 
|---|
| 504 | fontDicts.fini_deep (); | 
|---|
| 505 | privateDicts.fini_deep (); | 
|---|
| 506 | hb_blob_destroy (blob); | 
|---|
| 507 | blob = nullptr; | 
|---|
| 508 | } | 
|---|
| 509 |  | 
|---|
| 510 | bool is_valid () const { return blob != nullptr; } | 
|---|
| 511 |  | 
|---|
| 512 | protected: | 
|---|
| 513 | hb_blob_t			*blob; | 
|---|
| 514 | hb_sanitize_context_t	sc; | 
|---|
| 515 |  | 
|---|
| 516 | public: | 
|---|
| 517 | cff2_top_dict_values_t	topDict; | 
|---|
| 518 | const CFF2Subrs		*globalSubrs; | 
|---|
| 519 | const CFF2VariationStore	*varStore; | 
|---|
| 520 | const CFF2CharStrings	*charStrings; | 
|---|
| 521 | const CFF2FDArray		*fdArray; | 
|---|
| 522 | const CFF2FDSelect		*fdSelect; | 
|---|
| 523 | unsigned int		fdCount; | 
|---|
| 524 |  | 
|---|
| 525 | hb_vector_t<cff2_font_dict_values_t>     fontDicts; | 
|---|
| 526 | hb_vector_t<PRIVDICTVAL>  privateDicts; | 
|---|
| 527 |  | 
|---|
| 528 | unsigned int	      num_glyphs; | 
|---|
| 529 | }; | 
|---|
| 530 |  | 
|---|
| 531 | struct accelerator_t : accelerator_templ_t<cff2_private_dict_opset_t, cff2_private_dict_values_t> | 
|---|
| 532 | { | 
|---|
| 533 | HB_INTERNAL bool get_extents (hb_font_t *font, | 
|---|
| 534 | hb_codepoint_t glyph, | 
|---|
| 535 | hb_glyph_extents_t *extents) const; | 
|---|
| 536 | }; | 
|---|
| 537 |  | 
|---|
| 538 | typedef accelerator_templ_t<cff2_private_dict_opset_subset_t, cff2_private_dict_values_subset_t> accelerator_subset_t; | 
|---|
| 539 |  | 
|---|
| 540 | bool subset (hb_subset_plan_t *plan) const | 
|---|
| 541 | { | 
|---|
| 542 | hb_blob_t *cff2_prime = nullptr; | 
|---|
| 543 |  | 
|---|
| 544 | bool success = true; | 
|---|
| 545 | if (hb_subset_cff2 (plan, &cff2_prime)) { | 
|---|
| 546 | success = success && plan->add_table (HB_OT_TAG_cff2, cff2_prime); | 
|---|
| 547 | hb_blob_t *head_blob = hb_sanitize_context_t().reference_table<head> (plan->source); | 
|---|
| 548 | success = success && head_blob && plan->add_table (HB_OT_TAG_head, head_blob); | 
|---|
| 549 | hb_blob_destroy (head_blob); | 
|---|
| 550 | } else { | 
|---|
| 551 | success = false; | 
|---|
| 552 | } | 
|---|
| 553 | hb_blob_destroy (cff2_prime); | 
|---|
| 554 |  | 
|---|
| 555 | return success; | 
|---|
| 556 | } | 
|---|
| 557 |  | 
|---|
| 558 | public: | 
|---|
| 559 | FixedVersion<HBUINT8>		version;	/* Version of CFF2 table. set to 0x0200u */ | 
|---|
| 560 | NNOffsetTo<TopDict, HBUINT8>	topDict;	/* headerSize = Offset to Top DICT. */ | 
|---|
| 561 | HBUINT16			topDictSize;	/* Top DICT size */ | 
|---|
| 562 |  | 
|---|
| 563 | public: | 
|---|
| 564 | DEFINE_SIZE_STATIC (5); | 
|---|
| 565 | }; | 
|---|
| 566 |  | 
|---|
| 567 | struct cff2_accelerator_t : cff2::accelerator_t {}; | 
|---|
| 568 | } /* namespace OT */ | 
|---|
| 569 |  | 
|---|
| 570 | #endif /* HB_OT_CFF2_TABLE_HH */ | 
|---|
| 571 |  | 
|---|