< prev index next >

src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-cmap-table.hh

Print this page




  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  * Google Author(s): Behdad Esfahbod
  25  */
  26 
  27 #ifndef HB_OT_CMAP_TABLE_HH
  28 #define HB_OT_CMAP_TABLE_HH
  29 
  30 #include "hb-open-type-private.hh"
  31 #include "hb-set-private.hh"
  32 #include "hb-subset-plan.hh"
  33 
  34 /*
  35  * cmap -- Character to Glyph Index Mapping
  36  * https://docs.microsoft.com/en-us/typography/opentype/spec/cmap
  37  */
  38 #define HB_OT_TAG_cmap HB_TAG('c','m','a','p')
  39 
  40 
  41 namespace OT {
  42 
  43 
  44 struct CmapSubtableFormat0
  45 {
  46   inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
  47   {
  48     hb_codepoint_t gid = codepoint < 256 ? glyphIdArray[codepoint] : 0;
  49     if (!gid)
  50       return false;
  51     *glyph = gid;
  52     return true;
  53   }






  54 
  55   inline bool sanitize (hb_sanitize_context_t *c) const
  56   {
  57     TRACE_SANITIZE (this);
  58     return_trace (c->check_struct (this));
  59   }
  60 
  61   protected:
  62   HBUINT16      format;         /* Format number is set to 0. */
  63   HBUINT16      length;         /* Byte length of this subtable. */
  64   HBUINT16      language;       /* Ignore. */
  65   HBUINT8       glyphIdArray[256];/* An array that maps character
  66                                  * code to glyph index values. */
  67   public:
  68   DEFINE_SIZE_STATIC (6 + 256);
  69 };
  70 
  71 struct CmapSubtableFormat4
  72 {
  73   struct segment_plan
  74   {
  75     HBUINT16 start_code;
  76     HBUINT16 end_code;
  77     bool use_delta;
  78   };
  79 
  80   bool serialize (hb_serialize_context_t *c,
  81                   const hb_subset_plan_t *plan,
  82                   const hb_vector_t<segment_plan> &segments)
  83   {
  84     TRACE_SERIALIZE (this);
  85 
  86     if (unlikely (!c->extend_min (*this))) return_trace (false);
  87 
  88     this->format.set (4);
  89     this->length.set (get_sub_table_size (segments));
  90 
  91     this->segCountX2.set (segments.len * 2);
  92     this->entrySelector.set (MAX (1u, _hb_bit_storage (segments.len)) - 1);
  93     this->searchRange.set (2 * (1u << this->entrySelector));
  94     this->rangeShift.set (segments.len * 2 > this->searchRange
  95                           ? 2 * segments.len - this->searchRange
  96                           : 0);
  97 
  98     HBUINT16 *end_count = c->allocate_size<HBUINT16> (HBUINT16::static_size * segments.len);
  99     c->allocate_size<HBUINT16> (HBUINT16::static_size); // 2 bytes of padding.
 100     HBUINT16 *start_count = c->allocate_size<HBUINT16> (HBUINT16::static_size * segments.len);
 101     HBINT16 *id_delta = c->allocate_size<HBINT16> (HBUINT16::static_size * segments.len);
 102     HBUINT16 *id_range_offset = c->allocate_size<HBUINT16> (HBUINT16::static_size * segments.len);
 103 
 104     if (id_range_offset == nullptr)
 105       return_trace (false);
 106 
 107     for (unsigned int i = 0; i < segments.len; i++)
 108     {
 109       end_count[i].set (segments[i].end_code);
 110       start_count[i].set (segments[i].start_code);
 111       if (segments[i].use_delta)
 112       {
 113         hb_codepoint_t cp = segments[i].start_code;
 114         hb_codepoint_t start_gid = 0;
 115         if (unlikely (!plan->new_gid_for_codepoint (cp, &start_gid) && cp != 0xFFFF))
 116           return_trace (false);
 117         id_delta[i].set (start_gid - segments[i].start_code);
 118       } else {
 119         id_delta[i].set (0);
 120         unsigned int num_codepoints = segments[i].end_code - segments[i].start_code + 1;
 121         HBUINT16 *glyph_id_array = c->allocate_size<HBUINT16> (HBUINT16::static_size * num_codepoints);
 122         if (glyph_id_array == nullptr)
 123           return_trace (false);
 124         // From the cmap spec:
 125         //
 126         // id_range_offset[i]/2
 127         // + (cp - segments[i].start_code)


 133         //
 134         // id_range_offset[i]
 135         // =
 136         // 2 * (glyph_id_array - id_range_offset - i)
 137         id_range_offset[i].set (2 * (
 138             glyph_id_array - id_range_offset - i));
 139         for (unsigned int j = 0; j < num_codepoints; j++)
 140         {
 141           hb_codepoint_t cp = segments[i].start_code + j;
 142           hb_codepoint_t new_gid;
 143           if (unlikely (!plan->new_gid_for_codepoint (cp, &new_gid)))
 144             return_trace (false);
 145           glyph_id_array[j].set (new_gid);
 146         }
 147       }
 148     }
 149 
 150     return_trace (true);
 151   }
 152 
 153   static inline size_t get_sub_table_size (const hb_vector_t<segment_plan> &segments)
 154   {
 155     size_t segment_size = 0;
 156     for (unsigned int i = 0; i < segments.len; i++)
 157     {
 158       // Parallel array entries
 159       segment_size +=
 160             2  // end count
 161           + 2  // start count
 162           + 2  // delta
 163           + 2; // range offset
 164 
 165       if (!segments[i].use_delta)
 166         // Add bytes for the glyph index array entries for this segment.
 167         segment_size += (segments[i].end_code - segments[i].start_code + 1) * 2;
 168     }
 169 
 170     return min_size
 171         + 2 // Padding
 172         + segment_size;
 173   }
 174 
 175   static inline bool create_sub_table_plan (const hb_subset_plan_t *plan,
 176                                             hb_vector_t<segment_plan> *segments)
 177   {
 178     segment_plan *segment = nullptr;
 179     hb_codepoint_t last_gid = 0;
 180 
 181     hb_codepoint_t cp = HB_SET_VALUE_INVALID;
 182     while (plan->unicodes->next (&cp)) {
 183       hb_codepoint_t new_gid;
 184       if (unlikely (!plan->new_gid_for_codepoint (cp, &new_gid)))
 185       {
 186         DEBUG_MSG(SUBSET, nullptr, "Unable to find new gid for %04x", cp);
 187         return false;
 188       }
 189 
 190       if (cp > 0xFFFF) {
 191         // We are now outside of unicode BMP, stop adding to this cmap.
 192         break;
 193       }
 194 
 195       if (!segment
 196           || cp != segment->end_code + 1u)
 197       {
 198         segment = segments->push ();
 199         segment->start_code.set (cp);
 200         segment->end_code.set (cp);
 201         segment->use_delta = true;
 202       } else {
 203         segment->end_code.set (cp);
 204         if (last_gid + 1u != new_gid)
 205           // gid's are not consecutive in this segment so delta
 206           // cannot be used.
 207           segment->use_delta = false;
 208       }
 209 
 210       last_gid = new_gid;
 211     }
 212 
 213     // There must be a final entry with end_code == 0xFFFF. Check if we need to add one.
 214     if (segment == nullptr || segment->end_code != 0xFFFF)
 215     {
 216       segment = segments->push ();
 217       segment->start_code.set (0xFFFF);
 218       segment->end_code.set (0xFFFF);
 219       segment->use_delta = true;
 220     }
 221 
 222     return true;
 223   }
 224 
 225   struct accelerator_t
 226   {
 227     inline void init (const CmapSubtableFormat4 *subtable)




 228     {
 229       segCount = subtable->segCountX2 / 2;
 230       endCount = subtable->values;
 231       startCount = endCount + segCount + 1;
 232       idDelta = startCount + segCount;
 233       idRangeOffset = idDelta + segCount;
 234       glyphIdArray = idRangeOffset + segCount;
 235       glyphIdArrayLength = (subtable->length - 16 - 8 * segCount) / 2;
 236     }

 237 
 238     static inline bool get_glyph_func (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph)
 239     {
 240       const accelerator_t *thiz = (const accelerator_t *) obj;
 241 
 242       /* Custom two-array bsearch. */
 243       int min = 0, max = (int) thiz->segCount - 1;
 244       const HBUINT16 *startCount = thiz->startCount;
 245       const HBUINT16 *endCount = thiz->endCount;
 246       unsigned int i;
 247       while (min <= max)
 248       {
 249         int mid = (min + max) / 2;
 250         if (codepoint < startCount[mid])
 251           max = mid - 1;
 252         else if (codepoint > endCount[mid])
 253           min = mid + 1;
 254         else
 255         {
 256           i = mid;
 257           goto found;
 258         }
 259       }
 260       return false;
 261 
 262     found:
 263       hb_codepoint_t gid;
 264       unsigned int rangeOffset = thiz->idRangeOffset[i];
 265       if (rangeOffset == 0)
 266         gid = codepoint + thiz->idDelta[i];
 267       else
 268       {
 269         /* Somebody has been smoking... */
 270         unsigned int index = rangeOffset / 2 + (codepoint - thiz->startCount[i]) + i - thiz->segCount;
 271         if (unlikely (index >= thiz->glyphIdArrayLength))
 272           return false;
 273         gid = thiz->glyphIdArray[index];
 274         if (unlikely (!gid))
 275           return false;
 276         gid += thiz->idDelta[i];
 277       }
 278 
 279       *glyph = gid & 0xFFFFu;


 280       return true;
 281     }
 282 
 283     static inline void get_all_codepoints_func (const void *obj, hb_set_t *out)



 284     {
 285       const accelerator_t *thiz = (const accelerator_t *) obj;
 286       for (unsigned int i = 0; i < thiz->segCount; i++)


 287       {
 288         if (thiz->startCount[i] != 0xFFFFu
 289             || thiz->endCount[i] != 0xFFFFu) // Skip the last segment (0xFFFF)
 290           hb_set_add_range (out, thiz->startCount[i], thiz->endCount[i]);















 291       }
 292     }
 293 
 294     const HBUINT16 *endCount;
 295     const HBUINT16 *startCount;
 296     const HBUINT16 *idDelta;
 297     const HBUINT16 *idRangeOffset;
 298     const HBUINT16 *glyphIdArray;
 299     unsigned int segCount;
 300     unsigned int glyphIdArrayLength;
 301   };
 302 
 303   inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
 304   {
 305     accelerator_t accel;
 306     accel.init (this);
 307     return accel.get_glyph_func (&accel, codepoint, glyph);
 308   }





 309 
 310   inline bool sanitize (hb_sanitize_context_t *c) const
 311   {
 312     TRACE_SANITIZE (this);
 313     if (unlikely (!c->check_struct (this)))
 314       return_trace (false);
 315 
 316     if (unlikely (!c->check_range (this, length)))
 317     {
 318       /* Some broken fonts have too long of a "length" value.
 319        * If that is the case, just change the value to truncate
 320        * the subtable at the end of the blob. */
 321       uint16_t new_length = (uint16_t) MIN ((uintptr_t) 65535,
 322                                             (uintptr_t) (c->end -
 323                                                          (char *) this));
 324       if (!c->try_set (&length, new_length))
 325         return_trace (false);
 326     }
 327 
 328     return_trace (16 + 4 * (unsigned int) segCountX2 <= length);
 329   }
 330 
 331 
 332 
 333   protected:
 334   HBUINT16      format;         /* Format number is set to 4. */
 335   HBUINT16      length;         /* This is the length in bytes of the
 336                                  * subtable. */
 337   HBUINT16      language;       /* Ignore. */
 338   HBUINT16      segCountX2;     /* 2 x segCount. */
 339   HBUINT16      searchRange;    /* 2 * (2**floor(log2(segCount))) */
 340   HBUINT16      entrySelector;  /* log2(searchRange/2) */
 341   HBUINT16      rangeShift;     /* 2 x segCount - searchRange */
 342 
 343   HBUINT16      values[VAR];

 344 #if 0
 345   HBUINT16      endCount[segCount];     /* End characterCode for each segment,
 346                                          * last=0xFFFFu. */
 347   HBUINT16      reservedPad;            /* Set to 0. */
 348   HBUINT16      startCount[segCount];   /* Start character code for each segment. */
 349   HBINT16               idDelta[segCount];      /* Delta for all character codes in segment. */
 350   HBUINT16      idRangeOffset[segCount];/* Offsets into glyphIdArray or 0 */
 351   HBUINT16      glyphIdArray[VAR];      /* Glyph index array (arbitrary length) */

 352 #endif
 353 
 354   public:
 355   DEFINE_SIZE_ARRAY (14, values);
 356 };
 357 
 358 struct CmapSubtableLongGroup
 359 {
 360   friend struct CmapSubtableFormat12;
 361   friend struct CmapSubtableFormat13;
 362   template<typename U>
 363   friend struct CmapSubtableLongSegmented;
 364   friend struct cmap;
 365 
 366   int cmp (hb_codepoint_t codepoint) const
 367   {
 368     if (codepoint < startCharCode) return -1;
 369     if (codepoint > endCharCode)   return +1;
 370     return 0;
 371   }
 372 
 373   inline bool sanitize (hb_sanitize_context_t *c) const
 374   {
 375     TRACE_SANITIZE (this);
 376     return_trace (c->check_struct (this));
 377   }
 378 
 379   private:
 380   HBUINT32              startCharCode;  /* First character code in this group. */
 381   HBUINT32              endCharCode;    /* Last character code in this group. */
 382   HBUINT32              glyphID;        /* Glyph index; interpretation depends on
 383                                  * subtable format. */
 384   public:
 385   DEFINE_SIZE_STATIC (12);
 386 };

 387 
 388 template <typename UINT>
 389 struct CmapSubtableTrimmed
 390 {
 391   inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
 392   {
 393     /* Rely on our implicit array bound-checking. */
 394     hb_codepoint_t gid = glyphIdArray[codepoint - startCharCode];
 395     if (!gid)
 396       return false;
 397     *glyph = gid;
 398     return true;
 399   }








 400 
 401   inline bool sanitize (hb_sanitize_context_t *c) const
 402   {
 403     TRACE_SANITIZE (this);
 404     return_trace (c->check_struct (this) && glyphIdArray.sanitize (c));
 405   }
 406 
 407   protected:
 408   UINT          formatReserved; /* Subtable format and (maybe) padding. */
 409   UINT          length;         /* Byte length of this subtable. */
 410   UINT          language;       /* Ignore. */
 411   UINT          startCharCode;  /* First character code covered. */
 412   ArrayOf<GlyphID, UINT>
 413                 glyphIdArray;   /* Array of glyph index values for character
 414                                  * codes in the range. */
 415   public:
 416   DEFINE_SIZE_ARRAY (5 * sizeof (UINT), glyphIdArray);
 417 };
 418 
 419 struct CmapSubtableFormat6  : CmapSubtableTrimmed<HBUINT16> {};
 420 struct CmapSubtableFormat10 : CmapSubtableTrimmed<HBUINT32 > {};
 421 
 422 template <typename T>
 423 struct CmapSubtableLongSegmented
 424 {
 425   friend struct cmap;
 426 
 427   inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
 428   {
 429     int i = groups.bsearch (codepoint);
 430     if (i == -1)
 431       return false;
 432     *glyph = T::group_get_glyph (groups[i], codepoint);
 433     return true;
 434   }
 435 
 436   inline void get_all_codepoints (hb_set_t *out) const
 437   {
 438     for (unsigned int i = 0; i < this->groups.len; i++) {
 439       hb_set_add_range (out,
 440                         this->groups[i].startCharCode,
 441                         this->groups[i].endCharCode);
 442     }
 443   }
 444 
 445   inline bool sanitize (hb_sanitize_context_t *c) const
 446   {
 447     TRACE_SANITIZE (this);
 448     return_trace (c->check_struct (this) && groups.sanitize (c));
 449   }
 450 
 451   inline bool serialize (hb_serialize_context_t *c,
 452                          const hb_vector_t<CmapSubtableLongGroup> &group_data)
 453   {
 454     TRACE_SERIALIZE (this);
 455     if (unlikely (!c->extend_min (*this))) return_trace (false);
 456     Supplier<CmapSubtableLongGroup> supplier (group_data.arrayZ, group_data.len);
 457     if (unlikely (!groups.serialize (c, supplier, group_data.len))) return_trace (false);
 458     return true;
 459   }
 460 
 461   protected:
 462   HBUINT16      format;         /* Subtable format; set to 12. */
 463   HBUINT16      reserved;       /* Reserved; set to 0. */
 464   HBUINT32      length;         /* Byte length of this subtable. */
 465   HBUINT32      language;       /* Ignore. */
 466   SortedArrayOf<CmapSubtableLongGroup, HBUINT32>
 467                 groups;         /* Groupings. */
 468   public:
 469   DEFINE_SIZE_ARRAY (16, groups);
 470 };
 471 
 472 struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
 473 {
 474   static inline hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
 475                                                 hb_codepoint_t u)
 476   { return group.glyphID + (u - group.startCharCode); }

 477 
 478 
 479   bool serialize (hb_serialize_context_t *c,
 480                   const hb_vector_t<CmapSubtableLongGroup> &groups)
 481   {
 482     if (unlikely (!c->extend_min (*this))) return false;
 483 
 484     this->format.set (12);
 485     this->reserved.set (0);
 486     this->length.set (get_sub_table_size (groups));
 487 
 488     return CmapSubtableLongSegmented<CmapSubtableFormat12>::serialize (c, groups);
 489   }
 490 
 491   static inline size_t get_sub_table_size (const hb_vector_t<CmapSubtableLongGroup> &groups)
 492   {
 493     return 16 + 12 * groups.len;
 494   }
 495 
 496   static inline bool create_sub_table_plan (const hb_subset_plan_t *plan,
 497                                             hb_vector_t<CmapSubtableLongGroup> *groups)
 498   {
 499     CmapSubtableLongGroup *group = nullptr;
 500 
 501     hb_codepoint_t cp = HB_SET_VALUE_INVALID;
 502     while (plan->unicodes->next (&cp)) {
 503       hb_codepoint_t new_gid;
 504       if (unlikely (!plan->new_gid_for_codepoint (cp, &new_gid)))
 505       {
 506         DEBUG_MSG(SUBSET, nullptr, "Unable to find new gid for %04x", cp);
 507         return false;
 508       }
 509 
 510       if (!group || !_is_gid_consecutive (group, cp, new_gid))
 511       {
 512         group = groups->push ();
 513         group->startCharCode.set (cp);
 514         group->endCharCode.set (cp);
 515         group->glyphID.set (new_gid);
 516       } else
 517       {
 518         group->endCharCode.set (cp);
 519       }

 520     }
 521 
 522     DEBUG_MSG(SUBSET, nullptr, "cmap");
 523     for (unsigned int i = 0; i < groups->len; i++) {
 524       CmapSubtableLongGroup& group = (*groups)[i];
 525       DEBUG_MSG(SUBSET, nullptr, "  %d: U+%04X-U+%04X, gid %d-%d", i, (uint32_t) group.startCharCode, (uint32_t) group.endCharCode, (uint32_t) group.glyphID, (uint32_t) group.glyphID + ((uint32_t) group.endCharCode - (uint32_t) group.startCharCode));
 526     }
 527 
 528     return true;
 529   }
 530 
 531  private:
 532   static inline bool _is_gid_consecutive (CmapSubtableLongGroup *group,
 533                                           hb_codepoint_t cp,
 534                                           hb_codepoint_t new_gid)
 535   {
 536     return (cp - 1 == group->endCharCode) &&
 537         new_gid == group->glyphID + (cp - group->startCharCode);
 538   }
 539 
 540 };
 541 
 542 struct CmapSubtableFormat13 : CmapSubtableLongSegmented<CmapSubtableFormat13>
 543 {
 544   static inline hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
 545                                                 hb_codepoint_t u HB_UNUSED)
 546   { return group.glyphID; }
 547 };
 548 
 549 typedef enum
 550 {
 551   GLYPH_VARIANT_NOT_FOUND = 0,
 552   GLYPH_VARIANT_FOUND = 1,
 553   GLYPH_VARIANT_USE_DEFAULT = 2
 554 } glyph_variant_t;
 555 
 556 struct UnicodeValueRange
 557 {
 558   inline int cmp (const hb_codepoint_t &codepoint) const
 559   {
 560     if (codepoint < startUnicodeValue) return -1;
 561     if (codepoint > startUnicodeValue + additionalCount) return +1;
 562     return 0;
 563   }
 564 
 565   inline bool sanitize (hb_sanitize_context_t *c) const
 566   {
 567     TRACE_SANITIZE (this);
 568     return_trace (c->check_struct (this));
 569   }
 570 
 571   HBUINT24      startUnicodeValue;      /* First value in this range. */
 572   HBUINT8               additionalCount;        /* Number of additional values in this
 573                                          * range. */
 574   public:
 575   DEFINE_SIZE_STATIC (4);
 576 };
 577 
 578 typedef SortedArrayOf<UnicodeValueRange, HBUINT32> DefaultUVS;
















 579 
 580 struct UVSMapping
 581 {
 582   inline int cmp (const hb_codepoint_t &codepoint) const
 583   {
 584     return unicodeValue.cmp (codepoint);
 585   }
 586 
 587   inline bool sanitize (hb_sanitize_context_t *c) const
 588   {
 589     TRACE_SANITIZE (this);
 590     return_trace (c->check_struct (this));
 591   }
 592 
 593   HBUINT24      unicodeValue;   /* Base Unicode value of the UVS */
 594   GlyphID       glyphID;        /* Glyph ID of the UVS */
 595   public:
 596   DEFINE_SIZE_STATIC (5);
 597 };
 598 
 599 typedef SortedArrayOf<UVSMapping, HBUINT32> NonDefaultUVS;











 600 
 601 struct VariationSelectorRecord
 602 {
 603   inline glyph_variant_t get_glyph (hb_codepoint_t codepoint,
 604                                     hb_codepoint_t *glyph,
 605                                     const void *base) const
 606   {
 607     int i;
 608     const DefaultUVS &defaults = base+defaultUVS;
 609     i = defaults.bsearch (codepoint);
 610     if (i != -1)
 611       return GLYPH_VARIANT_USE_DEFAULT;
 612     const NonDefaultUVS &nonDefaults = base+nonDefaultUVS;
 613     i = nonDefaults.bsearch (codepoint);
 614     if (i != -1)
 615     {
 616       *glyph = nonDefaults[i].glyphID;
 617        return GLYPH_VARIANT_FOUND;
 618     }
 619     return GLYPH_VARIANT_NOT_FOUND;
 620   }
 621 
 622   inline int cmp (const hb_codepoint_t &variation_selector) const






 623   {
 624     return varSelector.cmp (variation_selector);
 625   }
 626 
 627   inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
 628   {
 629     TRACE_SANITIZE (this);
 630     return_trace (c->check_struct (this) &&
 631                   defaultUVS.sanitize (c, base) &&
 632                   nonDefaultUVS.sanitize (c, base));
 633   }
 634 
 635   HBUINT24      varSelector;    /* Variation selector. */
 636   LOffsetTo<DefaultUVS>
 637                 defaultUVS;     /* Offset to Default UVS Table. May be 0. */
 638   LOffsetTo<NonDefaultUVS>
 639                 nonDefaultUVS;  /* Offset to Non-Default UVS Table. May be 0. */
 640   public:
 641   DEFINE_SIZE_STATIC (11);
 642 };
 643 
 644 struct CmapSubtableFormat14
 645 {
 646   inline glyph_variant_t get_glyph_variant (hb_codepoint_t codepoint,
 647                                             hb_codepoint_t variation_selector,
 648                                             hb_codepoint_t *glyph) const
 649   {
 650     return record[record.bsearch(variation_selector)].get_glyph (codepoint, glyph, this);
 651   }
 652 
 653   inline bool sanitize (hb_sanitize_context_t *c) const












 654   {
 655     TRACE_SANITIZE (this);
 656     return_trace (c->check_struct (this) &&
 657                   record.sanitize (c, this));
 658   }
 659 
 660   protected:
 661   HBUINT16      format;         /* Format number is set to 14. */
 662   HBUINT32      length;         /* Byte length of this subtable. */
 663   SortedArrayOf<VariationSelectorRecord, HBUINT32>
 664                 record;         /* Variation selector records; sorted
 665                                  * in increasing order of `varSelector'. */
 666   public:
 667   DEFINE_SIZE_ARRAY (10, record);
 668 };
 669 
 670 struct CmapSubtable
 671 {
 672   /* Note: We intentionally do NOT implement subtable formats 2 and 8. */
 673 
 674   inline bool get_glyph (hb_codepoint_t codepoint,
 675                          hb_codepoint_t *glyph) const
 676   {
 677     switch (u.format) {
 678     case  0: return u.format0 .get_glyph (codepoint, glyph);
 679     case  4: return u.format4 .get_glyph (codepoint, glyph);
 680     case  6: return u.format6 .get_glyph (codepoint, glyph);
 681     case 10: return u.format10.get_glyph (codepoint, glyph);
 682     case 12: return u.format12.get_glyph (codepoint, glyph);
 683     case 13: return u.format13.get_glyph (codepoint, glyph);
 684     case 14:
 685     default: return false;
 686     }
 687   }













 688 
 689   inline bool sanitize (hb_sanitize_context_t *c) const
 690   {
 691     TRACE_SANITIZE (this);
 692     if (!u.format.sanitize (c)) return_trace (false);
 693     switch (u.format) {
 694     case  0: return_trace (u.format0 .sanitize (c));
 695     case  4: return_trace (u.format4 .sanitize (c));
 696     case  6: return_trace (u.format6 .sanitize (c));
 697     case 10: return_trace (u.format10.sanitize (c));
 698     case 12: return_trace (u.format12.sanitize (c));
 699     case 13: return_trace (u.format13.sanitize (c));
 700     case 14: return_trace (u.format14.sanitize (c));
 701     default:return_trace (true);
 702     }
 703   }
 704 
 705   public:
 706   union {
 707   HBUINT16              format;         /* Format identifier */
 708   CmapSubtableFormat0   format0;
 709   CmapSubtableFormat4   format4;
 710   CmapSubtableFormat6   format6;
 711   CmapSubtableFormat10  format10;
 712   CmapSubtableFormat12  format12;
 713   CmapSubtableFormat13  format13;
 714   CmapSubtableFormat14  format14;
 715   } u;
 716   public:
 717   DEFINE_SIZE_UNION (2, format);
 718 };
 719 
 720 
 721 struct EncodingRecord
 722 {
 723   inline int cmp (const EncodingRecord &other) const
 724   {
 725     int ret;
 726     ret = platformID.cmp (other.platformID);
 727     if (ret) return ret;
 728     ret = encodingID.cmp (other.encodingID);
 729     if (ret) return ret;
 730     return 0;
 731   }
 732 
 733   inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
 734   {
 735     TRACE_SANITIZE (this);
 736     return_trace (c->check_struct (this) &&
 737                   subtable.sanitize (c, base));
 738   }
 739 
 740   HBUINT16      platformID;     /* Platform ID. */
 741   HBUINT16      encodingID;     /* Platform-specific encoding ID. */
 742   LOffsetTo<CmapSubtable>
 743                 subtable;       /* Byte offset from beginning of table to the subtable for this encoding. */
 744   public:
 745   DEFINE_SIZE_STATIC (8);
 746 };
 747 
 748 struct cmap
 749 {
 750   static const hb_tag_t tableTag        = HB_OT_TAG_cmap;
 751 
 752   struct subset_plan {
 753     subset_plan(void)
 754     {
 755       format4_segments.init();
 756       format12_groups.init();
 757     }
 758 
 759     ~subset_plan(void)
 760     {
 761       format4_segments.fini();
 762       format12_groups.fini();
 763     }
 764 
 765     inline size_t final_size() const
 766     {
 767       return 4 // header
 768           +  8 * 3 // 3 EncodingRecord
 769           +  CmapSubtableFormat4::get_sub_table_size (this->format4_segments)
 770           +  CmapSubtableFormat12::get_sub_table_size (this->format12_groups);
 771     }
 772 
 773     // Format 4
 774     hb_vector_t<CmapSubtableFormat4::segment_plan> format4_segments;
 775     // Format 12
 776     hb_vector_t<CmapSubtableLongGroup> format12_groups;
 777   };
 778 
 779   inline bool sanitize (hb_sanitize_context_t *c) const
 780   {
 781     TRACE_SANITIZE (this);
 782     return_trace (c->check_struct (this) &&
 783                   likely (version == 0) &&
 784                   encodingRecord.sanitize (c, this));
 785   }
 786 
 787   inline bool _create_plan (const hb_subset_plan_t *plan,
 788                             subset_plan *cmap_plan) const
 789   {
 790     if (unlikely( !CmapSubtableFormat4::create_sub_table_plan (plan, &cmap_plan->format4_segments)))
 791       return false;
 792 
 793     return CmapSubtableFormat12::create_sub_table_plan (plan, &cmap_plan->format12_groups);
 794   }
 795 
 796   inline bool _subset (const hb_subset_plan_t *plan,
 797                        const subset_plan &cmap_subset_plan,
 798                        size_t dest_sz,
 799                        void *dest) const
 800   {
 801     hb_serialize_context_t c (dest, dest_sz);
 802 
 803     OT::cmap *cmap = c.start_serialize<OT::cmap> ();
 804     if (unlikely (!c.extend_min (*cmap)))
 805     {
 806       return false;
 807     }
 808 
 809     cmap->version.set (0);
 810 
 811     if (unlikely (!cmap->encodingRecord.serialize (&c, /* numTables */ 3)))
 812       return false;
 813 
 814     // TODO(grieger): Convert the below to a for loop
 815 
 816     // Format 4, Plat 0 Encoding Record
 817     EncodingRecord &format4_plat0_rec = cmap->encodingRecord[0];
 818     format4_plat0_rec.platformID.set (0); // Unicode
 819     format4_plat0_rec.encodingID.set (3);
 820 
 821     // Format 4, Plat 3 Encoding Record
 822     EncodingRecord &format4_plat3_rec = cmap->encodingRecord[1];
 823     format4_plat3_rec.platformID.set (3); // Windows
 824     format4_plat3_rec.encodingID.set (1); // Unicode BMP
 825 
 826     // Format 12 Encoding Record
 827     EncodingRecord &format12_rec = cmap->encodingRecord[2];
 828     format12_rec.platformID.set (3); // Windows
 829     format12_rec.encodingID.set (10); // Unicode UCS-4
 830 
 831     // Write out format 4 sub table
 832     {
 833       CmapSubtable &subtable = format4_plat0_rec.subtable.serialize (&c, cmap);
 834       format4_plat3_rec.subtable.set (format4_plat0_rec.subtable);
 835       subtable.u.format.set (4);
 836 
 837       CmapSubtableFormat4 &format4 = subtable.u.format4;
 838       if (unlikely (!format4.serialize (&c, plan, cmap_subset_plan.format4_segments)))
 839         return false;
 840     }
 841 
 842     // Write out format 12 sub table.
 843     {
 844       CmapSubtable &subtable = format12_rec.subtable.serialize (&c, cmap);
 845       subtable.u.format.set (12);
 846 
 847       CmapSubtableFormat12 &format12 = subtable.u.format12;
 848       if (unlikely (!format12.serialize (&c, cmap_subset_plan.format12_groups)))
 849         return false;
 850     }
 851 
 852     c.end_serialize ();
 853 
 854     return true;
 855   }
 856 
 857   inline bool subset (hb_subset_plan_t *plan) const
 858   {
 859     subset_plan cmap_subset_plan;
 860 
 861     if (unlikely (!_create_plan (plan, &cmap_subset_plan)))
 862     {
 863       DEBUG_MSG(SUBSET, nullptr, "Failed to generate a cmap subsetting plan.");
 864       return false;
 865     }
 866 
 867     // We now know how big our blob needs to be
 868     size_t dest_sz = cmap_subset_plan.final_size();
 869     void *dest = malloc (dest_sz);
 870     if (unlikely (!dest)) {
 871       DEBUG_MSG(SUBSET, nullptr, "Unable to alloc %lu for cmap subset output", (unsigned long) dest_sz);
 872       return false;
 873     }
 874 
 875     if (unlikely (!_subset (plan, cmap_subset_plan, dest_sz, dest)))
 876     {
 877       DEBUG_MSG(SUBSET, nullptr, "Failed to perform subsetting of cmap.");
 878       free (dest);
 879       return false;
 880     }
 881 
 882     // all done, write the blob into dest
 883     hb_blob_t *cmap_prime = hb_blob_create ((const char *)dest,
 884                                             dest_sz,
 885                                             HB_MEMORY_MODE_READONLY,
 886                                             dest,
 887                                             free);
 888     bool result =  plan->add_table (HB_OT_TAG_cmap, cmap_prime);
 889     hb_blob_destroy (cmap_prime);
 890     return result;
 891   }
 892 
 893   struct accelerator_t
 894   {
 895     inline void init (hb_face_t *face)
 896     {
 897       this->blob = OT::Sanitizer<OT::cmap>().sanitize (face->reference_table (HB_OT_TAG_cmap));
 898       const OT::cmap *cmap = this->blob->as<OT::cmap> ();
 899       const OT::CmapSubtable *subtable = nullptr;
 900       const OT::CmapSubtableFormat14 *subtable_uvs = nullptr;
 901 
 902       bool symbol = false;
 903       /* 32-bit subtables. */
 904       if (!subtable) subtable = cmap->find_subtable (3, 10);
 905       if (!subtable) subtable = cmap->find_subtable (0, 6);
 906       if (!subtable) subtable = cmap->find_subtable (0, 4);

 907       /* 16-bit subtables. */
 908       if (!subtable) subtable = cmap->find_subtable (3, 1);
 909       if (!subtable) subtable = cmap->find_subtable (0, 3);
 910       if (!subtable) subtable = cmap->find_subtable (0, 2);
 911       if (!subtable) subtable = cmap->find_subtable (0, 1);
 912       if (!subtable) subtable = cmap->find_subtable (0, 0);
 913       if (!subtable)


 914       {
 915         subtable = cmap->find_subtable (3, 0);
 916         if (subtable) symbol = true;
 917       }

 918       /* Meh. */
 919       if (!subtable) subtable = &Null(OT::CmapSubtable);

 920 
 921       /* UVS subtable. */
 922       if (!subtable_uvs)






 923       {
 924         const OT::CmapSubtable *st = cmap->find_subtable (0, 5);
 925         if (st && st->u.format == 14)
 926           subtable_uvs = &st->u.format14;
 927       }
 928       /* Meh. */
 929       if (!subtable_uvs) subtable_uvs = &Null(OT::CmapSubtableFormat14);
 930 
 931       this->uvs_table = subtable_uvs;
 932 
 933       this->get_glyph_data = subtable;
 934       if (unlikely (symbol))
 935       {
 936         this->get_glyph_func = get_glyph_from_symbol<OT::CmapSubtable>;
 937         this->get_all_codepoints_func = null_get_all_codepoints_func;
 938       } else {
 939         switch (subtable->u.format) {
 940         /* Accelerate format 4 and format 12. */
 941         default:
 942           this->get_glyph_func = get_glyph_from<OT::CmapSubtable>;
 943           this->get_all_codepoints_func = null_get_all_codepoints_func;
 944           break;
 945         case 12:
 946           this->get_glyph_func = get_glyph_from<OT::CmapSubtableFormat12>;
 947           this->get_all_codepoints_func = get_all_codepoints_from<OT::CmapSubtableFormat12>;
 948           break;
 949         case  4:
 950           {
 951             this->format4_accel.init (&subtable->u.format4);
 952             this->get_glyph_data = &this->format4_accel;
 953             this->get_glyph_func = this->format4_accel.get_glyph_func;
 954             this->get_all_codepoints_func = this->format4_accel.get_all_codepoints_func;
 955           }
 956           break;
 957         }
 958       }
 959     }
 960 
 961     inline void fini (void)



 962     {
 963       hb_blob_destroy (this->blob);

 964     }







 965 
 966     inline bool get_nominal_glyph (hb_codepoint_t  unicode,
 967                                    hb_codepoint_t *glyph) const





 968     {
 969       return this->get_glyph_func (this->get_glyph_data, unicode, glyph);



 970     }
 971 
 972     inline bool get_variation_glyph (hb_codepoint_t  unicode,
 973                                      hb_codepoint_t  variation_selector,
 974                                      hb_codepoint_t *glyph) const
 975     {
 976       switch (this->uvs_table->get_glyph_variant (unicode,
 977                                                   variation_selector,
 978                                                   glyph))
 979       {
 980         case OT::GLYPH_VARIANT_NOT_FOUND:               return false;
 981         case OT::GLYPH_VARIANT_FOUND:           return true;
 982         case OT::GLYPH_VARIANT_USE_DEFAULT:     break;
 983       }
 984 
 985       return get_nominal_glyph (unicode, glyph);
 986     }
 987 
 988     inline void get_all_codepoints (hb_set_t *out) const




 989     {
 990       this->get_all_codepoints_func (get_glyph_data, out);





 991     }
 992 
 993     protected:
 994     typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj,
 995                                               hb_codepoint_t codepoint,
 996                                               hb_codepoint_t *glyph);
 997     typedef void (*hb_cmap_get_all_codepoints_func_t) (const void *obj,
 998                                                        hb_set_t *out);
 999 
1000     static inline void null_get_all_codepoints_func (const void *obj, hb_set_t *out)
1001     {
1002       // NOOP
1003     }
1004 
1005     template <typename Type>
1006     static inline bool get_glyph_from (const void *obj,
1007                                        hb_codepoint_t codepoint,
1008                                        hb_codepoint_t *glyph)
1009     {
1010       const Type *typed_obj = (const Type *) obj;
1011       return typed_obj->get_glyph (codepoint, glyph);
1012     }
1013 
1014     template <typename Type>
1015     static inline void get_all_codepoints_from (const void *obj,
1016                                                 hb_set_t *out)
1017     {
1018       const Type *typed_obj = (const Type *) obj;
1019       typed_obj->get_all_codepoints (out);
1020     }
1021 
1022     template <typename Type>
1023     static inline bool get_glyph_from_symbol (const void *obj,
1024                                               hb_codepoint_t codepoint,
1025                                               hb_codepoint_t *glyph)
1026     {
1027       const Type *typed_obj = (const Type *) obj;
1028       if (likely (typed_obj->get_glyph (codepoint, glyph)))
1029         return true;
1030 
1031       if (codepoint <= 0x00FFu)
1032       {
1033         /* For symbol-encoded OpenType fonts, we duplicate the
1034          * U+F000..F0FF range at U+0000..U+00FF.  That's what
1035          * Windows seems to do, and that's hinted about at:
1036          * https://docs.microsoft.com/en-us/typography/opentype/spec/recom
1037          * under "Non-Standard (Symbol) Fonts". */
1038         return typed_obj->get_glyph (0xF000u + codepoint, glyph);
1039       }
1040 
1041       return false;
1042     }
1043 
1044     private:
1045     hb_cmap_get_glyph_func_t get_glyph_func;



1046     const void *get_glyph_data;
1047     hb_cmap_get_all_codepoints_func_t get_all_codepoints_func;
1048 
1049     OT::CmapSubtableFormat4::accelerator_t format4_accel;
1050 
1051     const OT::CmapSubtableFormat14 *uvs_table;
1052     hb_blob_t *blob;
1053   };
1054 
1055   protected:
1056 
1057   inline const CmapSubtable *find_subtable (unsigned int platform_id,
1058                                             unsigned int encoding_id) const
1059   {
1060     EncodingRecord key;
1061     key.platformID.set (platform_id);
1062     key.encodingID.set (encoding_id);
1063 
1064     /* Note: We can use bsearch, but since it has no performance
1065      * implications, we use lsearch and as such accept fonts with
1066      * unsorted subtable list. */
1067     int result = encodingRecord./*bsearch*/lsearch (key);
1068     if (result == -1 || !encodingRecord[result].subtable)
1069       return nullptr;
1070 
1071     return &(this+encodingRecord[result].subtable);










1072   }
1073 
1074   protected:
1075   HBUINT16              version;        /* Table version number (0). */
1076   SortedArrayOf<EncodingRecord>
1077                         encodingRecord; /* Encoding tables. */
1078   public:
1079   DEFINE_SIZE_ARRAY (4, encodingRecord);
1080 };
1081 

