src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-cmap-table.hh
changeset 50826 f5b95be8b6e2
parent 50352 25db2c8f3cf8
child 54232 7c11a7cc7c1d
equal deleted inserted replaced
50825:aa0a35b071fb 50826:f5b95be8b6e2
    26 
    26 
    27 #ifndef HB_OT_CMAP_TABLE_HH
    27 #ifndef HB_OT_CMAP_TABLE_HH
    28 #define HB_OT_CMAP_TABLE_HH
    28 #define HB_OT_CMAP_TABLE_HH
    29 
    29 
    30 #include "hb-open-type-private.hh"
    30 #include "hb-open-type-private.hh"
       
    31 #include "hb-set-private.hh"
    31 #include "hb-subset-plan.hh"
    32 #include "hb-subset-plan.hh"
    32 
    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 
    33 namespace OT {
    41 namespace OT {
    34 
       
    35 
       
    36 /*
       
    37  * cmap -- Character To Glyph Index Mapping Table
       
    38  */
       
    39 
       
    40 #define HB_OT_TAG_cmap HB_TAG('c','m','a','p')
       
    41 
    42 
    42 
    43 
    43 struct CmapSubtableFormat0
    44 struct CmapSubtableFormat0
    44 {
    45 {
    45   inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
    46   inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
    57     return_trace (c->check_struct (this));
    58     return_trace (c->check_struct (this));
    58   }
    59   }
    59 
    60 
    60   protected:
    61   protected:
    61   HBUINT16      format;         /* Format number is set to 0. */
    62   HBUINT16      format;         /* Format number is set to 0. */
    62   HBUINT16      lengthZ;        /* Byte length of this subtable. */
    63   HBUINT16      length;         /* Byte length of this subtable. */
    63   HBUINT16      languageZ;      /* Ignore. */
    64   HBUINT16      language;       /* Ignore. */
    64   HBUINT8       glyphIdArray[256];/* An array that maps character
    65   HBUINT8       glyphIdArray[256];/* An array that maps character
    65                                  * code to glyph index values. */
    66                                  * code to glyph index values. */
    66   public:
    67   public:
    67   DEFINE_SIZE_STATIC (6 + 256);
    68   DEFINE_SIZE_STATIC (6 + 256);
    68 };
    69 };
    69 
    70 
    70 struct CmapSubtableFormat4
    71 struct CmapSubtableFormat4
    71 {
    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)
       
   128         // + (id_range_offset + i)
       
   129         // =
       
   130         // glyph_id_array + (cp - segments[i].start_code)
       
   131         //
       
   132         // So, solve for id_range_offset[i]:
       
   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 
    72   struct accelerator_t
   225   struct accelerator_t
    73   {
   226   {
    74     inline void init (const CmapSubtableFormat4 *subtable)
   227     inline void init (const CmapSubtableFormat4 *subtable)
    75     {
   228     {
    76       segCount = subtable->segCountX2 / 2;
   229       segCount = subtable->segCountX2 / 2;
   125 
   278 
   126       *glyph = gid & 0xFFFFu;
   279       *glyph = gid & 0xFFFFu;
   127       return true;
   280       return true;
   128     }
   281     }
   129 
   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 
   130     const HBUINT16 *endCount;
   294     const HBUINT16 *endCount;
   131     const HBUINT16 *startCount;
   295     const HBUINT16 *startCount;
   132     const HBUINT16 *idDelta;
   296     const HBUINT16 *idDelta;
   133     const HBUINT16 *idRangeOffset;
   297     const HBUINT16 *idRangeOffset;
   134     const HBUINT16 *glyphIdArray;
   298     const HBUINT16 *glyphIdArray;
   162     }
   326     }
   163 
   327 
   164     return_trace (16 + 4 * (unsigned int) segCountX2 <= length);
   328     return_trace (16 + 4 * (unsigned int) segCountX2 <= length);
   165   }
   329   }
   166 
   330 
       
   331 
       
   332 
   167   protected:
   333   protected:
   168   HBUINT16      format;         /* Format number is set to 4. */
   334   HBUINT16      format;         /* Format number is set to 4. */
   169   HBUINT16      length;         /* This is the length in bytes of the
   335   HBUINT16      length;         /* This is the length in bytes of the
   170                                  * subtable. */
   336                                  * subtable. */
   171   HBUINT16      languageZ;      /* Ignore. */
   337   HBUINT16      language;       /* Ignore. */
   172   HBUINT16      segCountX2;     /* 2 x segCount. */
   338   HBUINT16      segCountX2;     /* 2 x segCount. */
   173   HBUINT16      searchRangeZ;   /* 2 * (2**floor(log2(segCount))) */
   339   HBUINT16      searchRange;    /* 2 * (2**floor(log2(segCount))) */
   174   HBUINT16      entrySelectorZ; /* log2(searchRange/2) */
   340   HBUINT16      entrySelector;  /* log2(searchRange/2) */
   175   HBUINT16      rangeShiftZ;    /* 2 x segCount - searchRange */
   341   HBUINT16      rangeShift;     /* 2 x segCount - searchRange */
   176 
   342 
   177   HBUINT16      values[VAR];
   343   HBUINT16      values[VAR];
   178 #if 0
   344 #if 0
   179   HBUINT16      endCount[segCount];     /* End characterCode for each segment,
   345   HBUINT16      endCount[segCount];     /* End characterCode for each segment,
   180                                          * last=0xFFFFu. */
   346                                          * last=0xFFFFu. */
   191 
   357 
   192 struct CmapSubtableLongGroup
   358 struct CmapSubtableLongGroup
   193 {
   359 {
   194   friend struct CmapSubtableFormat12;
   360   friend struct CmapSubtableFormat12;
   195   friend struct CmapSubtableFormat13;
   361   friend struct CmapSubtableFormat13;
       
   362   template<typename U>
       
   363   friend struct CmapSubtableLongSegmented;
   196   friend struct cmap;
   364   friend struct cmap;
   197 
   365 
   198   int cmp (hb_codepoint_t codepoint) const
   366   int cmp (hb_codepoint_t codepoint) const
   199   {
   367   {
   200     if (codepoint < startCharCode) return -1;
   368     if (codepoint < startCharCode) return -1;
   236     return_trace (c->check_struct (this) && glyphIdArray.sanitize (c));
   404     return_trace (c->check_struct (this) && glyphIdArray.sanitize (c));
   237   }
   405   }
   238 
   406 
   239   protected:
   407   protected:
   240   UINT          formatReserved; /* Subtable format and (maybe) padding. */
   408   UINT          formatReserved; /* Subtable format and (maybe) padding. */
   241   UINT          lengthZ;        /* Byte length of this subtable. */
   409   UINT          length;         /* Byte length of this subtable. */
   242   UINT          languageZ;      /* Ignore. */
   410   UINT          language;       /* Ignore. */
   243   UINT          startCharCode;  /* First character code covered. */
   411   UINT          startCharCode;  /* First character code covered. */
   244   ArrayOf<GlyphID, UINT>
   412   ArrayOf<GlyphID, UINT>
   245                 glyphIdArray;   /* Array of glyph index values for character
   413                 glyphIdArray;   /* Array of glyph index values for character
   246                                  * codes in the range. */
   414                                  * codes in the range. */
   247   public:
   415   public:
   263       return false;
   431       return false;
   264     *glyph = T::group_get_glyph (groups[i], codepoint);
   432     *glyph = T::group_get_glyph (groups[i], codepoint);
   265     return true;
   433     return true;
   266   }
   434   }
   267 
   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 
   268   inline bool sanitize (hb_sanitize_context_t *c) const
   445   inline bool sanitize (hb_sanitize_context_t *c) const
   269   {
   446   {
   270     TRACE_SANITIZE (this);
   447     TRACE_SANITIZE (this);
   271     return_trace (c->check_struct (this) && groups.sanitize (c));
   448     return_trace (c->check_struct (this) && groups.sanitize (c));
   272   }
   449   }
   273 
   450 
   274   inline bool serialize (hb_serialize_context_t *c,
   451   inline bool serialize (hb_serialize_context_t *c,
   275                          hb_prealloced_array_t<CmapSubtableLongGroup> &group_data)
   452                          const hb_vector_t<CmapSubtableLongGroup> &group_data)
   276   {
   453   {
   277     TRACE_SERIALIZE (this);
   454     TRACE_SERIALIZE (this);
   278     if (unlikely (!c->extend_min (*this))) return_trace (false);
   455     if (unlikely (!c->extend_min (*this))) return_trace (false);
   279     Supplier<CmapSubtableLongGroup> supplier (group_data.array, group_data.len);
   456     Supplier<CmapSubtableLongGroup> supplier (group_data.arrayZ, group_data.len);
   280     if (unlikely (!groups.serialize (c, supplier, group_data.len))) return_trace (false);
   457     if (unlikely (!groups.serialize (c, supplier, group_data.len))) return_trace (false);
   281     return true;
   458     return true;
   282   }
   459   }
   283 
   460 
   284   protected:
   461   protected:
   285   HBUINT16      format;         /* Subtable format; set to 12. */
   462   HBUINT16      format;         /* Subtable format; set to 12. */
   286   HBUINT16      reservedZ;      /* Reserved; set to 0. */
   463   HBUINT16      reserved;       /* Reserved; set to 0. */
   287   HBUINT32              lengthZ;        /* Byte length of this subtable. */
   464   HBUINT32      length;         /* Byte length of this subtable. */
   288   HBUINT32              languageZ;      /* Ignore. */
   465   HBUINT32      language;       /* Ignore. */
   289   SortedArrayOf<CmapSubtableLongGroup, HBUINT32>
   466   SortedArrayOf<CmapSubtableLongGroup, HBUINT32>
   290                 groups;         /* Groupings. */
   467                 groups;         /* Groupings. */
   291   public:
   468   public:
   292   DEFINE_SIZE_ARRAY (16, groups);
   469   DEFINE_SIZE_ARRAY (16, groups);
   293 };
   470 };
   295 struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
   472 struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
   296 {
   473 {
   297   static inline hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
   474   static inline hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
   298                                                 hb_codepoint_t u)
   475                                                 hb_codepoint_t u)
   299   { return group.glyphID + (u - group.startCharCode); }
   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 
   300 };
   540 };
   301 
   541 
   302 struct CmapSubtableFormat13 : CmapSubtableLongSegmented<CmapSubtableFormat13>
   542 struct CmapSubtableFormat13 : CmapSubtableLongSegmented<CmapSubtableFormat13>
   303 {
   543 {
   304   static inline hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
   544   static inline hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
   326   {
   566   {
   327     TRACE_SANITIZE (this);
   567     TRACE_SANITIZE (this);
   328     return_trace (c->check_struct (this));
   568     return_trace (c->check_struct (this));
   329   }
   569   }
   330 
   570 
   331   UINT24        startUnicodeValue;      /* First value in this range. */
   571   HBUINT24      startUnicodeValue;      /* First value in this range. */
   332   HBUINT8               additionalCount;        /* Number of additional values in this
   572   HBUINT8               additionalCount;        /* Number of additional values in this
   333                                          * range. */
   573                                          * range. */
   334   public:
   574   public:
   335   DEFINE_SIZE_STATIC (4);
   575   DEFINE_SIZE_STATIC (4);
   336 };
   576 };
   348   {
   588   {
   349     TRACE_SANITIZE (this);
   589     TRACE_SANITIZE (this);
   350     return_trace (c->check_struct (this));
   590     return_trace (c->check_struct (this));
   351   }
   591   }
   352 
   592 
   353   UINT24        unicodeValue;   /* Base Unicode value of the UVS */
   593   HBUINT24      unicodeValue;   /* Base Unicode value of the UVS */
   354   GlyphID       glyphID;        /* Glyph ID of the UVS */
   594   GlyphID       glyphID;        /* Glyph ID of the UVS */
   355   public:
   595   public:
   356   DEFINE_SIZE_STATIC (5);
   596   DEFINE_SIZE_STATIC (5);
   357 };
   597 };
   358 
   598 
   390     return_trace (c->check_struct (this) &&
   630     return_trace (c->check_struct (this) &&
   391                   defaultUVS.sanitize (c, base) &&
   631                   defaultUVS.sanitize (c, base) &&
   392                   nonDefaultUVS.sanitize (c, base));
   632                   nonDefaultUVS.sanitize (c, base));
   393   }
   633   }
   394 
   634 
   395   UINT24        varSelector;    /* Variation selector. */
   635   HBUINT24      varSelector;    /* Variation selector. */
   396   LOffsetTo<DefaultUVS>
   636   LOffsetTo<DefaultUVS>
   397                 defaultUVS;     /* Offset to Default UVS Table. May be 0. */
   637                 defaultUVS;     /* Offset to Default UVS Table. May be 0. */
   398   LOffsetTo<NonDefaultUVS>
   638   LOffsetTo<NonDefaultUVS>
   399                 nonDefaultUVS;  /* Offset to Non-Default UVS Table. May be 0. */
   639                 nonDefaultUVS;  /* Offset to Non-Default UVS Table. May be 0. */
   400   public:
   640   public:
   417                   record.sanitize (c, this));
   657                   record.sanitize (c, this));
   418   }
   658   }
   419 
   659 
   420   protected:
   660   protected:
   421   HBUINT16      format;         /* Format number is set to 14. */
   661   HBUINT16      format;         /* Format number is set to 14. */
   422   HBUINT32              lengthZ;        /* Byte length of this subtable. */
   662   HBUINT32      length;         /* Byte length of this subtable. */
   423   SortedArrayOf<VariationSelectorRecord, HBUINT32>
   663   SortedArrayOf<VariationSelectorRecord, HBUINT32>
   424                 record;         /* Variation selector records; sorted
   664                 record;         /* Variation selector records; sorted
   425                                  * in increasing order of `varSelector'. */
   665                                  * in increasing order of `varSelector'. */
   426   public:
   666   public:
   427   DEFINE_SIZE_ARRAY (10, record);
   667   DEFINE_SIZE_ARRAY (10, record);
   507 
   747 
   508 struct cmap
   748 struct cmap
   509 {
   749 {
   510   static const hb_tag_t tableTag        = HB_OT_TAG_cmap;
   750   static const hb_tag_t tableTag        = HB_OT_TAG_cmap;
   511 
   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 
   512   inline bool sanitize (hb_sanitize_context_t *c) const
   779   inline bool sanitize (hb_sanitize_context_t *c) const
   513   {
   780   {
   514     TRACE_SANITIZE (this);
   781     TRACE_SANITIZE (this);
   515     return_trace (c->check_struct (this) &&
   782     return_trace (c->check_struct (this) &&
   516                   likely (version == 0) &&
   783                   likely (version == 0) &&
   517                   encodingRecord.sanitize (c, this));
   784                   encodingRecord.sanitize (c, this));
   518   }
   785   }
   519 
   786 
   520   inline bool populate_groups (hb_subset_plan_t *plan,
   787   inline bool _create_plan (const hb_subset_plan_t *plan,
   521                                hb_prealloced_array_t<CmapSubtableLongGroup> *groups) const
   788                             subset_plan *cmap_plan) const
   522   {
   789   {
   523     CmapSubtableLongGroup *group = nullptr;
   790     if (unlikely( !CmapSubtableFormat4::create_sub_table_plan (plan, &cmap_plan->format4_segments)))
   524     for (unsigned int i = 0; i < plan->codepoints.len; i++) {
   791       return false;
   525 
   792 
   526       hb_codepoint_t cp = plan->codepoints[i];
   793     return CmapSubtableFormat12::create_sub_table_plan (plan, &cmap_plan->format12_groups);
   527       if (!group || cp - 1 != group->endCharCode)
   794   }
   528       {
   795 
   529         group = groups->push ();
   796   inline bool _subset (const hb_subset_plan_t *plan,
   530         group->startCharCode.set (cp);
   797                        const subset_plan &cmap_subset_plan,
   531         group->endCharCode.set (cp);
       
   532         hb_codepoint_t new_gid;
       
   533         if (unlikely (!hb_subset_plan_new_gid_for_codepoint (plan, cp, &new_gid)))
       
   534         {
       
   535           DEBUG_MSG(SUBSET, nullptr, "Unable to find new gid for %04x", cp);
       
   536           return false;
       
   537         }
       
   538         group->glyphID.set (new_gid);
       
   539       } else
       
   540       {
       
   541         group->endCharCode.set (cp);
       
   542       }
       
   543     }
       
   544 
       
   545     DEBUG_MSG(SUBSET, nullptr, "cmap");
       
   546     for (unsigned int i = 0; i < groups->len; i++) {
       
   547       CmapSubtableLongGroup& group = (*groups)[i];
       
   548       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));
       
   549     }
       
   550 
       
   551     return true;
       
   552   }
       
   553 
       
   554   inline bool _subset (hb_prealloced_array_t<CmapSubtableLongGroup> &groups,
       
   555                        size_t dest_sz,
   798                        size_t dest_sz,
   556                        void *dest) const
   799                        void *dest) const
   557   {
   800   {
   558     hb_serialize_context_t c (dest, dest_sz);
   801     hb_serialize_context_t c (dest, dest_sz);
   559 
   802 
   563       return false;
   806       return false;
   564     }
   807     }
   565 
   808 
   566     cmap->version.set (0);
   809     cmap->version.set (0);
   567 
   810 
   568     if (unlikely (!cmap->encodingRecord.serialize (&c, /* numTables */ 1))) return false;
   811     if (unlikely (!cmap->encodingRecord.serialize (&c, /* numTables */ 3)))
   569 
   812       return false;
   570     EncodingRecord &rec = cmap->encodingRecord[0];
   813 
   571     rec.platformID.set (3); // Windows
   814     // TODO(grieger): Convert the below to a for loop
   572     rec.encodingID.set (10); // Unicode UCS-4
   815 
   573 
   816     // Format 4, Plat 0 Encoding Record
   574     /* capture offset to subtable */
   817     EncodingRecord &format4_plat0_rec = cmap->encodingRecord[0];
   575     CmapSubtable &subtable = rec.subtable.serialize (&c, cmap);
   818     format4_plat0_rec.platformID.set (0); // Unicode
   576 
   819     format4_plat0_rec.encodingID.set (3);
   577     subtable.u.format.set (12);
   820 
   578 
   821     // Format 4, Plat 3 Encoding Record
   579     CmapSubtableFormat12 &format12 = subtable.u.format12;
   822     EncodingRecord &format4_plat3_rec = cmap->encodingRecord[1];
   580     if (unlikely (!c.extend_min (format12))) return false;
   823     format4_plat3_rec.platformID.set (3); // Windows
   581 
   824     format4_plat3_rec.encodingID.set (1); // Unicode BMP
   582     format12.format.set (12);
   825 
   583     format12.reservedZ.set (0);
   826     // Format 12 Encoding Record
   584     format12.lengthZ.set (16 + 12 * groups.len);
   827     EncodingRecord &format12_rec = cmap->encodingRecord[2];
   585 
   828     format12_rec.platformID.set (3); // Windows
   586     if (unlikely (!format12.serialize (&c, groups))) return false;
   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     }
   587 
   851 
   588     c.end_serialize ();
   852     c.end_serialize ();
   589 
   853 
   590     return true;
   854     return true;
   591   }
   855   }
   592 
   856 
   593   inline bool subset (hb_subset_plan_t *plan) const
   857   inline bool subset (hb_subset_plan_t *plan) const
   594   {
   858   {
   595     hb_auto_array_t<CmapSubtableLongGroup> groups;
   859     subset_plan cmap_subset_plan;
   596 
   860 
   597     if (unlikely (!populate_groups (plan, &groups))) return false;
   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     }
   598 
   866 
   599     // We now know how big our blob needs to be
   867     // We now know how big our blob needs to be
   600     // TODO use APIs from the structs to get size?
   868     size_t dest_sz = cmap_subset_plan.final_size();
   601     size_t dest_sz = 4 // header
       
   602                    + 8 // 1 EncodingRecord
       
   603                    + 16 // Format 12 header
       
   604                    + 12 * groups.len; // SequentialMapGroup records
       
   605     void *dest = malloc (dest_sz);
   869     void *dest = malloc (dest_sz);
   606     if (unlikely (!dest)) {
   870     if (unlikely (!dest)) {
   607       DEBUG_MSG(SUBSET, nullptr, "Unable to alloc %lu for cmap subset output", (unsigned long) dest_sz);
   871       DEBUG_MSG(SUBSET, nullptr, "Unable to alloc %lu for cmap subset output", (unsigned long) dest_sz);
   608       return false;
   872       return false;
   609     }
   873     }
   610 
   874 
   611     if (unlikely (!_subset (groups, dest_sz, dest)))
   875     if (unlikely (!_subset (plan, cmap_subset_plan, dest_sz, dest)))
   612     {
   876     {
       
   877       DEBUG_MSG(SUBSET, nullptr, "Failed to perform subsetting of cmap.");
   613       free (dest);
   878       free (dest);
   614       return false;
   879       return false;
   615     }
   880     }
   616 
   881 
   617     // all done, write the blob into dest
   882     // all done, write the blob into dest
   618     hb_blob_t *cmap_prime = hb_blob_create ((const char *)dest,
   883     hb_blob_t *cmap_prime = hb_blob_create ((const char *)dest,
   619                                             dest_sz,
   884                                             dest_sz,
   620                                             HB_MEMORY_MODE_READONLY,
   885                                             HB_MEMORY_MODE_READONLY,
   621                                             dest,
   886                                             dest,
   622                                             free);
   887                                             free);
   623     bool result =  hb_subset_plan_add_table (plan, HB_OT_TAG_cmap, cmap_prime);
   888     bool result =  plan->add_table (HB_OT_TAG_cmap, cmap_prime);
   624     hb_blob_destroy (cmap_prime);
   889     hb_blob_destroy (cmap_prime);
   625     return result;
   890     return result;
   626   }
   891   }
   627 
   892 
   628   struct accelerator_t
   893   struct accelerator_t
   629   {
   894   {
   630     inline void init (hb_face_t *face)
   895     inline void init (hb_face_t *face)
   631     {
   896     {
   632       this->blob = OT::Sanitizer<OT::cmap>().sanitize (face->reference_table (HB_OT_TAG_cmap));
   897       this->blob = OT::Sanitizer<OT::cmap>().sanitize (face->reference_table (HB_OT_TAG_cmap));
   633       const OT::cmap *cmap = OT::Sanitizer<OT::cmap>::lock_instance (this->blob);
   898       const OT::cmap *cmap = this->blob->as<OT::cmap> ();
   634       const OT::CmapSubtable *subtable = nullptr;
   899       const OT::CmapSubtable *subtable = nullptr;
   635       const OT::CmapSubtableFormat14 *subtable_uvs = nullptr;
   900       const OT::CmapSubtableFormat14 *subtable_uvs = nullptr;
   636 
   901 
   637       bool symbol = false;
   902       bool symbol = false;
   638       /* 32-bit subtables. */
   903       /* 32-bit subtables. */
   649       {
   914       {
   650         subtable = cmap->find_subtable (3, 0);
   915         subtable = cmap->find_subtable (3, 0);
   651         if (subtable) symbol = true;
   916         if (subtable) symbol = true;
   652       }
   917       }
   653       /* Meh. */
   918       /* Meh. */
   654       if (!subtable) subtable = &OT::Null(OT::CmapSubtable);
   919       if (!subtable) subtable = &Null(OT::CmapSubtable);
   655 
   920 
   656       /* UVS subtable. */
   921       /* UVS subtable. */
   657       if (!subtable_uvs)
   922       if (!subtable_uvs)
   658       {
   923       {
   659         const OT::CmapSubtable *st = cmap->find_subtable (0, 5);
   924         const OT::CmapSubtable *st = cmap->find_subtable (0, 5);
   660         if (st && st->u.format == 14)
   925         if (st && st->u.format == 14)
   661           subtable_uvs = &st->u.format14;
   926           subtable_uvs = &st->u.format14;
   662       }
   927       }
   663       /* Meh. */
   928       /* Meh. */
   664       if (!subtable_uvs) subtable_uvs = &OT::Null(OT::CmapSubtableFormat14);
   929       if (!subtable_uvs) subtable_uvs = &Null(OT::CmapSubtableFormat14);
   665 
   930 
   666       this->uvs_table = subtable_uvs;
   931       this->uvs_table = subtable_uvs;
   667 
   932 
   668       this->get_glyph_data = subtable;
   933       this->get_glyph_data = subtable;
   669       if (unlikely (symbol))
   934       if (unlikely (symbol))
       
   935       {
   670         this->get_glyph_func = get_glyph_from_symbol<OT::CmapSubtable>;
   936         this->get_glyph_func = get_glyph_from_symbol<OT::CmapSubtable>;
   671       else
   937         this->get_all_codepoints_func = null_get_all_codepoints_func;
       
   938       } else {
   672         switch (subtable->u.format) {
   939         switch (subtable->u.format) {
   673         /* Accelerate format 4 and format 12. */
   940         /* Accelerate format 4 and format 12. */
   674         default: this->get_glyph_func = get_glyph_from<OT::CmapSubtable>;               break;
   941         default:
   675         case 12: this->get_glyph_func = get_glyph_from<OT::CmapSubtableFormat12>;       break;
   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;
   676         case  4:
   949         case  4:
   677           {
   950           {
   678             this->format4_accel.init (&subtable->u.format4);
   951             this->format4_accel.init (&subtable->u.format4);
   679             this->get_glyph_data = &this->format4_accel;
   952             this->get_glyph_data = &this->format4_accel;
   680             this->get_glyph_func = this->format4_accel.get_glyph_func;
   953             this->get_glyph_func = this->format4_accel.get_glyph_func;
       
   954             this->get_all_codepoints_func = this->format4_accel.get_all_codepoints_func;
   681           }
   955           }
   682           break;
   956           break;
   683         }
   957         }
       
   958       }
   684     }
   959     }
   685 
   960 
   686     inline void fini (void)
   961     inline void fini (void)
   687     {
   962     {
   688       hb_blob_destroy (this->blob);
   963       hb_blob_destroy (this->blob);
   706         case OT::GLYPH_VARIANT_FOUND:           return true;
   981         case OT::GLYPH_VARIANT_FOUND:           return true;
   707         case OT::GLYPH_VARIANT_USE_DEFAULT:     break;
   982         case OT::GLYPH_VARIANT_USE_DEFAULT:     break;
   708       }
   983       }
   709 
   984 
   710       return get_nominal_glyph (unicode, glyph);
   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);
   711     }
   991     }
   712 
   992 
   713     protected:
   993     protected:
   714     typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj,
   994     typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj,
   715                                               hb_codepoint_t codepoint,
   995                                               hb_codepoint_t codepoint,
   716                                               hb_codepoint_t *glyph);
   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     }
   717 
  1004 
   718     template <typename Type>
  1005     template <typename Type>
   719     static inline bool get_glyph_from (const void *obj,
  1006     static inline bool get_glyph_from (const void *obj,
   720                                        hb_codepoint_t codepoint,
  1007                                        hb_codepoint_t codepoint,
   721                                        hb_codepoint_t *glyph)
  1008                                        hb_codepoint_t *glyph)
   723       const Type *typed_obj = (const Type *) obj;
  1010       const Type *typed_obj = (const Type *) obj;
   724       return typed_obj->get_glyph (codepoint, glyph);
  1011       return typed_obj->get_glyph (codepoint, glyph);
   725     }
  1012     }
   726 
  1013 
   727     template <typename Type>
  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>
   728     static inline bool get_glyph_from_symbol (const void *obj,
  1023     static inline bool get_glyph_from_symbol (const void *obj,
   729                                               hb_codepoint_t codepoint,
  1024                                               hb_codepoint_t codepoint,
   730                                               hb_codepoint_t *glyph)
  1025                                               hb_codepoint_t *glyph)
   731     {
  1026     {
   732       const Type *typed_obj = (const Type *) obj;
  1027       const Type *typed_obj = (const Type *) obj;
   736       if (codepoint <= 0x00FFu)
  1031       if (codepoint <= 0x00FFu)
   737       {
  1032       {
   738         /* For symbol-encoded OpenType fonts, we duplicate the
  1033         /* For symbol-encoded OpenType fonts, we duplicate the
   739          * U+F000..F0FF range at U+0000..U+00FF.  That's what
  1034          * U+F000..F0FF range at U+0000..U+00FF.  That's what
   740          * Windows seems to do, and that's hinted about at:
  1035          * Windows seems to do, and that's hinted about at:
   741          * http://www.microsoft.com/typography/otspec/recom.htm
  1036          * https://docs.microsoft.com/en-us/typography/opentype/spec/recom
   742          * under "Non-Standard (Symbol) Fonts". */
  1037          * under "Non-Standard (Symbol) Fonts". */
   743         return typed_obj->get_glyph (0xF000u + codepoint, glyph);
  1038         return typed_obj->get_glyph (0xF000u + codepoint, glyph);
   744       }
  1039       }
   745 
  1040 
   746       return false;
  1041       return false;
   747     }
  1042     }
   748 
  1043 
   749     private:
  1044     private:
   750     hb_cmap_get_glyph_func_t get_glyph_func;
  1045     hb_cmap_get_glyph_func_t get_glyph_func;
   751     const void *get_glyph_data;
  1046     const void *get_glyph_data;
       
  1047     hb_cmap_get_all_codepoints_func_t get_all_codepoints_func;
       
  1048 
   752     OT::CmapSubtableFormat4::accelerator_t format4_accel;
  1049     OT::CmapSubtableFormat4::accelerator_t format4_accel;
   753 
  1050 
   754     const OT::CmapSubtableFormat14 *uvs_table;
  1051     const OT::CmapSubtableFormat14 *uvs_table;
   755     hb_blob_t *blob;
  1052     hb_blob_t *blob;
   756   };
  1053   };