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