1082 
1083 } /* namespace OT */
1084 
1085 
1086 #endif /* HB_OT_CMAP_TABLE_HH */


  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  * Google Author(s): Behdad Esfahbod
  25  */
  26 
  27 #ifndef HB_OT_CMAP_TABLE_HH
  28 #define HB_OT_CMAP_TABLE_HH
  29 
  30 #include "hb-open-type.hh"
  31 #include "hb-set.hh"

  32 
  33 /*
  34  * cmap -- Character to Glyph Index Mapping
  35  * https://docs.microsoft.com/en-us/typography/opentype/spec/cmap
  36  */
  37 #define HB_OT_TAG_cmap HB_TAG('c','m','a','p')
  38 

  39 namespace OT {
  40 
  41 
  42 struct CmapSubtableFormat0
  43 {
  44   bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
  45   {
  46     hb_codepoint_t gid = codepoint < 256 ? glyphIdArray[codepoint] : 0;
  47     if (!gid)
  48       return false;
  49     *glyph = gid;
  50     return true;
  51   }
  52   void collect_unicodes (hb_set_t *out) const
  53   {
  54     for (unsigned int i = 0; i < 256; i++)
  55       if (glyphIdArray[i])
  56         out->add (i);
  57   }
  58 
  59   bool sanitize (hb_sanitize_context_t *c) const
  60   {
  61     TRACE_SANITIZE (this);
  62     return_trace (c->check_struct (this));
  63   }
  64 
  65   protected:
  66   HBUINT16      format;         /* Format number is set to 0. */
  67   HBUINT16      length;         /* Byte length of this subtable. */
  68   HBUINT16      language;       /* Ignore. */
  69   HBUINT8       glyphIdArray[256];/* An array that maps character
  70                                  * code to glyph index values. */
  71   public:
  72   DEFINE_SIZE_STATIC (6 + 256);
  73 };
  74 
  75 struct CmapSubtableFormat4
  76 {
  77   struct segment_plan
  78   {
  79     HBUINT16 start_code;
  80     HBUINT16 end_code;
  81     bool use_delta;
  82   };
  83 
  84   bool serialize (hb_serialize_context_t *c,
  85                   const hb_subset_plan_t *plan,
  86                   const hb_vector_t<segment_plan> &segments)
  87   {
  88     TRACE_SERIALIZE (this);
  89 
  90     if (unlikely (!c->extend_min (*this))) return_trace (false);
  91 
  92     this->format.set (4);
  93     this->length.set (get_sub_table_size (segments));
  94 
  95     this->segCountX2.set (segments.length * 2);
  96     this->entrySelector.set (MAX (1u, hb_bit_storage (segments.length)) - 1);
  97     this->searchRange.set (2 * (1u << this->entrySelector));
  98     this->rangeShift.set (segments.length * 2 > this->searchRange
  99                           ? 2 * segments.length - this->searchRange
 100                           : 0);
 101 
 102     HBUINT16 *end_count = c->allocate_size<HBUINT16> (HBUINT16::static_size * segments.length);
 103     c->allocate_size<HBUINT16> (HBUINT16::static_size); // 2 bytes of padding.
 104     HBUINT16 *start_count = c->allocate_size<HBUINT16> (HBUINT16::static_size * segments.length);
 105     HBINT16 *id_delta = c->allocate_size<HBINT16> (HBUINT16::static_size * segments.length);
 106     HBUINT16 *id_range_offset = c->allocate_size<HBUINT16> (HBUINT16::static_size * segments.length);
 107 
 108     if (id_range_offset == nullptr)
 109       return_trace (false);
 110 
 111     for (unsigned int i = 0; i < segments.length; i++)
 112     {
 113       end_count[i].set (segments[i].end_code);
 114       start_count[i].set (segments[i].start_code);
 115       if (segments[i].use_delta)
 116       {
 117         hb_codepoint_t cp = segments[i].start_code;
 118         hb_codepoint_t start_gid = 0;
 119         if (unlikely (!plan->new_gid_for_codepoint (cp, &start_gid) && cp != 0xFFFF))
 120           return_trace (false);
 121         id_delta[i].set (start_gid - segments[i].start_code);
 122       } else {
 123         id_delta[i].set (0);
 124         unsigned int num_codepoints = segments[i].end_code - segments[i].start_code + 1;
 125         HBUINT16 *glyph_id_array = c->allocate_size<HBUINT16> (HBUINT16::static_size * num_codepoints);
 126         if (glyph_id_array == nullptr)
 127           return_trace (false);
 128         // From the cmap spec:
 129         //
 130         // id_range_offset[i]/2
 131         // + (cp - segments[i].start_code)


 137         //
 138         // id_range_offset[i]
 139         // =
 140         // 2 * (glyph_id_array - id_range_offset - i)
 141         id_range_offset[i].set (2 * (
 142             glyph_id_array - id_range_offset - i));
 143         for (unsigned int j = 0; j < num_codepoints; j++)
 144         {
 145           hb_codepoint_t cp = segments[i].start_code + j;
 146           hb_codepoint_t new_gid;
 147           if (unlikely (!plan->new_gid_for_codepoint (cp, &new_gid)))
 148             return_trace (false);
 149           glyph_id_array[j].set (new_gid);
 150         }
 151       }
 152     }
 153 
 154     return_trace (true);
 155   }
 156 
 157   static size_t get_sub_table_size (const hb_vector_t<segment_plan> &segments)
 158   {
 159     size_t segment_size = 0;
 160     for (unsigned int i = 0; i < segments.length; i++)
 161     {
 162       // Parallel array entries
 163       segment_size +=
 164             2  // end count
 165           + 2  // start count
 166           + 2  // delta
 167           + 2; // range offset
 168 
 169       if (!segments[i].use_delta)
 170         // Add bytes for the glyph index array entries for this segment.
 171         segment_size += (segments[i].end_code - segments[i].start_code + 1) * 2;
 172     }
 173 
 174     return min_size
 175         + 2 // Padding
 176         + segment_size;
 177   }
 178 
 179   static bool create_sub_table_plan (const hb_subset_plan_t *plan,
 180                                      hb_vector_t<segment_plan> *segments)
 181   {
 182     segment_plan *segment = nullptr;
 183     hb_codepoint_t last_gid = 0;
 184 
 185     hb_codepoint_t cp = HB_SET_VALUE_INVALID;
 186     while (plan->unicodes->next (&cp)) {
 187       hb_codepoint_t new_gid;
 188       if (unlikely (!plan->new_gid_for_codepoint (cp, &new_gid)))
 189       {
 190         DEBUG_MSG(SUBSET, nullptr, "Unable to find new gid for %04x", cp);
 191         return false;
 192       }
 193 
 194       /* Stop adding to cmap if we are now outside of unicode BMP. */
 195       if (cp > 0xFFFF) break;


 196 
 197       if (!segment ||
 198           cp != segment->end_code + 1u)
 199       {
 200         segment = segments->push ();
 201         segment->start_code.set (cp);
 202         segment->end_code.set (cp);
 203         segment->use_delta = true;
 204       } else {
 205         segment->end_code.set (cp);
 206         if (last_gid + 1u != new_gid)
 207           // gid's are not consecutive in this segment so delta
 208           // cannot be used.
 209           segment->use_delta = false;
 210       }
 211 
 212       last_gid = new_gid;
 213     }
 214 
 215     // There must be a final entry with end_code == 0xFFFF. Check if we need to add one.
 216     if (segment == nullptr || segment->end_code != 0xFFFF)
 217     {
 218       segment = segments->push ();
 219       segment->start_code.set (0xFFFF);
 220       segment->end_code.set (0xFFFF);
 221       segment->use_delta = true;
 222     }
 223 
 224     return true;
 225   }
 226 
 227   struct accelerator_t
 228   {
 229     accelerator_t () {}
 230     accelerator_t (const CmapSubtableFormat4 *subtable) { init (subtable); }
 231     ~accelerator_t () { fini (); }
 232 
 233     void init (const CmapSubtableFormat4 *subtable)
 234     {
 235       segCount = subtable->segCountX2 / 2;
 236       endCount = subtable->values.arrayZ;
 237       startCount = endCount + segCount + 1;
 238       idDelta = startCount + segCount;
 239       idRangeOffset = idDelta + segCount;
 240       glyphIdArray = idRangeOffset + segCount;
 241       glyphIdArrayLength = (subtable->length - 16 - 8 * segCount) / 2;
 242     }
 243     void fini () {}
 244 
 245     bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
 246     {


 247       /* Custom two-array bsearch. */
 248       int min = 0, max = (int) this->segCount - 1;
 249       const HBUINT16 *startCount = this->startCount;
 250       const HBUINT16 *endCount = this->endCount;
 251       unsigned int i;
 252       while (min <= max)
 253       {
 254         int mid = ((unsigned int) min + (unsigned int) max) / 2;
 255         if (codepoint < startCount[mid])
 256           max = mid - 1;
 257         else if (codepoint > endCount[mid])
 258           min = mid + 1;
 259         else
 260         {
 261           i = mid;
 262           goto found;
 263         }
 264       }
 265       return false;
 266 
 267     found:
 268       hb_codepoint_t gid;
 269       unsigned int rangeOffset = this->idRangeOffset[i];
 270       if (rangeOffset == 0)
 271         gid = codepoint + this->idDelta[i];
 272       else
 273       {
 274         /* Somebody has been smoking... */
 275         unsigned int index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount;
 276         if (unlikely (index >= this->glyphIdArrayLength))
 277           return false;
 278         gid = this->glyphIdArray[index];
 279         if (unlikely (!gid))
 280           return false;
 281         gid += this->idDelta[i];
 282       }
 283       gid &= 0xFFFFu;
 284       if (!gid)
 285         return false;
 286       *glyph = gid;
 287       return true;
 288     }
 289     static bool get_glyph_func (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph)
 290     {
 291       return ((const accelerator_t *) obj)->get_glyph (codepoint, glyph);
 292     }
 293     void collect_unicodes (hb_set_t *out) const
 294     {
 295       unsigned int count = this->segCount;
 296       if (count && this->startCount[count - 1] == 0xFFFFu)
 297         count--; /* Skip sentinel segment. */
 298       for (unsigned int i = 0; i < count; i++)
 299       {
 300         unsigned int rangeOffset = this->idRangeOffset[i];
 301         if (rangeOffset == 0)
 302           out->add_range (this->startCount[i], this->endCount[i]);
 303         else
 304         {
 305           for (hb_codepoint_t codepoint = this->startCount[i];
 306                codepoint <= this->endCount[i];
 307                codepoint++)
 308           {
 309             unsigned int index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount;
 310             if (unlikely (index >= this->glyphIdArrayLength))
 311               break;
 312             hb_codepoint_t gid = this->glyphIdArray[index];
 313             if (unlikely (!gid))
 314               continue;
 315             out->add (codepoint);
 316           }
 317         }
 318       }
 319     }
 320 
 321     const HBUINT16 *endCount;
 322     const HBUINT16 *startCount;
 323     const HBUINT16 *idDelta;
 324     const HBUINT16 *idRangeOffset;
 325     const HBUINT16 *glyphIdArray;
 326     unsigned int segCount;
 327     unsigned int glyphIdArrayLength;
 328   };
 329 
 330   bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
 331   {
 332     accelerator_t accel (this);

 333     return accel.get_glyph_func (&accel, codepoint, glyph);
 334   }
 335   void collect_unicodes (hb_set_t *out) const
 336   {
 337     accelerator_t accel (this);
 338     accel.collect_unicodes (out);
 339   }
 340 
 341   bool sanitize (hb_sanitize_context_t *c) const
 342   {
 343     TRACE_SANITIZE (this);
 344     if (unlikely (!c->check_struct (this)))
 345       return_trace (false);
 346 
 347     if (unlikely (!c->check_range (this, length)))
 348     {
 349       /* Some broken fonts have too long of a "length" value.
 350        * If that is the case, just change the value to truncate
 351        * the subtable at the end of the blob. */
 352       uint16_t new_length = (uint16_t) MIN ((uintptr_t) 65535,
 353                                             (uintptr_t) (c->end -
 354                                                          (char *) this));
 355       if (!c->try_set (&length, new_length))
 356         return_trace (false);
 357     }
 358 
 359     return_trace (16 + 4 * (unsigned int) segCountX2 <= length);
 360   }
 361 
 362 
 363 
 364   protected:
 365   HBUINT16      format;         /* Format number is set to 4. */
 366   HBUINT16      length;         /* This is the length in bytes of the
 367                                  * subtable. */
 368   HBUINT16      language;       /* Ignore. */
 369   HBUINT16      segCountX2;     /* 2 x segCount. */
 370   HBUINT16      searchRange;    /* 2 * (2**floor(log2(segCount))) */
 371   HBUINT16      entrySelector;  /* log2(searchRange/2) */
 372   HBUINT16      rangeShift;     /* 2 x segCount - searchRange */
 373 
 374   UnsizedArrayOf<HBUINT16>
 375                 values;
 376 #if 0
 377   HBUINT16      endCount[segCount];     /* End characterCode for each segment,
 378                                          * last=0xFFFFu. */
 379   HBUINT16      reservedPad;            /* Set to 0. */
 380   HBUINT16      startCount[segCount];   /* Start character code for each segment. */
 381   HBINT16               idDelta[segCount];      /* Delta for all character codes in segment. */
 382   HBUINT16      idRangeOffset[segCount];/* Offsets into glyphIdArray or 0 */
 383   UnsizedArrayOf<HBUINT16>
 384                 glyphIdArray;   /* Glyph index array (arbitrary length) */
 385 #endif
 386 
 387   public:
 388   DEFINE_SIZE_ARRAY (14, values);
 389 };
 390 
 391 struct CmapSubtableLongGroup
 392 {
 393   friend struct CmapSubtableFormat12;
 394   friend struct CmapSubtableFormat13;
 395   template<typename U>
 396   friend struct CmapSubtableLongSegmented;
 397   friend struct cmap;
 398 
 399   int cmp (hb_codepoint_t codepoint) const
 400   {
 401     if (codepoint < startCharCode) return -1;
 402     if (codepoint > endCharCode)   return +1;
 403     return 0;
 404   }
 405 
 406   bool sanitize (hb_sanitize_context_t *c) const
 407   {
 408     TRACE_SANITIZE (this);
 409     return_trace (c->check_struct (this));
 410   }
 411 
 412   private:
 413   HBUINT32              startCharCode;  /* First character code in this group. */
 414   HBUINT32              endCharCode;    /* Last character code in this group. */
 415   HBUINT32              glyphID;        /* Glyph index; interpretation depends on
 416                                          * subtable format. */
 417   public:
 418   DEFINE_SIZE_STATIC (12);
 419 };
 420 DECLARE_NULL_NAMESPACE_BYTES (OT, CmapSubtableLongGroup);
 421 
 422 template <typename UINT>
 423 struct CmapSubtableTrimmed
 424 {
 425   bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
 426   {
 427     /* Rely on our implicit array bound-checking. */
 428     hb_codepoint_t gid = glyphIdArray[codepoint - startCharCode];
 429     if (!gid)
 430       return false;
 431     *glyph = gid;
 432     return true;
 433   }
 434   void collect_unicodes (hb_set_t *out) const
 435   {
 436     hb_codepoint_t start = startCharCode;
 437     unsigned int count = glyphIdArray.len;
 438     for (unsigned int i = 0; i < count; i++)
 439       if (glyphIdArray[i])
 440         out->add (start + i);
 441   }
 442 
 443   bool sanitize (hb_sanitize_context_t *c) const
 444   {
 445     TRACE_SANITIZE (this);
 446     return_trace (c->check_struct (this) && glyphIdArray.sanitize (c));
 447   }
 448 
 449   protected:
 450   UINT          formatReserved; /* Subtable format and (maybe) padding. */
 451   UINT          length;         /* Byte length of this subtable. */
 452   UINT          language;       /* Ignore. */
 453   UINT          startCharCode;  /* First character code covered. */
 454   ArrayOf<GlyphID, UINT>
 455                 glyphIdArray;   /* Array of glyph index values for character
 456                                  * codes in the range. */
 457   public:
 458   DEFINE_SIZE_ARRAY (5 * sizeof (UINT), glyphIdArray);
 459 };
 460 
 461 struct CmapSubtableFormat6  : CmapSubtableTrimmed<HBUINT16> {};
 462 struct CmapSubtableFormat10 : CmapSubtableTrimmed<HBUINT32 > {};
 463 
 464 template <typename T>
 465 struct CmapSubtableLongSegmented
 466 {
 467   friend struct cmap;
 468 
 469   bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
 470   {
 471     hb_codepoint_t gid = T::group_get_glyph (groups.bsearch (codepoint), codepoint);
 472     if (!gid)
 473       return false;
 474     *glyph = gid;
 475     return true;
 476   }
 477 
 478   void collect_unicodes (hb_set_t *out) const
 479   {
 480     for (unsigned int i = 0; i < this->groups.len; i++) {
 481       out->add_range (this->groups[i].startCharCode,
 482                       MIN ((hb_codepoint_t) this->groups[i].endCharCode,
 483                            (hb_codepoint_t) HB_UNICODE_MAX));
 484     }
 485   }
 486 
 487   bool sanitize (hb_sanitize_context_t *c) const
 488   {
 489     TRACE_SANITIZE (this);
 490     return_trace (c->check_struct (this) && groups.sanitize (c));
 491   }
 492 
 493   bool serialize (hb_serialize_context_t *c,
 494                   const hb_vector_t<CmapSubtableLongGroup> &group_data)
 495   {
 496     TRACE_SERIALIZE (this);
 497     if (unlikely (!c->extend_min (*this))) return_trace (false);
 498     if (unlikely (!groups.serialize (c, group_data.as_array ()))) return_trace (false);

 499     return true;
 500   }
 501 
 502   protected:
 503   HBUINT16      format;         /* Subtable format; set to 12. */
 504   HBUINT16      reserved;       /* Reserved; set to 0. */
 505   HBUINT32      length;         /* Byte length of this subtable. */
 506   HBUINT32      language;       /* Ignore. */
 507   SortedArrayOf<CmapSubtableLongGroup, HBUINT32>
 508                 groups;         /* Groupings. */
 509   public:
 510   DEFINE_SIZE_ARRAY (16, groups);
 511 };
 512 
 513 struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
 514 {
 515   static hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
 516                                          hb_codepoint_t u)
 517   { return likely (group.startCharCode <= group.endCharCode) ?
 518            group.glyphID + (u - group.startCharCode) : 0; }
 519 
 520 
 521   bool serialize (hb_serialize_context_t *c,
 522                   const hb_vector_t<CmapSubtableLongGroup> &groups)
 523   {
 524     if (unlikely (!c->extend_min (*this))) return false;
 525 
 526     this->format.set (12);
 527     this->reserved.set (0);
 528     this->length.set (get_sub_table_size (groups));
 529 
 530     return CmapSubtableLongSegmented<CmapSubtableFormat12>::serialize (c, groups);
 531   }
 532 
 533   static size_t get_sub_table_size (const hb_vector_t<CmapSubtableLongGroup> &groups)
 534   {
 535     return 16 + 12 * groups.length;
 536   }
 537 
 538   static bool create_sub_table_plan (const hb_subset_plan_t *plan,
 539                                      hb_vector_t<CmapSubtableLongGroup> *groups)
 540   {
 541     CmapSubtableLongGroup *group = nullptr;
 542 
 543     hb_codepoint_t cp = HB_SET_VALUE_INVALID;
 544     while (plan->unicodes->next (&cp)) {
 545       hb_codepoint_t new_gid;
 546       if (unlikely (!plan->new_gid_for_codepoint (cp, &new_gid)))
 547       {
 548         DEBUG_MSG(SUBSET, nullptr, "Unable to find new gid for %04x", cp);
 549         return false;
 550       }
 551 
 552       if (!group || !_is_gid_consecutive (group, cp, new_gid))
 553       {
 554         group = groups->push ();
 555         group->startCharCode.set (cp);
 556         group->endCharCode.set (cp);
 557         group->glyphID.set (new_gid);



 558       }
 559       else group->endCharCode.set (cp);
 560     }
 561 
 562     DEBUG_MSG(SUBSET, nullptr, "cmap");
 563     for (unsigned int i = 0; i < groups->length; i++) {
 564       CmapSubtableLongGroup& group = (*groups)[i];
 565       DEBUG_MSG(SUBSET, nullptr, "  %d: U+%04X-U+%04X, gid %d-%d", i, (uint32_t) group.startCharCode, (uint32_t) group.endCharCode, (uint32_t) group.glyphID, (uint32_t) group.glyphID + ((uint32_t) group.endCharCode - (uint32_t) group.startCharCode));
 566     }
 567 
 568     return true;
 569   }
 570 
 571  private:
 572   static bool _is_gid_consecutive (CmapSubtableLongGroup *group,
 573                                    hb_codepoint_t cp,
 574                                    hb_codepoint_t new_gid)
 575   {
 576     return (cp - 1 == group->endCharCode) &&
 577         new_gid == group->glyphID + (cp - group->startCharCode);
 578   }
 579 
 580 };
 581 
 582 struct CmapSubtableFormat13 : CmapSubtableLongSegmented<CmapSubtableFormat13>
 583 {
 584   static hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
 585                                          hb_codepoint_t u HB_UNUSED)
 586   { return group.glyphID; }
 587 };
 588 
 589 typedef enum
 590 {
 591   GLYPH_VARIANT_NOT_FOUND = 0,
 592   GLYPH_VARIANT_FOUND = 1,
 593   GLYPH_VARIANT_USE_DEFAULT = 2
 594 } glyph_variant_t;
 595 
 596 struct UnicodeValueRange
 597 {
 598   int cmp (const hb_codepoint_t &codepoint) const
 599   {
 600     if (codepoint < startUnicodeValue) return -1;
 601     if (codepoint > startUnicodeValue + additionalCount) return +1;
 602     return 0;
 603   }
 604 
 605   bool sanitize (hb_sanitize_context_t *c) const
 606   {
 607     TRACE_SANITIZE (this);
 608     return_trace (c->check_struct (this));
 609   }
 610 
 611   HBUINT24      startUnicodeValue;      /* First value in this range. */
 612   HBUINT8       additionalCount;        /* Number of additional values in this
 613                                          * range. */
 614   public:
 615   DEFINE_SIZE_STATIC (4);
 616 };
 617 
 618 struct DefaultUVS : SortedArrayOf<UnicodeValueRange, HBUINT32>
 619 {
 620   void collect_unicodes (hb_set_t *out) const
 621   {
 622     unsigned int count = len;
 623     for (unsigned int i = 0; i < count; i++)
 624     {
 625       hb_codepoint_t first = arrayZ[i].startUnicodeValue;
 626       hb_codepoint_t last = MIN ((hb_codepoint_t) (first + arrayZ[i].additionalCount),
 627                                  (hb_codepoint_t) HB_UNICODE_MAX);
 628       out->add_range (first, last);
 629     }
 630   }
 631 
 632   public:
 633   DEFINE_SIZE_ARRAY (4, *this);
 634 };
 635 
 636 struct UVSMapping
 637 {
 638   int cmp (const hb_codepoint_t &codepoint) const
 639   {
 640     return unicodeValue.cmp (codepoint);
 641   }
 642 
 643   bool sanitize (hb_sanitize_context_t *c) const
 644   {
 645     TRACE_SANITIZE (this);
 646     return_trace (c->check_struct (this));
 647   }
 648 
 649   HBUINT24      unicodeValue;   /* Base Unicode value of the UVS */
 650   GlyphID       glyphID;        /* Glyph ID of the UVS */
 651   public:
 652   DEFINE_SIZE_STATIC (5);
 653 };
 654 
 655 struct NonDefaultUVS : SortedArrayOf<UVSMapping, HBUINT32>
 656 {
 657   void collect_unicodes (hb_set_t *out) const
 658   {
 659     unsigned int count = len;
 660     for (unsigned int i = 0; i < count; i++)
 661       out->add (arrayZ[i].glyphID);
 662   }
 663 
 664   public:
 665   DEFINE_SIZE_ARRAY (4, *this);
 666 };
 667 
 668 struct VariationSelectorRecord
 669 {
 670   glyph_variant_t get_glyph (hb_codepoint_t codepoint,
 671                              hb_codepoint_t *glyph,
 672                              const void *base) const
 673   {
 674     if ((base+defaultUVS).bfind (codepoint))



 675       return GLYPH_VARIANT_USE_DEFAULT;
 676     const UVSMapping &nonDefault = (base+nonDefaultUVS).bsearch (codepoint);
 677     if (nonDefault.glyphID)

 678     {
 679       *glyph = nonDefault.glyphID;
 680        return GLYPH_VARIANT_FOUND;
 681     }
 682     return GLYPH_VARIANT_NOT_FOUND;
 683   }
 684 
 685   void collect_unicodes (hb_set_t *out, const void *base) const
 686   {
 687     (base+defaultUVS).collect_unicodes (out);
 688     (base+nonDefaultUVS).collect_unicodes (out);
 689   }
 690 
 691   int cmp (const hb_codepoint_t &variation_selector) const
 692   {
 693     return varSelector.cmp (variation_selector);
 694   }
 695 
 696   bool sanitize (hb_sanitize_context_t *c, const void *base) const
 697   {
 698     TRACE_SANITIZE (this);
 699     return_trace (c->check_struct (this) &&
 700                   defaultUVS.sanitize (c, base) &&
 701                   nonDefaultUVS.sanitize (c, base));
 702   }
 703 
 704   HBUINT24      varSelector;    /* Variation selector. */
 705   LOffsetTo<DefaultUVS>
 706                 defaultUVS;     /* Offset to Default UVS Table.  May be 0. */
 707   LOffsetTo<NonDefaultUVS>
 708                 nonDefaultUVS;  /* Offset to Non-Default UVS Table.  May be 0. */
 709   public:
 710   DEFINE_SIZE_STATIC (11);
 711 };
 712 
 713 struct CmapSubtableFormat14
 714 {
 715   glyph_variant_t get_glyph_variant (hb_codepoint_t codepoint,
 716                                      hb_codepoint_t variation_selector,
 717                                      hb_codepoint_t *glyph) const
 718   {
 719     return record.bsearch (variation_selector).get_glyph (codepoint, glyph, this);
 720   }
 721 
 722   void collect_variation_selectors (hb_set_t *out) const
 723   {
 724     unsigned int count = record.len;
 725     for (unsigned int i = 0; i < count; i++)
 726       out->add (record.arrayZ[i].varSelector);
 727   }
 728   void collect_variation_unicodes (hb_codepoint_t variation_selector,
 729                                    hb_set_t *out) const
 730   {
 731     record.bsearch (variation_selector).collect_unicodes (out, this);
 732   }
 733 
 734   bool sanitize (hb_sanitize_context_t *c) const
 735   {
 736     TRACE_SANITIZE (this);
 737     return_trace (c->check_struct (this) &&
 738                   record.sanitize (c, this));
 739   }
 740 
 741   protected:
 742   HBUINT16      format;         /* Format number is set to 14. */
 743   HBUINT32      length;         /* Byte length of this subtable. */
 744   SortedArrayOf<VariationSelectorRecord, HBUINT32>
 745                 record;         /* Variation selector records; sorted
 746                                  * in increasing order of `varSelector'. */
 747   public:
 748   DEFINE_SIZE_ARRAY (10, record);
 749 };
 750 
 751 struct CmapSubtable
 752 {
 753   /* Note: We intentionally do NOT implement subtable formats 2 and 8. */
 754 
 755   bool get_glyph (hb_codepoint_t codepoint,
 756                   hb_codepoint_t *glyph) const
 757   {
 758     switch (u.format) {
 759     case  0: return u.format0 .get_glyph (codepoint, glyph);
 760     case  4: return u.format4 .get_glyph (codepoint, glyph);
 761     case  6: return u.format6 .get_glyph (codepoint, glyph);
 762     case 10: return u.format10.get_glyph (codepoint, glyph);
 763     case 12: return u.format12.get_glyph (codepoint, glyph);
 764     case 13: return u.format13.get_glyph (codepoint, glyph);
 765     case 14:
 766     default: return false;
 767     }
 768   }
 769   void collect_unicodes (hb_set_t *out) const
 770   {
 771     switch (u.format) {
 772     case  0: u.format0 .collect_unicodes (out); return;
 773     case  4: u.format4 .collect_unicodes (out); return;
 774     case  6: u.format6 .collect_unicodes (out); return;
 775     case 10: u.format10.collect_unicodes (out); return;
 776     case 12: u.format12.collect_unicodes (out); return;
 777     case 13: u.format13.collect_unicodes (out); return;
 778     case 14:
 779     default: return;
 780     }
 781   }
 782 
 783   bool sanitize (hb_sanitize_context_t *c) const
 784   {
 785     TRACE_SANITIZE (this);
 786     if (!u.format.sanitize (c)) return_trace (false);
 787     switch (u.format) {
 788     case  0: return_trace (u.format0 .sanitize (c));
 789     case  4: return_trace (u.format4 .sanitize (c));
 790     case  6: return_trace (u.format6 .sanitize (c));
 791     case 10: return_trace (u.format10.sanitize (c));
 792     case 12: return_trace (u.format12.sanitize (c));
 793     case 13: return_trace (u.format13.sanitize (c));
 794     case 14: return_trace (u.format14.sanitize (c));
 795     default:return_trace (true);
 796     }
 797   }
 798 
 799   public:
 800   union {
 801   HBUINT16              format;         /* Format identifier */
 802   CmapSubtableFormat0   format0;
 803   CmapSubtableFormat4   format4;
 804   CmapSubtableFormat6   format6;
 805   CmapSubtableFormat10  format10;
 806   CmapSubtableFormat12  format12;
 807   CmapSubtableFormat13  format13;
 808   CmapSubtableFormat14  format14;
 809   } u;
 810   public:
 811   DEFINE_SIZE_UNION (2, format);
 812 };
 813 
 814 
 815 struct EncodingRecord
 816 {
 817   int cmp (const EncodingRecord &other) const
 818   {
 819     int ret;
 820     ret = platformID.cmp (other.platformID);
 821     if (ret) return ret;
 822     ret = encodingID.cmp (other.encodingID);
 823     if (ret) return ret;
 824     return 0;
 825   }
 826 
 827   bool sanitize (hb_sanitize_context_t *c, const void *base) const
 828   {
 829     TRACE_SANITIZE (this);
 830     return_trace (c->check_struct (this) &&
 831                   subtable.sanitize (c, base));
 832   }
 833 
 834   HBUINT16      platformID;     /* Platform ID. */
 835   HBUINT16      encodingID;     /* Platform-specific encoding ID. */
 836   LOffsetTo<CmapSubtable>
 837                 subtable;       /* Byte offset from beginning of table to the subtable for this encoding. */
 838   public:
 839   DEFINE_SIZE_STATIC (8);
 840 };
 841 
 842 struct cmap
 843 {
 844   static constexpr hb_tag_t tableTag = HB_OT_TAG_cmap;
 845 
 846   struct subset_plan

 847   {
 848     size_t final_size () const










 849     {
 850       return 4 // header
 851           +  8 * 3 // 3 EncodingRecord
 852           +  CmapSubtableFormat4::get_sub_table_size (this->format4_segments)
 853           +  CmapSubtableFormat12::get_sub_table_size (this->format12_groups);
 854     }
 855 

 856     hb_vector_t<CmapSubtableFormat4::segment_plan> format4_segments;

 857     hb_vector_t<CmapSubtableLongGroup> format12_groups;
 858   };
 859 
 860   bool _create_plan (const hb_subset_plan_t *plan,








 861                      subset_plan *cmap_plan) const
 862   {
 863     if (unlikely (!CmapSubtableFormat4::create_sub_table_plan (plan, &cmap_plan->format4_segments)))
 864       return false;
 865 
 866     return CmapSubtableFormat12::create_sub_table_plan (plan, &cmap_plan->format12_groups);
 867   }
 868 
 869   bool _subset (const hb_subset_plan_t *plan,
 870                 const subset_plan &cmap_subset_plan,
 871                 size_t dest_sz,
 872                 void *dest) const
 873   {
 874     hb_serialize_context_t c (dest, dest_sz);
 875 
 876     cmap *table = c.start_serialize<cmap> ();
 877     if (unlikely (!c.extend_min (*table)))
 878     {
 879       return false;
 880     }
 881 
 882     table->version.set (0);
 883 
 884     if (unlikely (!table->encodingRecord.serialize (&c, /* numTables */ 3)))
 885       return false;
 886 
 887     // TODO(grieger): Convert the below to a for loop
 888 
 889     // Format 4, Plat 0 Encoding Record
 890     EncodingRecord &format4_plat0_rec = table->encodingRecord[0];
 891     format4_plat0_rec.platformID.set (0); // Unicode
 892     format4_plat0_rec.encodingID.set (3);
 893 
 894     // Format 4, Plat 3 Encoding Record
 895     EncodingRecord &format4_plat3_rec = table->encodingRecord[1];
 896     format4_plat3_rec.platformID.set (3); // Windows
 897     format4_plat3_rec.encodingID.set (1); // Unicode BMP
 898 
 899     // Format 12 Encoding Record
 900     EncodingRecord &format12_rec = table->encodingRecord[2];
 901     format12_rec.platformID.set (3); // Windows
 902     format12_rec.encodingID.set (10); // Unicode UCS-4
 903 
 904     // Write out format 4 sub table
 905     {
 906       CmapSubtable &subtable = format4_plat0_rec.subtable.serialize (&c, table);
 907       format4_plat3_rec.subtable.set (format4_plat0_rec.subtable);
 908       subtable.u.format.set (4);
 909 
 910       CmapSubtableFormat4 &format4 = subtable.u.format4;
 911       if (unlikely (!format4.serialize (&c, plan, cmap_subset_plan.format4_segments)))
 912         return false;
 913     }
 914 
 915     // Write out format 12 sub table.
 916     {
 917       CmapSubtable &subtable = format12_rec.subtable.serialize (&c, table);
 918       subtable.u.format.set (12);
 919 
 920       CmapSubtableFormat12 &format12 = subtable.u.format12;
 921       if (unlikely (!format12.serialize (&c, cmap_subset_plan.format12_groups)))
 922         return false;
 923     }
 924 
 925     c.end_serialize ();
 926 
 927     return true;
 928   }
 929 
 930   bool subset (hb_subset_plan_t *plan) const
 931   {
 932     subset_plan cmap_subset_plan;
 933 
 934     if (unlikely (!_create_plan (plan, &cmap_subset_plan)))
 935     {
 936       DEBUG_MSG(SUBSET, nullptr, "Failed to generate a cmap subsetting plan.");
 937       return false;
 938     }
 939 
 940     // We now know how big our blob needs to be
 941     size_t dest_sz = cmap_subset_plan.final_size ();
 942     void *dest = malloc (dest_sz);
 943     if (unlikely (!dest)) {
 944       DEBUG_MSG(SUBSET, nullptr, "Unable to alloc %lu for cmap subset output", (unsigned long) dest_sz);
 945       return false;
 946     }
 947 
 948     if (unlikely (!_subset (plan, cmap_subset_plan, dest_sz, dest)))
 949     {
 950       DEBUG_MSG(SUBSET, nullptr, "Failed to perform subsetting of cmap.");
 951       free (dest);
 952       return false;
 953     }
 954 
 955     // all done, write the blob into dest
 956     hb_blob_t *cmap_prime = hb_blob_create ((const char *) dest,
 957                                             dest_sz,
 958                                             HB_MEMORY_MODE_READONLY,
 959                                             dest,
 960                                             free);
 961     bool result =  plan->add_table (HB_OT_TAG_cmap, cmap_prime);
 962     hb_blob_destroy (cmap_prime);
 963     return result;
 964   }
 965 
 966   const CmapSubtable *find_best_subtable (bool *symbol = nullptr) const
 967   {
 968     if (symbol) *symbol = false;
 969 
 970     const CmapSubtable *subtable;



 971 

 972     /* 32-bit subtables. */
 973     if ((subtable = this->find_subtable (3, 10))) return subtable;
 974     if ((subtable = this->find_subtable (0, 6))) return subtable;
 975     if ((subtable = this->find_subtable (0, 4))) return subtable;
 976 
 977     /* 16-bit subtables. */
 978     if ((subtable = this->find_subtable (3, 1))) return subtable;
 979     if ((subtable = this->find_subtable (0, 3))) return subtable;
 980     if ((subtable = this->find_subtable (0, 2))) return subtable;
 981     if ((subtable = this->find_subtable (0, 1))) return subtable;
 982     if ((subtable = this->find_subtable (0, 0))) return subtable;
 983 
 984     /* Symbol subtable. */
 985     if ((subtable = this->find_subtable (3, 0)))
 986     {
 987       if (symbol) *symbol = true;
 988       return subtable;
 989     }
 990 
 991     /* Meh. */
 992     return &Null (CmapSubtable);
 993   }
 994 
 995   struct accelerator_t
 996   {
 997     void init (hb_face_t *face)
 998     {
 999       this->table = hb_sanitize_context_t ().reference_table<cmap> (face);
1000       bool symbol;
1001       this->subtable = table->find_best_subtable (&symbol);
1002       this->subtable_uvs = &Null (CmapSubtableFormat14);
1003       {
1004         const CmapSubtable *st = table->find_subtable (0, 5);
1005         if (st && st->u.format == 14)
1006           subtable_uvs = &st->u.format14;
1007       }




1008 
1009       this->get_glyph_data = subtable;
1010       if (unlikely (symbol))
1011       {
1012         this->get_glyph_funcZ = get_glyph_from_symbol<CmapSubtable>;

1013       } else {
1014         switch (subtable->u.format) {
1015         /* Accelerate format 4 and format 12. */
1016         default:
1017           this->get_glyph_funcZ = get_glyph_from<CmapSubtable>;

1018           break;
1019         case 12:
1020           this->get_glyph_funcZ = get_glyph_from<CmapSubtableFormat12>;

1021           break;
1022         case  4:
1023           {
1024             this->format4_accel.init (&subtable->u.format4);
1025             this->get_glyph_data = &this->format4_accel;
1026             this->get_glyph_funcZ = this->format4_accel.get_glyph_func;

1027           }
1028           break;
1029         }
1030       }
1031     }
1032 
1033     void fini () { this->table.destroy (); }
1034 
1035     bool get_nominal_glyph (hb_codepoint_t  unicode,
1036                                    hb_codepoint_t *glyph) const
1037     {
1038       if (unlikely (!this->get_glyph_funcZ)) return false;
1039       return this->get_glyph_funcZ (this->get_glyph_data, unicode, glyph);
1040     }
1041     unsigned int get_nominal_glyphs (unsigned int count,
1042                                      const hb_codepoint_t *first_unicode,
1043                                      unsigned int unicode_stride,
1044                                      hb_codepoint_t *first_glyph,
1045                                      unsigned int glyph_stride) const
1046     {
1047       if (unlikely (!this->get_glyph_funcZ)) return 0;
1048 
1049       hb_cmap_get_glyph_func_t get_glyph_funcZ = this->get_glyph_funcZ;
1050       const void *get_glyph_data = this->get_glyph_data;
1051 
1052       unsigned int done;
1053       for (done = 0;
1054            done < count && get_glyph_funcZ (get_glyph_data, *first_unicode, first_glyph);
1055            done++)
1056       {
1057         first_unicode = &StructAtOffsetUnaligned<hb_codepoint_t> (first_unicode, unicode_stride);
1058         first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
1059       }
1060       return done;
1061     }
1062 
1063     bool get_variation_glyph (hb_codepoint_t  unicode,
1064                               hb_codepoint_t  variation_selector,
1065                               hb_codepoint_t *glyph) const
1066     {
1067       switch (this->subtable_uvs->get_glyph_variant (unicode,
1068                                                      variation_selector,
1069                                                      glyph))
1070       {
1071         case GLYPH_VARIANT_NOT_FOUND:   return false;
1072         case GLYPH_VARIANT_FOUND:       return true;
1073         case GLYPH_VARIANT_USE_DEFAULT: break;
1074       }
1075 
1076       return get_nominal_glyph (unicode, glyph);
1077     }
1078 
1079     void collect_unicodes (hb_set_t *out) const
1080     {
1081       subtable->collect_unicodes (out);
1082     }
1083     void collect_variation_selectors (hb_set_t *out) const
1084     {
1085       subtable_uvs->collect_variation_selectors (out);
1086     }
1087     void collect_variation_unicodes (hb_codepoint_t variation_selector,
1088                                      hb_set_t *out) const
1089     {
1090       subtable_uvs->collect_variation_unicodes (variation_selector, out);
1091     }
1092 
1093     protected:
1094     typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj,
1095                                               hb_codepoint_t codepoint,
1096                                               hb_codepoint_t *glyph);







1097 
1098     template <typename Type>
1099     static bool get_glyph_from (const void *obj,
1100                                 hb_codepoint_t codepoint,
1101                                 hb_codepoint_t *glyph)
1102     {
1103       const Type *typed_obj = (const Type *) obj;
1104       return typed_obj->get_glyph (codepoint, glyph);
1105     }
1106 
1107     template <typename Type>
1108     static bool get_glyph_from_symbol (const void *obj,








1109                                               hb_codepoint_t codepoint,
1110                                               hb_codepoint_t *glyph)
1111     {
1112       const Type *typed_obj = (const Type *) obj;
1113       if (likely (typed_obj->get_glyph (codepoint, glyph)))
1114         return true;
1115 
1116       if (codepoint <= 0x00FFu)
1117       {
1118         /* For symbol-encoded OpenType fonts, we duplicate the
1119          * U+F000..F0FF range at U+0000..U+00FF.  That's what
1120          * Windows seems to do, and that's hinted about at:
1121          * https://docs.microsoft.com/en-us/typography/opentype/spec/recom
1122          * under "Non-Standard (Symbol) Fonts". */
1123         return typed_obj->get_glyph (0xF000u + codepoint, glyph);
1124       }
1125 
1126       return false;
1127     }
1128 
1129     private:
1130     hb_nonnull_ptr_t<const CmapSubtable> subtable;
1131     hb_nonnull_ptr_t<const CmapSubtableFormat14> subtable_uvs;
1132 
1133     hb_cmap_get_glyph_func_t get_glyph_funcZ;
1134     const void *get_glyph_data;

1135 
1136     CmapSubtableFormat4::accelerator_t format4_accel;
1137 
1138     hb_blob_ptr_t<cmap> table;

1139   };
1140 
1141   protected:
1142 
1143   const CmapSubtable *find_subtable (unsigned int platform_id,
1144                                      unsigned int encoding_id) const
1145   {
1146     EncodingRecord key;
1147     key.platformID.set (platform_id);
1148     key.encodingID.set (encoding_id);
1149 
1150     const EncodingRecord &result = encodingRecord.bsearch (key);
1151     if (!result.subtable)



1152       return nullptr;
1153 
1154     return &(this+result.subtable);
1155   }
1156 
1157   public:
1158 
1159   bool sanitize (hb_sanitize_context_t *c) const
1160   {
1161     TRACE_SANITIZE (this);
1162     return_trace (c->check_struct (this) &&
1163                   likely (version == 0) &&
1164                   encodingRecord.sanitize (c, this));
1165   }
1166 
1167   protected:
1168   HBUINT16              version;        /* Table version number (0). */
1169   SortedArrayOf<EncodingRecord>
1170                         encodingRecord; /* Encoding tables. */
1171   public:
1172   DEFINE_SIZE_ARRAY (4, encodingRecord);
1173 };
1174 
1175 struct cmap_accelerator_t : cmap::accelerator_t {};
1176 
1177 } /* namespace OT */
1178 
1179 
1180 #endif /* HB_OT_CMAP_TABLE_HH */
< prev index next >