Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/harfbuzz/src/hb-ot-cff1-table.hh @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 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_CFF1_TABLE_HH | |
| 28 #define HB_OT_CFF1_TABLE_HH | |
| 29 | |
| 30 #include "hb-ot-cff-common.hh" | |
| 31 #include "hb-subset-cff1.hh" | |
| 32 #include "hb-draw.hh" | |
| 33 | |
| 34 #define HB_STRING_ARRAY_NAME cff1_std_strings | |
| 35 #define HB_STRING_ARRAY_LIST "hb-ot-cff1-std-str.hh" | |
| 36 #include "hb-string-array.hh" | |
| 37 #undef HB_STRING_ARRAY_LIST | |
| 38 #undef HB_STRING_ARRAY_NAME | |
| 39 | |
| 40 namespace CFF { | |
| 41 | |
| 42 /* | |
| 43 * CFF -- Compact Font Format (CFF) | |
| 44 * https://www.adobe.com/content/dam/acom/en/devnet/font/pdfs/5176.CFF.pdf | |
| 45 */ | |
| 46 #define HB_OT_TAG_cff1 HB_TAG('C','F','F',' ') | |
| 47 | |
| 48 #define CFF_UNDEF_SID CFF_UNDEF_CODE | |
| 49 | |
| 50 enum EncodingID { StandardEncoding = 0, ExpertEncoding = 1 }; | |
| 51 enum CharsetID { ISOAdobeCharset = 0, ExpertCharset = 1, ExpertSubsetCharset = 2 }; | |
| 52 | |
| 53 typedef CFFIndex<HBUINT16> CFF1Index; | |
| 54 template <typename Type> struct CFF1IndexOf : CFFIndexOf<HBUINT16, Type> {}; | |
| 55 | |
| 56 typedef CFFIndex<HBUINT16> CFF1Index; | |
| 57 typedef CFF1Index CFF1CharStrings; | |
| 58 typedef Subrs<HBUINT16> CFF1Subrs; | |
| 59 | |
| 60 struct CFF1FDSelect : FDSelect {}; | |
| 61 | |
| 62 /* Encoding */ | |
| 63 struct Encoding0 { | |
| 64 bool sanitize (hb_sanitize_context_t *c) const | |
| 65 { | |
| 66 TRACE_SANITIZE (this); | |
| 67 return_trace (codes.sanitize (c)); | |
| 68 } | |
| 69 | |
| 70 hb_codepoint_t get_code (hb_codepoint_t glyph) const | |
| 71 { | |
| 72 assert (glyph > 0); | |
| 73 glyph--; | |
| 74 if (glyph < nCodes ()) | |
| 75 { | |
| 76 return (hb_codepoint_t)codes[glyph]; | |
| 77 } | |
| 78 else | |
| 79 return CFF_UNDEF_CODE; | |
| 80 } | |
| 81 | |
| 82 HBUINT8 &nCodes () { return codes.len; } | |
| 83 HBUINT8 nCodes () const { return codes.len; } | |
| 84 | |
| 85 ArrayOf<HBUINT8, HBUINT8> codes; | |
| 86 | |
| 87 DEFINE_SIZE_ARRAY_SIZED (1, codes); | |
| 88 }; | |
| 89 | |
| 90 struct Encoding1_Range { | |
| 91 bool sanitize (hb_sanitize_context_t *c) const | |
| 92 { | |
| 93 TRACE_SANITIZE (this); | |
| 94 return_trace (c->check_struct (this)); | |
| 95 } | |
| 96 | |
| 97 HBUINT8 first; | |
| 98 HBUINT8 nLeft; | |
| 99 | |
| 100 DEFINE_SIZE_STATIC (2); | |
| 101 }; | |
| 102 | |
| 103 struct Encoding1 { | |
| 104 bool sanitize (hb_sanitize_context_t *c) const | |
| 105 { | |
| 106 TRACE_SANITIZE (this); | |
| 107 return_trace (ranges.sanitize (c)); | |
| 108 } | |
| 109 | |
| 110 hb_codepoint_t get_code (hb_codepoint_t glyph) const | |
| 111 { | |
| 112 assert (glyph > 0); | |
| 113 glyph--; | |
| 114 for (unsigned int i = 0; i < nRanges (); i++) | |
| 115 { | |
| 116 if (glyph <= ranges[i].nLeft) | |
| 117 { | |
| 118 hb_codepoint_t code = (hb_codepoint_t) ranges[i].first + glyph; | |
| 119 return (likely (code < 0x100) ? code: CFF_UNDEF_CODE); | |
| 120 } | |
| 121 glyph -= (ranges[i].nLeft + 1); | |
| 122 } | |
| 123 return CFF_UNDEF_CODE; | |
| 124 } | |
| 125 | |
| 126 HBUINT8 &nRanges () { return ranges.len; } | |
| 127 HBUINT8 nRanges () const { return ranges.len; } | |
| 128 | |
| 129 ArrayOf<Encoding1_Range, HBUINT8> ranges; | |
| 130 | |
| 131 DEFINE_SIZE_ARRAY_SIZED (1, ranges); | |
| 132 }; | |
| 133 | |
| 134 struct SuppEncoding { | |
| 135 bool sanitize (hb_sanitize_context_t *c) const | |
| 136 { | |
| 137 TRACE_SANITIZE (this); | |
| 138 return_trace (c->check_struct (this)); | |
| 139 } | |
| 140 | |
| 141 HBUINT8 code; | |
| 142 HBUINT16 glyph; | |
| 143 | |
| 144 DEFINE_SIZE_STATIC (3); | |
| 145 }; | |
| 146 | |
| 147 struct CFF1SuppEncData { | |
| 148 bool sanitize (hb_sanitize_context_t *c) const | |
| 149 { | |
| 150 TRACE_SANITIZE (this); | |
| 151 return_trace (supps.sanitize (c)); | |
| 152 } | |
| 153 | |
| 154 void get_codes (hb_codepoint_t sid, hb_vector_t<hb_codepoint_t> &codes) const | |
| 155 { | |
| 156 for (unsigned int i = 0; i < nSups (); i++) | |
| 157 if (sid == supps[i].glyph) | |
| 158 codes.push (supps[i].code); | |
| 159 } | |
| 160 | |
| 161 HBUINT8 &nSups () { return supps.len; } | |
| 162 HBUINT8 nSups () const { return supps.len; } | |
| 163 | |
| 164 ArrayOf<SuppEncoding, HBUINT8> supps; | |
| 165 | |
| 166 DEFINE_SIZE_ARRAY_SIZED (1, supps); | |
| 167 }; | |
| 168 | |
| 169 struct Encoding | |
| 170 { | |
| 171 /* serialize a fullset Encoding */ | |
| 172 bool serialize (hb_serialize_context_t *c, const Encoding &src) | |
| 173 { | |
| 174 TRACE_SERIALIZE (this); | |
| 175 unsigned int size = src.get_size (); | |
| 176 Encoding *dest = c->allocate_size<Encoding> (size); | |
| 177 if (unlikely (!dest)) return_trace (false); | |
| 178 hb_memcpy (dest, &src, size); | |
| 179 return_trace (true); | |
| 180 } | |
| 181 | |
| 182 /* serialize a subset Encoding */ | |
| 183 bool serialize (hb_serialize_context_t *c, | |
| 184 uint8_t format, | |
| 185 unsigned int enc_count, | |
| 186 const hb_vector_t<code_pair_t>& code_ranges, | |
| 187 const hb_vector_t<code_pair_t>& supp_codes) | |
| 188 { | |
| 189 TRACE_SERIALIZE (this); | |
| 190 Encoding *dest = c->extend_min (this); | |
| 191 if (unlikely (!dest)) return_trace (false); | |
| 192 dest->format = format | ((supp_codes.length > 0) ? 0x80 : 0); | |
| 193 switch (format) { | |
| 194 case 0: | |
| 195 { | |
| 196 Encoding0 *fmt0 = c->allocate_size<Encoding0> (Encoding0::min_size + HBUINT8::static_size * enc_count); | |
| 197 if (unlikely (!fmt0)) return_trace (false); | |
| 198 fmt0->nCodes () = enc_count; | |
| 199 unsigned int glyph = 0; | |
| 200 for (unsigned int i = 0; i < code_ranges.length; i++) | |
| 201 { | |
| 202 hb_codepoint_t code = code_ranges[i].code; | |
| 203 for (int left = (int)code_ranges[i].glyph; left >= 0; left--) | |
| 204 fmt0->codes[glyph++] = code++; | |
| 205 if (unlikely (!((glyph <= 0x100) && (code <= 0x100)))) | |
| 206 return_trace (false); | |
| 207 } | |
| 208 } | |
| 209 break; | |
| 210 | |
| 211 case 1: | |
| 212 { | |
| 213 Encoding1 *fmt1 = c->allocate_size<Encoding1> (Encoding1::min_size + Encoding1_Range::static_size * code_ranges.length); | |
| 214 if (unlikely (!fmt1)) return_trace (false); | |
| 215 fmt1->nRanges () = code_ranges.length; | |
| 216 for (unsigned int i = 0; i < code_ranges.length; i++) | |
| 217 { | |
| 218 if (unlikely (!((code_ranges[i].code <= 0xFF) && (code_ranges[i].glyph <= 0xFF)))) | |
| 219 return_trace (false); | |
| 220 fmt1->ranges[i].first = code_ranges[i].code; | |
| 221 fmt1->ranges[i].nLeft = code_ranges[i].glyph; | |
| 222 } | |
| 223 } | |
| 224 break; | |
| 225 | |
| 226 } | |
| 227 | |
| 228 if (supp_codes.length) | |
| 229 { | |
| 230 CFF1SuppEncData *suppData = c->allocate_size<CFF1SuppEncData> (CFF1SuppEncData::min_size + SuppEncoding::static_size * supp_codes.length); | |
| 231 if (unlikely (!suppData)) return_trace (false); | |
| 232 suppData->nSups () = supp_codes.length; | |
| 233 for (unsigned int i = 0; i < supp_codes.length; i++) | |
| 234 { | |
| 235 suppData->supps[i].code = supp_codes[i].code; | |
| 236 suppData->supps[i].glyph = supp_codes[i].glyph; /* actually SID */ | |
| 237 } | |
| 238 } | |
| 239 | |
| 240 return_trace (true); | |
| 241 } | |
| 242 | |
| 243 unsigned int get_size () const | |
| 244 { | |
| 245 unsigned int size = min_size; | |
| 246 switch (table_format ()) | |
| 247 { | |
| 248 case 0: size += u.format0.get_size (); break; | |
| 249 case 1: size += u.format1.get_size (); break; | |
| 250 } | |
| 251 if (has_supplement ()) | |
| 252 size += suppEncData ().get_size (); | |
| 253 return size; | |
| 254 } | |
| 255 | |
| 256 hb_codepoint_t get_code (hb_codepoint_t glyph) const | |
| 257 { | |
| 258 switch (table_format ()) | |
| 259 { | |
| 260 case 0: return u.format0.get_code (glyph); | |
| 261 case 1: return u.format1.get_code (glyph); | |
| 262 default:return 0; | |
| 263 } | |
| 264 } | |
| 265 | |
| 266 uint8_t table_format () const { return format & 0x7F; } | |
| 267 bool has_supplement () const { return format & 0x80; } | |
| 268 | |
| 269 void get_supplement_codes (hb_codepoint_t sid, hb_vector_t<hb_codepoint_t> &codes) const | |
| 270 { | |
| 271 codes.resize (0); | |
| 272 if (has_supplement ()) | |
| 273 suppEncData().get_codes (sid, codes); | |
| 274 } | |
| 275 | |
| 276 bool sanitize (hb_sanitize_context_t *c) const | |
| 277 { | |
| 278 TRACE_SANITIZE (this); | |
| 279 if (unlikely (!c->check_struct (this))) | |
| 280 return_trace (false); | |
| 281 | |
| 282 switch (table_format ()) | |
| 283 { | |
| 284 case 0: if (unlikely (!u.format0.sanitize (c))) { return_trace (false); } break; | |
| 285 case 1: if (unlikely (!u.format1.sanitize (c))) { return_trace (false); } break; | |
| 286 default:return_trace (false); | |
| 287 } | |
| 288 return_trace (likely (!has_supplement () || suppEncData ().sanitize (c))); | |
| 289 } | |
| 290 | |
| 291 protected: | |
| 292 const CFF1SuppEncData &suppEncData () const | |
| 293 { | |
| 294 switch (table_format ()) | |
| 295 { | |
| 296 case 0: return StructAfter<CFF1SuppEncData> (u.format0.codes[u.format0.nCodes ()-1]); | |
| 297 case 1: return StructAfter<CFF1SuppEncData> (u.format1.ranges[u.format1.nRanges ()-1]); | |
| 298 default:return Null (CFF1SuppEncData); | |
| 299 } | |
| 300 } | |
| 301 | |
| 302 public: | |
| 303 HBUINT8 format; | |
| 304 union { | |
| 305 Encoding0 format0; | |
| 306 Encoding1 format1; | |
| 307 } u; | |
| 308 /* CFF1SuppEncData suppEncData; */ | |
| 309 | |
| 310 DEFINE_SIZE_MIN (1); | |
| 311 }; | |
| 312 | |
| 313 /* Charset */ | |
| 314 struct Charset0 { | |
| 315 bool sanitize (hb_sanitize_context_t *c, unsigned int num_glyphs) const | |
| 316 { | |
| 317 TRACE_SANITIZE (this); | |
| 318 return_trace (c->check_struct (this) && sids[num_glyphs - 1].sanitize (c)); | |
| 319 } | |
| 320 | |
| 321 hb_codepoint_t get_sid (hb_codepoint_t glyph, unsigned num_glyphs) const | |
| 322 { | |
| 323 if (unlikely (glyph >= num_glyphs)) return 0; | |
| 324 if (glyph == 0) | |
| 325 return 0; | |
| 326 else | |
| 327 return sids[glyph - 1]; | |
| 328 } | |
| 329 | |
| 330 void collect_glyph_to_sid_map (hb_map_t *mapping, unsigned int num_glyphs) const | |
| 331 { | |
| 332 for (hb_codepoint_t gid = 1; gid < num_glyphs; gid++) | |
| 333 mapping->set (gid, sids[gid - 1]); | |
| 334 } | |
| 335 | |
| 336 hb_codepoint_t get_glyph (hb_codepoint_t sid, unsigned int num_glyphs) const | |
| 337 { | |
| 338 if (sid == 0) | |
| 339 return 0; | |
| 340 | |
| 341 for (unsigned int glyph = 1; glyph < num_glyphs; glyph++) | |
| 342 { | |
| 343 if (sids[glyph-1] == sid) | |
| 344 return glyph; | |
| 345 } | |
| 346 return 0; | |
| 347 } | |
| 348 | |
| 349 unsigned int get_size (unsigned int num_glyphs) const | |
| 350 { | |
| 351 assert (num_glyphs > 0); | |
| 352 return HBUINT16::static_size * (num_glyphs - 1); | |
| 353 } | |
| 354 | |
| 355 HBUINT16 sids[HB_VAR_ARRAY]; | |
| 356 | |
| 357 DEFINE_SIZE_ARRAY(0, sids); | |
| 358 }; | |
| 359 | |
| 360 template <typename TYPE> | |
| 361 struct Charset_Range { | |
| 362 bool sanitize (hb_sanitize_context_t *c) const | |
| 363 { | |
| 364 TRACE_SANITIZE (this); | |
| 365 return_trace (c->check_struct (this)); | |
| 366 } | |
| 367 | |
| 368 HBUINT16 first; | |
| 369 TYPE nLeft; | |
| 370 | |
| 371 DEFINE_SIZE_STATIC (HBUINT16::static_size + TYPE::static_size); | |
| 372 }; | |
| 373 | |
| 374 template <typename TYPE> | |
| 375 struct Charset1_2 { | |
| 376 bool sanitize (hb_sanitize_context_t *c, unsigned int num_glyphs) const | |
| 377 { | |
| 378 TRACE_SANITIZE (this); | |
| 379 if (unlikely (!c->check_struct (this))) | |
| 380 return_trace (false); | |
| 381 num_glyphs--; | |
| 382 for (unsigned int i = 0; num_glyphs > 0; i++) | |
| 383 { | |
| 384 if (unlikely (!ranges[i].sanitize (c) || (num_glyphs < ranges[i].nLeft + 1))) | |
| 385 return_trace (false); | |
| 386 num_glyphs -= (ranges[i].nLeft + 1); | |
| 387 } | |
| 388 return_trace (true); | |
| 389 } | |
| 390 | |
| 391 hb_codepoint_t get_sid (hb_codepoint_t glyph, unsigned num_glyphs) const | |
| 392 { | |
| 393 if (unlikely (glyph >= num_glyphs)) return 0; | |
| 394 if (glyph == 0) return 0; | |
| 395 glyph--; | |
| 396 for (unsigned int i = 0;; i++) | |
| 397 { | |
| 398 if (glyph <= ranges[i].nLeft) | |
| 399 return (hb_codepoint_t) ranges[i].first + glyph; | |
| 400 glyph -= (ranges[i].nLeft + 1); | |
| 401 } | |
| 402 | |
| 403 return 0; | |
| 404 } | |
| 405 | |
| 406 void collect_glyph_to_sid_map (hb_map_t *mapping, unsigned int num_glyphs) const | |
| 407 { | |
| 408 hb_codepoint_t gid = 1; | |
| 409 if (gid >= num_glyphs) | |
| 410 return; | |
| 411 for (unsigned i = 0;; i++) | |
| 412 { | |
| 413 hb_codepoint_t sid = ranges[i].first; | |
| 414 unsigned count = ranges[i].nLeft + 1; | |
| 415 for (unsigned j = 0; j < count; j++) | |
| 416 mapping->set (gid++, sid++); | |
| 417 | |
| 418 if (gid >= num_glyphs) | |
| 419 break; | |
| 420 } | |
| 421 } | |
| 422 | |
| 423 hb_codepoint_t get_glyph (hb_codepoint_t sid, unsigned int num_glyphs) const | |
| 424 { | |
| 425 if (sid == 0) return 0; | |
| 426 hb_codepoint_t glyph = 1; | |
| 427 for (unsigned int i = 0;; i++) | |
| 428 { | |
| 429 if (glyph >= num_glyphs) | |
| 430 return 0; | |
| 431 if ((ranges[i].first <= sid) && (sid <= ranges[i].first + ranges[i].nLeft)) | |
| 432 return glyph + (sid - ranges[i].first); | |
| 433 glyph += (ranges[i].nLeft + 1); | |
| 434 } | |
| 435 | |
| 436 return 0; | |
| 437 } | |
| 438 | |
| 439 unsigned int get_size (unsigned int num_glyphs) const | |
| 440 { | |
| 441 unsigned int size = HBUINT8::static_size; | |
| 442 int glyph = (int)num_glyphs; | |
| 443 | |
| 444 assert (glyph > 0); | |
| 445 glyph--; | |
| 446 for (unsigned int i = 0; glyph > 0; i++) | |
| 447 { | |
| 448 glyph -= (ranges[i].nLeft + 1); | |
| 449 size += Charset_Range<TYPE>::static_size; | |
| 450 } | |
| 451 | |
| 452 return size; | |
| 453 } | |
| 454 | |
| 455 Charset_Range<TYPE> ranges[HB_VAR_ARRAY]; | |
| 456 | |
| 457 DEFINE_SIZE_ARRAY (0, ranges); | |
| 458 }; | |
| 459 | |
| 460 typedef Charset1_2<HBUINT8> Charset1; | |
| 461 typedef Charset1_2<HBUINT16> Charset2; | |
| 462 typedef Charset_Range<HBUINT8> Charset1_Range; | |
| 463 typedef Charset_Range<HBUINT16> Charset2_Range; | |
| 464 | |
| 465 struct Charset | |
| 466 { | |
| 467 /* serialize a fullset Charset */ | |
| 468 bool serialize (hb_serialize_context_t *c, const Charset &src, unsigned int num_glyphs) | |
| 469 { | |
| 470 TRACE_SERIALIZE (this); | |
| 471 unsigned int size = src.get_size (num_glyphs); | |
| 472 Charset *dest = c->allocate_size<Charset> (size); | |
| 473 if (unlikely (!dest)) return_trace (false); | |
| 474 hb_memcpy (dest, &src, size); | |
| 475 return_trace (true); | |
| 476 } | |
| 477 | |
| 478 /* serialize a subset Charset */ | |
| 479 bool serialize (hb_serialize_context_t *c, | |
| 480 uint8_t format, | |
| 481 unsigned int num_glyphs, | |
| 482 const hb_vector_t<code_pair_t>& sid_ranges) | |
| 483 { | |
| 484 TRACE_SERIALIZE (this); | |
| 485 Charset *dest = c->extend_min (this); | |
| 486 if (unlikely (!dest)) return_trace (false); | |
| 487 dest->format = format; | |
| 488 switch (format) | |
| 489 { | |
| 490 case 0: | |
| 491 { | |
| 492 Charset0 *fmt0 = c->allocate_size<Charset0> (Charset0::min_size + HBUINT16::static_size * (num_glyphs - 1)); | |
| 493 if (unlikely (!fmt0)) return_trace (false); | |
| 494 unsigned int glyph = 0; | |
| 495 for (unsigned int i = 0; i < sid_ranges.length; i++) | |
| 496 { | |
| 497 hb_codepoint_t sid = sid_ranges[i].code; | |
| 498 for (int left = (int)sid_ranges[i].glyph; left >= 0; left--) | |
| 499 fmt0->sids[glyph++] = sid++; | |
| 500 } | |
| 501 } | |
| 502 break; | |
| 503 | |
| 504 case 1: | |
| 505 { | |
| 506 Charset1 *fmt1 = c->allocate_size<Charset1> (Charset1::min_size + Charset1_Range::static_size * sid_ranges.length); | |
| 507 if (unlikely (!fmt1)) return_trace (false); | |
| 508 for (unsigned int i = 0; i < sid_ranges.length; i++) | |
| 509 { | |
| 510 if (unlikely (!(sid_ranges[i].glyph <= 0xFF))) | |
| 511 return_trace (false); | |
| 512 fmt1->ranges[i].first = sid_ranges[i].code; | |
| 513 fmt1->ranges[i].nLeft = sid_ranges[i].glyph; | |
| 514 } | |
| 515 } | |
| 516 break; | |
| 517 | |
| 518 case 2: | |
| 519 { | |
| 520 Charset2 *fmt2 = c->allocate_size<Charset2> (Charset2::min_size + Charset2_Range::static_size * sid_ranges.length); | |
| 521 if (unlikely (!fmt2)) return_trace (false); | |
| 522 for (unsigned int i = 0; i < sid_ranges.length; i++) | |
| 523 { | |
| 524 if (unlikely (!(sid_ranges[i].glyph <= 0xFFFF))) | |
| 525 return_trace (false); | |
| 526 fmt2->ranges[i].first = sid_ranges[i].code; | |
| 527 fmt2->ranges[i].nLeft = sid_ranges[i].glyph; | |
| 528 } | |
| 529 } | |
| 530 break; | |
| 531 | |
| 532 } | |
| 533 return_trace (true); | |
| 534 } | |
| 535 | |
| 536 unsigned int get_size (unsigned int num_glyphs) const | |
| 537 { | |
| 538 switch (format) | |
| 539 { | |
| 540 case 0: return min_size + u.format0.get_size (num_glyphs); | |
| 541 case 1: return min_size + u.format1.get_size (num_glyphs); | |
| 542 case 2: return min_size + u.format2.get_size (num_glyphs); | |
| 543 default:return 0; | |
| 544 } | |
| 545 } | |
| 546 | |
| 547 hb_codepoint_t get_sid (hb_codepoint_t glyph, unsigned int num_glyphs) const | |
| 548 { | |
| 549 switch (format) | |
| 550 { | |
| 551 case 0: return u.format0.get_sid (glyph, num_glyphs); | |
| 552 case 1: return u.format1.get_sid (glyph, num_glyphs); | |
| 553 case 2: return u.format2.get_sid (glyph, num_glyphs); | |
| 554 default:return 0; | |
| 555 } | |
| 556 } | |
| 557 | |
| 558 void collect_glyph_to_sid_map (hb_map_t *mapping, unsigned int num_glyphs) const | |
| 559 { | |
| 560 switch (format) | |
| 561 { | |
| 562 case 0: u.format0.collect_glyph_to_sid_map (mapping, num_glyphs); return; | |
| 563 case 1: u.format1.collect_glyph_to_sid_map (mapping, num_glyphs); return; | |
| 564 case 2: u.format2.collect_glyph_to_sid_map (mapping, num_glyphs); return; | |
| 565 default:return; | |
| 566 } | |
| 567 } | |
| 568 | |
| 569 hb_codepoint_t get_glyph (hb_codepoint_t sid, unsigned int num_glyphs) const | |
| 570 { | |
| 571 switch (format) | |
| 572 { | |
| 573 case 0: return u.format0.get_glyph (sid, num_glyphs); | |
| 574 case 1: return u.format1.get_glyph (sid, num_glyphs); | |
| 575 case 2: return u.format2.get_glyph (sid, num_glyphs); | |
| 576 default:return 0; | |
| 577 } | |
| 578 } | |
| 579 | |
| 580 bool sanitize (hb_sanitize_context_t *c) const | |
| 581 { | |
| 582 TRACE_SANITIZE (this); | |
| 583 if (unlikely (!c->check_struct (this))) | |
| 584 return_trace (false); | |
| 585 | |
| 586 switch (format) | |
| 587 { | |
| 588 case 0: return_trace (u.format0.sanitize (c, c->get_num_glyphs ())); | |
| 589 case 1: return_trace (u.format1.sanitize (c, c->get_num_glyphs ())); | |
| 590 case 2: return_trace (u.format2.sanitize (c, c->get_num_glyphs ())); | |
| 591 default:return_trace (false); | |
| 592 } | |
| 593 } | |
| 594 | |
| 595 HBUINT8 format; | |
| 596 union { | |
| 597 Charset0 format0; | |
| 598 Charset1 format1; | |
| 599 Charset2 format2; | |
| 600 } u; | |
| 601 | |
| 602 DEFINE_SIZE_MIN (1); | |
| 603 }; | |
| 604 | |
| 605 struct CFF1StringIndex : CFF1Index | |
| 606 { | |
| 607 bool serialize (hb_serialize_context_t *c, const CFF1StringIndex &strings, | |
| 608 const hb_inc_bimap_t &sidmap) | |
| 609 { | |
| 610 TRACE_SERIALIZE (this); | |
| 611 if (unlikely ((strings.count == 0) || (sidmap.get_population () == 0))) | |
| 612 { | |
| 613 if (unlikely (!c->extend_min (this->count))) | |
| 614 return_trace (false); | |
| 615 count = 0; | |
| 616 return_trace (true); | |
| 617 } | |
| 618 | |
| 619 byte_str_array_t bytesArray; | |
| 620 if (!bytesArray.resize (sidmap.get_population ())) | |
| 621 return_trace (false); | |
| 622 for (unsigned int i = 0; i < strings.count; i++) | |
| 623 { | |
| 624 hb_codepoint_t j = sidmap[i]; | |
| 625 if (j != HB_MAP_VALUE_INVALID) | |
| 626 bytesArray[j] = strings[i]; | |
| 627 } | |
| 628 | |
| 629 bool result = CFF1Index::serialize (c, bytesArray); | |
| 630 return_trace (result); | |
| 631 } | |
| 632 }; | |
| 633 | |
| 634 struct cff1_top_dict_interp_env_t : num_interp_env_t | |
| 635 { | |
| 636 cff1_top_dict_interp_env_t () | |
| 637 : num_interp_env_t(), prev_offset(0), last_offset(0) {} | |
| 638 cff1_top_dict_interp_env_t (const hb_ubytes_t &bytes) | |
| 639 : num_interp_env_t(bytes), prev_offset(0), last_offset(0) {} | |
| 640 | |
| 641 unsigned int prev_offset; | |
| 642 unsigned int last_offset; | |
| 643 }; | |
| 644 | |
| 645 struct name_dict_values_t | |
| 646 { | |
| 647 enum name_dict_val_index_t | |
| 648 { | |
| 649 version, | |
| 650 notice, | |
| 651 copyright, | |
| 652 fullName, | |
| 653 familyName, | |
| 654 weight, | |
| 655 postscript, | |
| 656 fontName, | |
| 657 baseFontName, | |
| 658 registry, | |
| 659 ordering, | |
| 660 | |
| 661 ValCount | |
| 662 }; | |
| 663 | |
| 664 void init () | |
| 665 { | |
| 666 for (unsigned int i = 0; i < ValCount; i++) | |
| 667 values[i] = CFF_UNDEF_SID; | |
| 668 } | |
| 669 | |
| 670 unsigned int& operator[] (unsigned int i) | |
| 671 { assert (i < ValCount); return values[i]; } | |
| 672 | |
| 673 unsigned int operator[] (unsigned int i) const | |
| 674 { assert (i < ValCount); return values[i]; } | |
| 675 | |
| 676 static enum name_dict_val_index_t name_op_to_index (op_code_t op) | |
| 677 { | |
| 678 switch (op) { | |
| 679 default: // can't happen - just make some compiler happy | |
| 680 case OpCode_version: | |
| 681 return version; | |
| 682 case OpCode_Notice: | |
| 683 return notice; | |
| 684 case OpCode_Copyright: | |
| 685 return copyright; | |
| 686 case OpCode_FullName: | |
| 687 return fullName; | |
| 688 case OpCode_FamilyName: | |
| 689 return familyName; | |
| 690 case OpCode_Weight: | |
| 691 return weight; | |
| 692 case OpCode_PostScript: | |
| 693 return postscript; | |
| 694 case OpCode_FontName: | |
| 695 return fontName; | |
| 696 case OpCode_BaseFontName: | |
| 697 return baseFontName; | |
| 698 } | |
| 699 } | |
| 700 | |
| 701 unsigned int values[ValCount]; | |
| 702 }; | |
| 703 | |
| 704 struct cff1_top_dict_val_t : op_str_t | |
| 705 { | |
| 706 unsigned int last_arg_offset; | |
| 707 }; | |
| 708 | |
| 709 struct cff1_top_dict_values_t : top_dict_values_t<cff1_top_dict_val_t> | |
| 710 { | |
| 711 void init () | |
| 712 { | |
| 713 top_dict_values_t<cff1_top_dict_val_t>::init (); | |
| 714 | |
| 715 nameSIDs.init (); | |
| 716 ros_supplement = 0; | |
| 717 cidCount = 8720; | |
| 718 EncodingOffset = 0; | |
| 719 CharsetOffset = 0; | |
| 720 FDSelectOffset = 0; | |
| 721 privateDictInfo.init (); | |
| 722 } | |
| 723 void fini () { top_dict_values_t<cff1_top_dict_val_t>::fini (); } | |
| 724 | |
| 725 bool is_CID () const | |
| 726 { return nameSIDs[name_dict_values_t::registry] != CFF_UNDEF_SID; } | |
| 727 | |
| 728 name_dict_values_t nameSIDs; | |
| 729 unsigned int ros_supplement_offset; | |
| 730 unsigned int ros_supplement; | |
| 731 unsigned int cidCount; | |
| 732 | |
| 733 unsigned int EncodingOffset; | |
| 734 unsigned int CharsetOffset; | |
| 735 unsigned int FDSelectOffset; | |
| 736 table_info_t privateDictInfo; | |
| 737 }; | |
| 738 | |
| 739 struct cff1_top_dict_opset_t : top_dict_opset_t<cff1_top_dict_val_t> | |
| 740 { | |
| 741 static void process_op (op_code_t op, cff1_top_dict_interp_env_t& env, cff1_top_dict_values_t& dictval) | |
| 742 { | |
| 743 cff1_top_dict_val_t val; | |
| 744 val.last_arg_offset = (env.last_offset-1) - dictval.opStart; /* offset to the last argument */ | |
| 745 | |
| 746 switch (op) { | |
| 747 case OpCode_version: | |
| 748 case OpCode_Notice: | |
| 749 case OpCode_Copyright: | |
| 750 case OpCode_FullName: | |
| 751 case OpCode_FontName: | |
| 752 case OpCode_FamilyName: | |
| 753 case OpCode_Weight: | |
| 754 case OpCode_PostScript: | |
| 755 case OpCode_BaseFontName: | |
| 756 dictval.nameSIDs[name_dict_values_t::name_op_to_index (op)] = env.argStack.pop_uint (); | |
| 757 env.clear_args (); | |
| 758 break; | |
| 759 case OpCode_isFixedPitch: | |
| 760 case OpCode_ItalicAngle: | |
| 761 case OpCode_UnderlinePosition: | |
| 762 case OpCode_UnderlineThickness: | |
| 763 case OpCode_PaintType: | |
| 764 case OpCode_CharstringType: | |
| 765 case OpCode_UniqueID: | |
| 766 case OpCode_StrokeWidth: | |
| 767 case OpCode_SyntheticBase: | |
| 768 case OpCode_CIDFontVersion: | |
| 769 case OpCode_CIDFontRevision: | |
| 770 case OpCode_CIDFontType: | |
| 771 case OpCode_UIDBase: | |
| 772 case OpCode_FontBBox: | |
| 773 case OpCode_XUID: | |
| 774 case OpCode_BaseFontBlend: | |
| 775 env.clear_args (); | |
| 776 break; | |
| 777 | |
| 778 case OpCode_CIDCount: | |
| 779 dictval.cidCount = env.argStack.pop_uint (); | |
| 780 env.clear_args (); | |
| 781 break; | |
| 782 | |
| 783 case OpCode_ROS: | |
| 784 dictval.ros_supplement = env.argStack.pop_uint (); | |
| 785 dictval.nameSIDs[name_dict_values_t::ordering] = env.argStack.pop_uint (); | |
| 786 dictval.nameSIDs[name_dict_values_t::registry] = env.argStack.pop_uint (); | |
| 787 env.clear_args (); | |
| 788 break; | |
| 789 | |
| 790 case OpCode_Encoding: | |
| 791 dictval.EncodingOffset = env.argStack.pop_uint (); | |
| 792 env.clear_args (); | |
| 793 if (unlikely (dictval.EncodingOffset == 0)) return; | |
| 794 break; | |
| 795 | |
| 796 case OpCode_charset: | |
| 797 dictval.CharsetOffset = env.argStack.pop_uint (); | |
| 798 env.clear_args (); | |
| 799 if (unlikely (dictval.CharsetOffset == 0)) return; | |
| 800 break; | |
| 801 | |
| 802 case OpCode_FDSelect: | |
| 803 dictval.FDSelectOffset = env.argStack.pop_uint (); | |
| 804 env.clear_args (); | |
| 805 break; | |
| 806 | |
| 807 case OpCode_Private: | |
| 808 dictval.privateDictInfo.offset = env.argStack.pop_uint (); | |
| 809 dictval.privateDictInfo.size = env.argStack.pop_uint (); | |
| 810 env.clear_args (); | |
| 811 break; | |
| 812 | |
| 813 default: | |
| 814 env.last_offset = env.str_ref.get_offset (); | |
| 815 top_dict_opset_t<cff1_top_dict_val_t>::process_op (op, env, dictval); | |
| 816 /* Record this operand below if stack is empty, otherwise done */ | |
| 817 if (!env.argStack.is_empty ()) return; | |
| 818 break; | |
| 819 } | |
| 820 | |
| 821 if (unlikely (env.in_error ())) return; | |
| 822 | |
| 823 dictval.add_op (op, env.str_ref, val); | |
| 824 } | |
| 825 }; | |
| 826 | |
| 827 struct cff1_font_dict_values_t : dict_values_t<op_str_t> | |
| 828 { | |
| 829 void init () | |
| 830 { | |
| 831 dict_values_t<op_str_t>::init (); | |
| 832 privateDictInfo.init (); | |
| 833 fontName = CFF_UNDEF_SID; | |
| 834 } | |
| 835 void fini () { dict_values_t<op_str_t>::fini (); } | |
| 836 | |
| 837 table_info_t privateDictInfo; | |
| 838 unsigned int fontName; | |
| 839 }; | |
| 840 | |
| 841 struct cff1_font_dict_opset_t : dict_opset_t | |
| 842 { | |
| 843 static void process_op (op_code_t op, num_interp_env_t& env, cff1_font_dict_values_t& dictval) | |
| 844 { | |
| 845 switch (op) { | |
| 846 case OpCode_FontName: | |
| 847 dictval.fontName = env.argStack.pop_uint (); | |
| 848 env.clear_args (); | |
| 849 break; | |
| 850 case OpCode_FontMatrix: | |
| 851 case OpCode_PaintType: | |
| 852 env.clear_args (); | |
| 853 break; | |
| 854 case OpCode_Private: | |
| 855 dictval.privateDictInfo.offset = env.argStack.pop_uint (); | |
| 856 dictval.privateDictInfo.size = env.argStack.pop_uint (); | |
| 857 env.clear_args (); | |
| 858 break; | |
| 859 | |
| 860 default: | |
| 861 dict_opset_t::process_op (op, env); | |
| 862 if (!env.argStack.is_empty ()) return; | |
| 863 break; | |
| 864 } | |
| 865 | |
| 866 if (unlikely (env.in_error ())) return; | |
| 867 | |
| 868 dictval.add_op (op, env.str_ref); | |
| 869 } | |
| 870 }; | |
| 871 | |
| 872 template <typename VAL> | |
| 873 struct cff1_private_dict_values_base_t : dict_values_t<VAL> | |
| 874 { | |
| 875 void init () | |
| 876 { | |
| 877 dict_values_t<VAL>::init (); | |
| 878 subrsOffset = 0; | |
| 879 localSubrs = &Null (CFF1Subrs); | |
| 880 } | |
| 881 void fini () { dict_values_t<VAL>::fini (); } | |
| 882 | |
| 883 unsigned int subrsOffset; | |
| 884 const CFF1Subrs *localSubrs; | |
| 885 }; | |
| 886 | |
| 887 typedef cff1_private_dict_values_base_t<op_str_t> cff1_private_dict_values_subset_t; | |
| 888 typedef cff1_private_dict_values_base_t<num_dict_val_t> cff1_private_dict_values_t; | |
| 889 | |
| 890 struct cff1_private_dict_opset_t : dict_opset_t | |
| 891 { | |
| 892 static void process_op (op_code_t op, num_interp_env_t& env, cff1_private_dict_values_t& dictval) | |
| 893 { | |
| 894 num_dict_val_t val; | |
| 895 val.init (); | |
| 896 | |
| 897 switch (op) { | |
| 898 case OpCode_BlueValues: | |
| 899 case OpCode_OtherBlues: | |
| 900 case OpCode_FamilyBlues: | |
| 901 case OpCode_FamilyOtherBlues: | |
| 902 case OpCode_StemSnapH: | |
| 903 case OpCode_StemSnapV: | |
| 904 env.clear_args (); | |
| 905 break; | |
| 906 case OpCode_StdHW: | |
| 907 case OpCode_StdVW: | |
| 908 case OpCode_BlueScale: | |
| 909 case OpCode_BlueShift: | |
| 910 case OpCode_BlueFuzz: | |
| 911 case OpCode_ForceBold: | |
| 912 case OpCode_LanguageGroup: | |
| 913 case OpCode_ExpansionFactor: | |
| 914 case OpCode_initialRandomSeed: | |
| 915 case OpCode_defaultWidthX: | |
| 916 case OpCode_nominalWidthX: | |
| 917 val.single_val = env.argStack.pop_num (); | |
| 918 env.clear_args (); | |
| 919 break; | |
| 920 case OpCode_Subrs: | |
| 921 dictval.subrsOffset = env.argStack.pop_uint (); | |
| 922 env.clear_args (); | |
| 923 break; | |
| 924 | |
| 925 default: | |
| 926 dict_opset_t::process_op (op, env); | |
| 927 if (!env.argStack.is_empty ()) return; | |
| 928 break; | |
| 929 } | |
| 930 | |
| 931 if (unlikely (env.in_error ())) return; | |
| 932 | |
| 933 dictval.add_op (op, env.str_ref, val); | |
| 934 } | |
| 935 }; | |
| 936 | |
| 937 struct cff1_private_dict_opset_subset : dict_opset_t | |
| 938 { | |
| 939 static void process_op (op_code_t op, num_interp_env_t& env, cff1_private_dict_values_subset_t& dictval) | |
| 940 { | |
| 941 switch (op) { | |
| 942 case OpCode_BlueValues: | |
| 943 case OpCode_OtherBlues: | |
| 944 case OpCode_FamilyBlues: | |
| 945 case OpCode_FamilyOtherBlues: | |
| 946 case OpCode_StemSnapH: | |
| 947 case OpCode_StemSnapV: | |
| 948 case OpCode_StdHW: | |
| 949 case OpCode_StdVW: | |
| 950 case OpCode_BlueScale: | |
| 951 case OpCode_BlueShift: | |
| 952 case OpCode_BlueFuzz: | |
| 953 case OpCode_ForceBold: | |
| 954 case OpCode_LanguageGroup: | |
| 955 case OpCode_ExpansionFactor: | |
| 956 case OpCode_initialRandomSeed: | |
| 957 case OpCode_defaultWidthX: | |
| 958 case OpCode_nominalWidthX: | |
| 959 env.clear_args (); | |
| 960 break; | |
| 961 | |
| 962 case OpCode_Subrs: | |
| 963 dictval.subrsOffset = env.argStack.pop_uint (); | |
| 964 env.clear_args (); | |
| 965 break; | |
| 966 | |
| 967 default: | |
| 968 dict_opset_t::process_op (op, env); | |
| 969 if (!env.argStack.is_empty ()) return; | |
| 970 break; | |
| 971 } | |
| 972 | |
| 973 if (unlikely (env.in_error ())) return; | |
| 974 | |
| 975 dictval.add_op (op, env.str_ref); | |
| 976 } | |
| 977 }; | |
| 978 | |
| 979 typedef dict_interpreter_t<cff1_top_dict_opset_t, cff1_top_dict_values_t, cff1_top_dict_interp_env_t> cff1_top_dict_interpreter_t; | |
| 980 typedef dict_interpreter_t<cff1_font_dict_opset_t, cff1_font_dict_values_t> cff1_font_dict_interpreter_t; | |
| 981 | |
| 982 typedef CFF1Index CFF1NameIndex; | |
| 983 typedef CFF1IndexOf<TopDict> CFF1TopDictIndex; | |
| 984 | |
| 985 struct cff1_font_dict_values_mod_t | |
| 986 { | |
| 987 cff1_font_dict_values_mod_t() { init (); } | |
| 988 | |
| 989 void init () { init ( &Null (cff1_font_dict_values_t), CFF_UNDEF_SID ); } | |
| 990 | |
| 991 void init (const cff1_font_dict_values_t *base_, | |
| 992 unsigned int fontName_) | |
| 993 { | |
| 994 base = base_; | |
| 995 fontName = fontName_; | |
| 996 privateDictInfo.init (); | |
| 997 } | |
| 998 | |
| 999 unsigned get_count () const { return base->get_count (); } | |
| 1000 | |
| 1001 const op_str_t &operator [] (unsigned int i) const { return (*base)[i]; } | |
| 1002 | |
| 1003 const cff1_font_dict_values_t *base; | |
| 1004 table_info_t privateDictInfo; | |
| 1005 unsigned int fontName; | |
| 1006 }; | |
| 1007 | |
| 1008 struct CFF1FDArray : FDArray<HBUINT16> | |
| 1009 { | |
| 1010 /* FDArray::serialize() requires this partial specialization to compile */ | |
| 1011 template <typename ITER, typename OP_SERIALIZER> | |
| 1012 bool serialize (hb_serialize_context_t *c, ITER it, OP_SERIALIZER& opszr) | |
| 1013 { return FDArray<HBUINT16>::serialize<cff1_font_dict_values_mod_t, cff1_font_dict_values_mod_t> (c, it, opszr); } | |
| 1014 }; | |
| 1015 | |
| 1016 } /* namespace CFF */ | |
| 1017 | |
| 1018 namespace OT { | |
| 1019 | |
| 1020 using namespace CFF; | |
| 1021 | |
| 1022 struct cff1 | |
| 1023 { | |
| 1024 static constexpr hb_tag_t tableTag = HB_OT_TAG_cff1; | |
| 1025 | |
| 1026 bool sanitize (hb_sanitize_context_t *c) const | |
| 1027 { | |
| 1028 TRACE_SANITIZE (this); | |
| 1029 return_trace (c->check_struct (this) && | |
| 1030 likely (version.major == 1)); | |
| 1031 } | |
| 1032 | |
| 1033 template <typename PRIVOPSET, typename PRIVDICTVAL> | |
| 1034 struct accelerator_templ_t | |
| 1035 { | |
| 1036 void init (hb_face_t *face) | |
| 1037 { | |
| 1038 topDict.init (); | |
| 1039 fontDicts.init (); | |
| 1040 privateDicts.init (); | |
| 1041 | |
| 1042 this->blob = sc.reference_table<cff1> (face); | |
| 1043 | |
| 1044 /* setup for run-time santization */ | |
| 1045 sc.init (this->blob); | |
| 1046 sc.start_processing (); | |
| 1047 | |
| 1048 const OT::cff1 *cff = this->blob->template as<OT::cff1> (); | |
| 1049 | |
| 1050 if (cff == &Null (OT::cff1)) | |
| 1051 { fini (); return; } | |
| 1052 | |
| 1053 nameIndex = &cff->nameIndex (cff); | |
| 1054 if ((nameIndex == &Null (CFF1NameIndex)) || !nameIndex->sanitize (&sc)) | |
| 1055 { fini (); return; } | |
| 1056 | |
| 1057 topDictIndex = &StructAtOffset<CFF1TopDictIndex> (nameIndex, nameIndex->get_size ()); | |
| 1058 if ((topDictIndex == &Null (CFF1TopDictIndex)) || !topDictIndex->sanitize (&sc) || (topDictIndex->count == 0)) | |
| 1059 { fini (); return; } | |
| 1060 | |
| 1061 { /* parse top dict */ | |
| 1062 const hb_ubytes_t topDictStr = (*topDictIndex)[0]; | |
| 1063 if (unlikely (!topDictStr.sanitize (&sc))) { fini (); return; } | |
| 1064 cff1_top_dict_interp_env_t env (topDictStr); | |
| 1065 cff1_top_dict_interpreter_t top_interp (env); | |
| 1066 if (unlikely (!top_interp.interpret (topDict))) { fini (); return; } | |
| 1067 } | |
| 1068 | |
| 1069 if (is_predef_charset ()) | |
| 1070 charset = &Null (Charset); | |
| 1071 else | |
| 1072 { | |
| 1073 charset = &StructAtOffsetOrNull<Charset> (cff, topDict.CharsetOffset); | |
| 1074 if (unlikely ((charset == &Null (Charset)) || !charset->sanitize (&sc))) { fini (); return; } | |
| 1075 } | |
| 1076 | |
| 1077 fdCount = 1; | |
| 1078 if (is_CID ()) | |
| 1079 { | |
| 1080 fdArray = &StructAtOffsetOrNull<CFF1FDArray> (cff, topDict.FDArrayOffset); | |
| 1081 fdSelect = &StructAtOffsetOrNull<CFF1FDSelect> (cff, topDict.FDSelectOffset); | |
| 1082 if (unlikely ((fdArray == &Null (CFF1FDArray)) || !fdArray->sanitize (&sc) || | |
| 1083 (fdSelect == &Null (CFF1FDSelect)) || !fdSelect->sanitize (&sc, fdArray->count))) | |
| 1084 { fini (); return; } | |
| 1085 | |
| 1086 fdCount = fdArray->count; | |
| 1087 } | |
| 1088 else | |
| 1089 { | |
| 1090 fdArray = &Null (CFF1FDArray); | |
| 1091 fdSelect = &Null (CFF1FDSelect); | |
| 1092 } | |
| 1093 | |
| 1094 encoding = &Null (Encoding); | |
| 1095 if (is_CID ()) | |
| 1096 { | |
| 1097 if (unlikely (charset == &Null (Charset))) { fini (); return; } | |
| 1098 } | |
| 1099 else | |
| 1100 { | |
| 1101 if (!is_predef_encoding ()) | |
| 1102 { | |
| 1103 encoding = &StructAtOffsetOrNull<Encoding> (cff, topDict.EncodingOffset); | |
| 1104 if (unlikely ((encoding == &Null (Encoding)) || !encoding->sanitize (&sc))) { fini (); return; } | |
| 1105 } | |
| 1106 } | |
| 1107 | |
| 1108 stringIndex = &StructAtOffset<CFF1StringIndex> (topDictIndex, topDictIndex->get_size ()); | |
| 1109 if ((stringIndex == &Null (CFF1StringIndex)) || !stringIndex->sanitize (&sc)) | |
| 1110 { fini (); return; } | |
| 1111 | |
| 1112 globalSubrs = &StructAtOffset<CFF1Subrs> (stringIndex, stringIndex->get_size ()); | |
| 1113 if ((globalSubrs != &Null (CFF1Subrs)) && !globalSubrs->sanitize (&sc)) | |
| 1114 { fini (); return; } | |
| 1115 | |
| 1116 charStrings = &StructAtOffsetOrNull<CFF1CharStrings> (cff, topDict.charStringsOffset); | |
| 1117 | |
| 1118 if ((charStrings == &Null (CFF1CharStrings)) || unlikely (!charStrings->sanitize (&sc))) | |
| 1119 { fini (); return; } | |
| 1120 | |
| 1121 num_glyphs = charStrings->count; | |
| 1122 if (num_glyphs != sc.get_num_glyphs ()) | |
| 1123 { fini (); return; } | |
| 1124 | |
| 1125 if (unlikely (!privateDicts.resize (fdCount))) | |
| 1126 { fini (); return; } | |
| 1127 for (unsigned int i = 0; i < fdCount; i++) | |
| 1128 privateDicts[i].init (); | |
| 1129 | |
| 1130 // parse CID font dicts and gather private dicts | |
| 1131 if (is_CID ()) | |
| 1132 { | |
| 1133 for (unsigned int i = 0; i < fdCount; i++) | |
| 1134 { | |
| 1135 hb_ubytes_t fontDictStr = (*fdArray)[i]; | |
| 1136 if (unlikely (!fontDictStr.sanitize (&sc))) { fini (); return; } | |
| 1137 cff1_font_dict_values_t *font; | |
| 1138 cff1_top_dict_interp_env_t env (fontDictStr); | |
| 1139 cff1_font_dict_interpreter_t font_interp (env); | |
| 1140 font = fontDicts.push (); | |
| 1141 if (unlikely (fontDicts.in_error ())) { fini (); return; } | |
| 1142 | |
| 1143 font->init (); | |
| 1144 if (unlikely (!font_interp.interpret (*font))) { fini (); return; } | |
| 1145 PRIVDICTVAL *priv = &privateDicts[i]; | |
| 1146 const hb_ubytes_t privDictStr = StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size); | |
| 1147 if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; } | |
| 1148 num_interp_env_t env2 (privDictStr); | |
| 1149 dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> priv_interp (env2); | |
| 1150 priv->init (); | |
| 1151 if (unlikely (!priv_interp.interpret (*priv))) { fini (); return; } | |
| 1152 | |
| 1153 priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (&privDictStr, priv->subrsOffset); | |
| 1154 if (priv->localSubrs != &Null (CFF1Subrs) && | |
| 1155 unlikely (!priv->localSubrs->sanitize (&sc))) | |
| 1156 { fini (); return; } | |
| 1157 } | |
| 1158 } | |
| 1159 else /* non-CID */ | |
| 1160 { | |
| 1161 cff1_top_dict_values_t *font = &topDict; | |
| 1162 PRIVDICTVAL *priv = &privateDicts[0]; | |
| 1163 | |
| 1164 const hb_ubytes_t privDictStr = StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size); | |
| 1165 if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; } | |
| 1166 num_interp_env_t env (privDictStr); | |
| 1167 dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> priv_interp (env); | |
| 1168 priv->init (); | |
| 1169 if (unlikely (!priv_interp.interpret (*priv))) { fini (); return; } | |
| 1170 | |
| 1171 priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (&privDictStr, priv->subrsOffset); | |
| 1172 if (priv->localSubrs != &Null (CFF1Subrs) && | |
| 1173 unlikely (!priv->localSubrs->sanitize (&sc))) | |
| 1174 { fini (); return; } | |
| 1175 } | |
| 1176 } | |
| 1177 | |
| 1178 void fini () | |
| 1179 { | |
| 1180 sc.end_processing (); | |
| 1181 topDict.fini (); | |
| 1182 fontDicts.fini (); | |
| 1183 privateDicts.fini (); | |
| 1184 hb_blob_destroy (blob); | |
| 1185 blob = nullptr; | |
| 1186 } | |
| 1187 | |
| 1188 bool is_valid () const { return blob; } | |
| 1189 bool is_CID () const { return topDict.is_CID (); } | |
| 1190 | |
| 1191 bool is_predef_charset () const { return topDict.CharsetOffset <= ExpertSubsetCharset; } | |
| 1192 | |
| 1193 unsigned int std_code_to_glyph (hb_codepoint_t code) const | |
| 1194 { | |
| 1195 hb_codepoint_t sid = lookup_standard_encoding_for_sid (code); | |
| 1196 if (unlikely (sid == CFF_UNDEF_SID)) | |
| 1197 return 0; | |
| 1198 | |
| 1199 if (charset != &Null (Charset)) | |
| 1200 return charset->get_glyph (sid, num_glyphs); | |
| 1201 else if ((topDict.CharsetOffset == ISOAdobeCharset) | |
| 1202 && (code <= 228 /*zcaron*/)) return sid; | |
| 1203 return 0; | |
| 1204 } | |
| 1205 | |
| 1206 bool is_predef_encoding () const { return topDict.EncodingOffset <= ExpertEncoding; } | |
| 1207 | |
| 1208 hb_codepoint_t glyph_to_code (hb_codepoint_t glyph) const | |
| 1209 { | |
| 1210 if (encoding != &Null (Encoding)) | |
| 1211 return encoding->get_code (glyph); | |
| 1212 else | |
| 1213 { | |
| 1214 hb_codepoint_t sid = glyph_to_sid (glyph); | |
| 1215 if (sid == 0) return 0; | |
| 1216 hb_codepoint_t code = 0; | |
| 1217 switch (topDict.EncodingOffset) | |
| 1218 { | |
| 1219 case StandardEncoding: | |
| 1220 code = lookup_standard_encoding_for_code (sid); | |
| 1221 break; | |
| 1222 case ExpertEncoding: | |
| 1223 code = lookup_expert_encoding_for_code (sid); | |
| 1224 break; | |
| 1225 default: | |
| 1226 break; | |
| 1227 } | |
| 1228 return code; | |
| 1229 } | |
| 1230 } | |
| 1231 | |
| 1232 hb_map_t *create_glyph_to_sid_map () const | |
| 1233 { | |
| 1234 if (charset != &Null (Charset)) | |
| 1235 { | |
| 1236 hb_map_t *mapping = hb_map_create (); | |
| 1237 mapping->set (0, 0); | |
| 1238 charset->collect_glyph_to_sid_map (mapping, num_glyphs); | |
| 1239 return mapping; | |
| 1240 } | |
| 1241 else | |
| 1242 return nullptr; | |
| 1243 } | |
| 1244 | |
| 1245 hb_codepoint_t glyph_to_sid (hb_codepoint_t glyph) const | |
| 1246 { | |
| 1247 if (charset != &Null (Charset)) | |
| 1248 return charset->get_sid (glyph, num_glyphs); | |
| 1249 else | |
| 1250 { | |
| 1251 hb_codepoint_t sid = 0; | |
| 1252 switch (topDict.CharsetOffset) | |
| 1253 { | |
| 1254 case ISOAdobeCharset: | |
| 1255 if (glyph <= 228 /*zcaron*/) sid = glyph; | |
| 1256 break; | |
| 1257 case ExpertCharset: | |
| 1258 sid = lookup_expert_charset_for_sid (glyph); | |
| 1259 break; | |
| 1260 case ExpertSubsetCharset: | |
| 1261 sid = lookup_expert_subset_charset_for_sid (glyph); | |
| 1262 break; | |
| 1263 default: | |
| 1264 break; | |
| 1265 } | |
| 1266 return sid; | |
| 1267 } | |
| 1268 } | |
| 1269 | |
| 1270 hb_codepoint_t sid_to_glyph (hb_codepoint_t sid) const | |
| 1271 { | |
| 1272 if (charset != &Null (Charset)) | |
| 1273 return charset->get_glyph (sid, num_glyphs); | |
| 1274 else | |
| 1275 { | |
| 1276 hb_codepoint_t glyph = 0; | |
| 1277 switch (topDict.CharsetOffset) | |
| 1278 { | |
| 1279 case ISOAdobeCharset: | |
| 1280 if (sid <= 228 /*zcaron*/) glyph = sid; | |
| 1281 break; | |
| 1282 case ExpertCharset: | |
| 1283 glyph = lookup_expert_charset_for_glyph (sid); | |
| 1284 break; | |
| 1285 case ExpertSubsetCharset: | |
| 1286 glyph = lookup_expert_subset_charset_for_glyph (sid); | |
| 1287 break; | |
| 1288 default: | |
| 1289 break; | |
| 1290 } | |
| 1291 return glyph; | |
| 1292 } | |
| 1293 } | |
| 1294 | |
| 1295 protected: | |
| 1296 hb_sanitize_context_t sc; | |
| 1297 | |
| 1298 public: | |
| 1299 hb_blob_t *blob = nullptr; | |
| 1300 const Encoding *encoding = nullptr; | |
| 1301 const Charset *charset = nullptr; | |
| 1302 const CFF1NameIndex *nameIndex = nullptr; | |
| 1303 const CFF1TopDictIndex *topDictIndex = nullptr; | |
| 1304 const CFF1StringIndex *stringIndex = nullptr; | |
| 1305 const CFF1Subrs *globalSubrs = nullptr; | |
| 1306 const CFF1CharStrings *charStrings = nullptr; | |
| 1307 const CFF1FDArray *fdArray = nullptr; | |
| 1308 const CFF1FDSelect *fdSelect = nullptr; | |
| 1309 unsigned int fdCount = 0; | |
| 1310 | |
| 1311 cff1_top_dict_values_t topDict; | |
| 1312 hb_vector_t<cff1_font_dict_values_t> | |
| 1313 fontDicts; | |
| 1314 hb_vector_t<PRIVDICTVAL> privateDicts; | |
| 1315 | |
| 1316 unsigned int num_glyphs = 0; | |
| 1317 }; | |
| 1318 | |
| 1319 struct accelerator_t : accelerator_templ_t<cff1_private_dict_opset_t, cff1_private_dict_values_t> | |
| 1320 { | |
| 1321 accelerator_t (hb_face_t *face) | |
| 1322 { | |
| 1323 SUPER::init (face); | |
| 1324 | |
| 1325 glyph_names.set_relaxed (nullptr); | |
| 1326 | |
| 1327 if (!is_valid ()) return; | |
| 1328 if (is_CID ()) return; | |
| 1329 | |
| 1330 } | |
| 1331 ~accelerator_t () | |
| 1332 { | |
| 1333 hb_sorted_vector_t<gname_t> *names = glyph_names.get_relaxed (); | |
| 1334 if (names) | |
| 1335 { | |
| 1336 names->fini (); | |
| 1337 hb_free (names); | |
| 1338 } | |
| 1339 | |
| 1340 SUPER::fini (); | |
| 1341 } | |
| 1342 | |
| 1343 bool get_glyph_name (hb_codepoint_t glyph, | |
| 1344 char *buf, unsigned int buf_len) const | |
| 1345 { | |
| 1346 if (unlikely (!is_valid ())) return false; | |
| 1347 if (is_CID()) return false; | |
| 1348 if (unlikely (!buf_len)) return true; | |
| 1349 hb_codepoint_t sid = glyph_to_sid (glyph); | |
| 1350 const char *str; | |
| 1351 size_t str_len; | |
| 1352 if (sid < cff1_std_strings_length) | |
| 1353 { | |
| 1354 hb_bytes_t byte_str = cff1_std_strings (sid); | |
| 1355 str = byte_str.arrayZ; | |
| 1356 str_len = byte_str.length; | |
| 1357 } | |
| 1358 else | |
| 1359 { | |
| 1360 hb_ubytes_t ubyte_str = (*stringIndex)[sid - cff1_std_strings_length]; | |
| 1361 str = (const char *)ubyte_str.arrayZ; | |
| 1362 str_len = ubyte_str.length; | |
| 1363 } | |
| 1364 if (!str_len) return false; | |
| 1365 unsigned int len = hb_min (buf_len - 1, str_len); | |
| 1366 strncpy (buf, (const char*)str, len); | |
| 1367 buf[len] = '\0'; | |
| 1368 return true; | |
| 1369 } | |
| 1370 | |
| 1371 bool get_glyph_from_name (const char *name, int len, | |
| 1372 hb_codepoint_t *glyph) const | |
| 1373 { | |
| 1374 if (unlikely (!is_valid ())) return false; | |
| 1375 if (is_CID()) return false; | |
| 1376 if (len < 0) len = strlen (name); | |
| 1377 if (unlikely (!len)) return false; | |
| 1378 | |
| 1379 retry: | |
| 1380 hb_sorted_vector_t<gname_t> *names = glyph_names.get_acquire (); | |
| 1381 if (unlikely (!names)) | |
| 1382 { | |
| 1383 names = (hb_sorted_vector_t<gname_t> *) hb_calloc (sizeof (hb_sorted_vector_t<gname_t>), 1); | |
| 1384 if (likely (names)) | |
| 1385 { | |
| 1386 names->init (); | |
| 1387 /* TODO */ | |
| 1388 | |
| 1389 /* fill glyph names */ | |
| 1390 for (hb_codepoint_t gid = 0; gid < num_glyphs; gid++) | |
| 1391 { | |
| 1392 hb_codepoint_t sid = glyph_to_sid (gid); | |
| 1393 gname_t gname; | |
| 1394 gname.sid = sid; | |
| 1395 if (sid < cff1_std_strings_length) | |
| 1396 gname.name = cff1_std_strings (sid); | |
| 1397 else | |
| 1398 { | |
| 1399 hb_ubytes_t ustr = (*stringIndex)[sid - cff1_std_strings_length]; | |
| 1400 gname.name = hb_bytes_t ((const char*) ustr.arrayZ, ustr.length); | |
| 1401 } | |
| 1402 if (unlikely (!gname.name.arrayZ)) | |
| 1403 gname.name = hb_bytes_t ("", 0); /* To avoid nullptr. */ | |
| 1404 names->push (gname); | |
| 1405 } | |
| 1406 names->qsort (); | |
| 1407 } | |
| 1408 if (unlikely (!glyph_names.cmpexch (nullptr, names))) | |
| 1409 { | |
| 1410 if (names) | |
| 1411 { | |
| 1412 names->fini (); | |
| 1413 hb_free (names); | |
| 1414 } | |
| 1415 goto retry; | |
| 1416 } | |
| 1417 } | |
| 1418 | |
| 1419 gname_t key = { hb_bytes_t (name, len), 0 }; | |
| 1420 const gname_t *gname = names ? names->bsearch (key) : nullptr; | |
| 1421 if (!gname) return false; | |
| 1422 hb_codepoint_t gid = sid_to_glyph (gname->sid); | |
| 1423 if (!gid && gname->sid) return false; | |
| 1424 *glyph = gid; | |
| 1425 return true; | |
| 1426 } | |
| 1427 | |
| 1428 HB_INTERNAL bool get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const; | |
| 1429 HB_INTERNAL bool get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const; | |
| 1430 HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const; | |
| 1431 | |
| 1432 private: | |
| 1433 struct gname_t | |
| 1434 { | |
| 1435 hb_bytes_t name; | |
| 1436 uint16_t sid; | |
| 1437 | |
| 1438 static int cmp (const void *a_, const void *b_) | |
| 1439 { | |
| 1440 const gname_t *a = (const gname_t *)a_; | |
| 1441 const gname_t *b = (const gname_t *)b_; | |
| 1442 unsigned minlen = hb_min (a->name.length, b->name.length); | |
| 1443 int ret = strncmp (a->name.arrayZ, b->name.arrayZ, minlen); | |
| 1444 if (ret) return ret; | |
| 1445 return a->name.length - b->name.length; | |
| 1446 } | |
| 1447 | |
| 1448 int cmp (const gname_t &a) const { return cmp (&a, this); } | |
| 1449 }; | |
| 1450 | |
| 1451 mutable hb_atomic_ptr_t<hb_sorted_vector_t<gname_t>> glyph_names; | |
| 1452 | |
| 1453 typedef accelerator_templ_t<cff1_private_dict_opset_t, cff1_private_dict_values_t> SUPER; | |
| 1454 }; | |
| 1455 | |
| 1456 struct accelerator_subset_t : accelerator_templ_t<cff1_private_dict_opset_subset, cff1_private_dict_values_subset_t> {}; | |
| 1457 | |
| 1458 bool subset (hb_subset_context_t *c) const { return hb_subset_cff1 (c); } | |
| 1459 | |
| 1460 protected: | |
| 1461 HB_INTERNAL static hb_codepoint_t lookup_standard_encoding_for_code (hb_codepoint_t sid); | |
| 1462 HB_INTERNAL static hb_codepoint_t lookup_expert_encoding_for_code (hb_codepoint_t sid); | |
| 1463 HB_INTERNAL static hb_codepoint_t lookup_expert_charset_for_sid (hb_codepoint_t glyph); | |
| 1464 HB_INTERNAL static hb_codepoint_t lookup_expert_subset_charset_for_sid (hb_codepoint_t glyph); | |
| 1465 HB_INTERNAL static hb_codepoint_t lookup_expert_charset_for_glyph (hb_codepoint_t sid); | |
| 1466 HB_INTERNAL static hb_codepoint_t lookup_expert_subset_charset_for_glyph (hb_codepoint_t sid); | |
| 1467 HB_INTERNAL static hb_codepoint_t lookup_standard_encoding_for_sid (hb_codepoint_t code); | |
| 1468 | |
| 1469 public: | |
| 1470 FixedVersion<HBUINT8> version; /* Version of CFF table. set to 0x0100u */ | |
| 1471 NNOffsetTo<CFF1NameIndex, HBUINT8> nameIndex; /* headerSize = Offset to Name INDEX. */ | |
| 1472 HBUINT8 offSize; /* offset size (unused?) */ | |
| 1473 | |
| 1474 public: | |
| 1475 DEFINE_SIZE_STATIC (4); | |
| 1476 }; | |
| 1477 | |
| 1478 struct cff1_accelerator_t : cff1::accelerator_t { | |
| 1479 cff1_accelerator_t (hb_face_t *face) : cff1::accelerator_t (face) {} | |
| 1480 }; | |
| 1481 | |
| 1482 } /* namespace OT */ | |
| 1483 | |
| 1484 #endif /* HB_OT_CFF1_TABLE_HH */ |
