2 * Copyright © 2014 Google, Inc.
4 * This is part of HarfBuzz, a text shaping library.
6 * Permission is hereby granted, without written agreement and without
7 * license or royalty fees, to use, copy, modify, and distribute this
8 * software and its documentation for any purpose, provided that the
9 * above copyright notice and the following two paragraphs appear in
10 * all copies of this software.
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
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.
24 * Google Author(s): Behdad Esfahbod
27 #ifndef HB_OT_CMAP_TABLE_HH
28 #define HB_OT_CMAP_TABLE_HH
30 #include "hb-open-type-private.hh"
31 #include "hb-set-private.hh"
32 #include "hb-subset-plan.hh"
35 * cmap -- Character to Glyph Index Mapping
36 * https://docs.microsoft.com/en-us/typography/opentype/spec/cmap
38 #define HB_OT_TAG_cmap HB_TAG('c','m','a','p')
44 struct CmapSubtableFormat0
46 inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
48 hb_codepoint_t gid = codepoint < 256 ? glyphIdArray[codepoint] : 0;
55 inline bool sanitize (hb_sanitize_context_t *c) const
57 TRACE_SANITIZE (this);
58 return_trace (c->check_struct (this));
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. */
68 DEFINE_SIZE_STATIC (6 + 256);
71 struct CmapSubtableFormat4
80 bool serialize (hb_serialize_context_t *c,
81 const hb_subset_plan_t *plan,
82 const hb_vector_t<segment_plan> &segments)
84 TRACE_SERIALIZE (this);
86 if (unlikely (!c->extend_min (*this))) return_trace (false);
89 this->length.set (get_sub_table_size (segments));
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
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);
104 if (id_range_offset == nullptr)
105 return_trace (false);
107 for (unsigned int i = 0; i < segments.len; i++)
109 end_count[i].set (segments[i].end_code);
110 start_count[i].set (segments[i].start_code);
111 if (segments[i].use_delta)
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);
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:
126 // id_range_offset[i]/2
127 // + (cp - segments[i].start_code)
128 // + (id_range_offset + i)
130 // glyph_id_array + (cp - segments[i].start_code)
132 // So, solve for id_range_offset[i]:
134 // id_range_offset[i]
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++)
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);
153 static inline size_t get_sub_table_size (const hb_vector_t<segment_plan> &segments)
155 size_t segment_size = 0;
156 for (unsigned int i = 0; i < segments.len; i++)
158 // Parallel array entries
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;
175 static inline bool create_sub_table_plan (const hb_subset_plan_t *plan,
176 hb_vector_t<segment_plan> *segments)
178 segment_plan *segment = nullptr;
179 hb_codepoint_t last_gid = 0;
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)))
186 DEBUG_MSG(SUBSET, nullptr, "Unable to find new gid for %04x", cp);
191 // We are now outside of unicode BMP, stop adding to this cmap.
196 || cp != segment->end_code + 1u)
198 segment = segments->push ();
199 segment->start_code.set (cp);
200 segment->end_code.set (cp);
201 segment->use_delta = true;
203 segment->end_code.set (cp);
204 if (last_gid + 1u != new_gid)
205 // gid's are not consecutive in this segment so delta
207 segment->use_delta = false;
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)
216 segment = segments->push ();
217 segment->start_code.set (0xFFFF);
218 segment->end_code.set (0xFFFF);
219 segment->use_delta = true;
227 inline void init (const CmapSubtableFormat4 *subtable)
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;
238 static inline bool get_glyph_func (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph)
240 const accelerator_t *thiz = (const accelerator_t *) obj;
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;
249 int mid = (min + max) / 2;
250 if (codepoint < startCount[mid])
252 else if (codepoint > endCount[mid])
264 unsigned int rangeOffset = thiz->idRangeOffset[i];
265 if (rangeOffset == 0)
266 gid = codepoint + thiz->idDelta[i];
269 /* Somebody has been smoking... */
270 unsigned int index = rangeOffset / 2 + (codepoint - thiz->startCount[i]) + i - thiz->segCount;
271 if (unlikely (index >= thiz->glyphIdArrayLength))
273 gid = thiz->glyphIdArray[index];
276 gid += thiz->idDelta[i];
279 *glyph = gid & 0xFFFFu;
283 static inline void get_all_codepoints_func (const void *obj, hb_set_t *out)
285 const accelerator_t *thiz = (const accelerator_t *) obj;
286 for (unsigned int i = 0; i < thiz->segCount; i++)
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]);
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;
303 inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
307 return accel.get_glyph_func (&accel, codepoint, glyph);
310 inline bool sanitize (hb_sanitize_context_t *c) const
312 TRACE_SANITIZE (this);
313 if (unlikely (!c->check_struct (this)))
314 return_trace (false);
316 if (unlikely (!c->check_range (this, length)))
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 -
324 if (!c->try_set (&length, new_length))
325 return_trace (false);
328 return_trace (16 + 4 * (unsigned int) segCountX2 <= length);
334 HBUINT16 format; /* Format number is set to 4. */
335 HBUINT16 length; /* This is the length in bytes of the
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 */
343 HBUINT16 values[VAR];
345 HBUINT16 endCount[segCount]; /* End characterCode for each segment,
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) */
355 DEFINE_SIZE_ARRAY (14, values);
358 struct CmapSubtableLongGroup
360 friend struct CmapSubtableFormat12;
361 friend struct CmapSubtableFormat13;
363 friend struct CmapSubtableLongSegmented;
366 int cmp (hb_codepoint_t codepoint) const
368 if (codepoint < startCharCode) return -1;
369 if (codepoint > endCharCode) return +1;
373 inline bool sanitize (hb_sanitize_context_t *c) const
375 TRACE_SANITIZE (this);
376 return_trace (c->check_struct (this));
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. */
385 DEFINE_SIZE_STATIC (12);
388 template <typename UINT>
389 struct CmapSubtableTrimmed
391 inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
393 /* Rely on our implicit array bound-checking. */
394 hb_codepoint_t gid = glyphIdArray[codepoint - startCharCode];
401 inline bool sanitize (hb_sanitize_context_t *c) const
403 TRACE_SANITIZE (this);
404 return_trace (c->check_struct (this) && glyphIdArray.sanitize (c));
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. */
416 DEFINE_SIZE_ARRAY (5 * sizeof (UINT), glyphIdArray);
419 struct CmapSubtableFormat6 : CmapSubtableTrimmed<HBUINT16> {};
420 struct CmapSubtableFormat10 : CmapSubtableTrimmed<HBUINT32 > {};
422 template <typename T>
423 struct CmapSubtableLongSegmented
427 inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
429 int i = groups.bsearch (codepoint);
432 *glyph = T::group_get_glyph (groups[i], codepoint);
436 inline void get_all_codepoints (hb_set_t *out) const
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);
445 inline bool sanitize (hb_sanitize_context_t *c) const
447 TRACE_SANITIZE (this);
448 return_trace (c->check_struct (this) && groups.sanitize (c));
451 inline bool serialize (hb_serialize_context_t *c,
452 const hb_vector_t<CmapSubtableLongGroup> &group_data)
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);
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. */
469 DEFINE_SIZE_ARRAY (16, groups);
472 struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
474 static inline hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
476 { return group.glyphID + (u - group.startCharCode); }
479 bool serialize (hb_serialize_context_t *c,
480 const hb_vector_t<CmapSubtableLongGroup> &groups)
482 if (unlikely (!c->extend_min (*this))) return false;
484 this->format.set (12);
485 this->reserved.set (0);
486 this->length.set (get_sub_table_size (groups));
488 return CmapSubtableLongSegmented<CmapSubtableFormat12>::serialize (c, groups);
491 static inline size_t get_sub_table_size (const hb_vector_t<CmapSubtableLongGroup> &groups)
493 return 16 + 12 * groups.len;
496 static inline bool create_sub_table_plan (const hb_subset_plan_t *plan,
497 hb_vector_t<CmapSubtableLongGroup> *groups)
499 CmapSubtableLongGroup *group = nullptr;
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)))
506 DEBUG_MSG(SUBSET, nullptr, "Unable to find new gid for %04x", cp);
510 if (!group || !_is_gid_consecutive (group, cp, new_gid))
512 group = groups->push ();
513 group->startCharCode.set (cp);
514 group->endCharCode.set (cp);
515 group->glyphID.set (new_gid);
518 group->endCharCode.set (cp);
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));
532 static inline bool _is_gid_consecutive (CmapSubtableLongGroup *group,
534 hb_codepoint_t new_gid)
536 return (cp - 1 == group->endCharCode) &&
537 new_gid == group->glyphID + (cp - group->startCharCode);
542 struct CmapSubtableFormat13 : CmapSubtableLongSegmented<CmapSubtableFormat13>
544 static inline hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
545 hb_codepoint_t u HB_UNUSED)
546 { return group.glyphID; }
551 GLYPH_VARIANT_NOT_FOUND = 0,
552 GLYPH_VARIANT_FOUND = 1,
553 GLYPH_VARIANT_USE_DEFAULT = 2
556 struct UnicodeValueRange
558 inline int cmp (const hb_codepoint_t &codepoint) const
560 if (codepoint < startUnicodeValue) return -1;
561 if (codepoint > startUnicodeValue + additionalCount) return +1;
565 inline bool sanitize (hb_sanitize_context_t *c) const
567 TRACE_SANITIZE (this);
568 return_trace (c->check_struct (this));
571 HBUINT24 startUnicodeValue; /* First value in this range. */
572 HBUINT8 additionalCount; /* Number of additional values in this
575 DEFINE_SIZE_STATIC (4);
578 typedef SortedArrayOf<UnicodeValueRange, HBUINT32> DefaultUVS;
582 inline int cmp (const hb_codepoint_t &codepoint) const
584 return unicodeValue.cmp (codepoint);
587 inline bool sanitize (hb_sanitize_context_t *c) const
589 TRACE_SANITIZE (this);
590 return_trace (c->check_struct (this));
593 HBUINT24 unicodeValue; /* Base Unicode value of the UVS */
594 GlyphID glyphID; /* Glyph ID of the UVS */
596 DEFINE_SIZE_STATIC (5);
599 typedef SortedArrayOf<UVSMapping, HBUINT32> NonDefaultUVS;
601 struct VariationSelectorRecord
603 inline glyph_variant_t get_glyph (hb_codepoint_t codepoint,
604 hb_codepoint_t *glyph,
605 const void *base) const
608 const DefaultUVS &defaults = base+defaultUVS;
609 i = defaults.bsearch (codepoint);
611 return GLYPH_VARIANT_USE_DEFAULT;
612 const NonDefaultUVS &nonDefaults = base+nonDefaultUVS;
613 i = nonDefaults.bsearch (codepoint);
616 *glyph = nonDefaults[i].glyphID;
617 return GLYPH_VARIANT_FOUND;
619 return GLYPH_VARIANT_NOT_FOUND;
622 inline int cmp (const hb_codepoint_t &variation_selector) const
624 return varSelector.cmp (variation_selector);
627 inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
629 TRACE_SANITIZE (this);
630 return_trace (c->check_struct (this) &&
631 defaultUVS.sanitize (c, base) &&
632 nonDefaultUVS.sanitize (c, base));
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. */
641 DEFINE_SIZE_STATIC (11);
644 struct CmapSubtableFormat14
646 inline glyph_variant_t get_glyph_variant (hb_codepoint_t codepoint,
647 hb_codepoint_t variation_selector,
648 hb_codepoint_t *glyph) const
650 return record[record.bsearch(variation_selector)].get_glyph (codepoint, glyph, this);
653 inline bool sanitize (hb_sanitize_context_t *c) const
655 TRACE_SANITIZE (this);
656 return_trace (c->check_struct (this) &&
657 record.sanitize (c, this));
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'. */
667 DEFINE_SIZE_ARRAY (10, record);
672 /* Note: We intentionally do NOT implement subtable formats 2 and 8. */
674 inline bool get_glyph (hb_codepoint_t codepoint,
675 hb_codepoint_t *glyph) const
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);
685 default: return false;
689 inline bool sanitize (hb_sanitize_context_t *c) const
691 TRACE_SANITIZE (this);
692 if (!u.format.sanitize (c)) return_trace (false);
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);
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;
717 DEFINE_SIZE_UNION (2, format);
721 struct EncodingRecord
723 inline int cmp (const EncodingRecord &other) const
726 ret = platformID.cmp (other.platformID);
728 ret = encodingID.cmp (other.encodingID);
733 inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
735 TRACE_SANITIZE (this);
736 return_trace (c->check_struct (this) &&
737 subtable.sanitize (c, base));
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. */
745 DEFINE_SIZE_STATIC (8);
750 static const hb_tag_t tableTag = HB_OT_TAG_cmap;
755 format4_segments.init();
756 format12_groups.init();
761 format4_segments.fini();
762 format12_groups.fini();
765 inline size_t final_size() const
768 + 8 * 3 // 3 EncodingRecord
769 + CmapSubtableFormat4::get_sub_table_size (this->format4_segments)
770 + CmapSubtableFormat12::get_sub_table_size (this->format12_groups);
774 hb_vector_t<CmapSubtableFormat4::segment_plan> format4_segments;
776 hb_vector_t<CmapSubtableLongGroup> format12_groups;
779 inline bool sanitize (hb_sanitize_context_t *c) const
781 TRACE_SANITIZE (this);
782 return_trace (c->check_struct (this) &&
783 likely (version == 0) &&
784 encodingRecord.sanitize (c, this));
787 inline bool _create_plan (const hb_subset_plan_t *plan,
788 subset_plan *cmap_plan) const
790 if (unlikely( !CmapSubtableFormat4::create_sub_table_plan (plan, &cmap_plan->format4_segments)))
793 return CmapSubtableFormat12::create_sub_table_plan (plan, &cmap_plan->format12_groups);
796 inline bool _subset (const hb_subset_plan_t *plan,
797 const subset_plan &cmap_subset_plan,
801 hb_serialize_context_t c (dest, dest_sz);
803 OT::cmap *cmap = c.start_serialize<OT::cmap> ();
804 if (unlikely (!c.extend_min (*cmap)))
809 cmap->version.set (0);
811 if (unlikely (!cmap->encodingRecord.serialize (&c, /* numTables */ 3)))
814 // TODO(grieger): Convert the below to a for loop
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);
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
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
831 // Write out format 4 sub table
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);
837 CmapSubtableFormat4 &format4 = subtable.u.format4;
838 if (unlikely (!format4.serialize (&c, plan, cmap_subset_plan.format4_segments)))
842 // Write out format 12 sub table.
844 CmapSubtable &subtable = format12_rec.subtable.serialize (&c, cmap);
845 subtable.u.format.set (12);
847 CmapSubtableFormat12 &format12 = subtable.u.format12;
848 if (unlikely (!format12.serialize (&c, cmap_subset_plan.format12_groups)))
857 inline bool subset (hb_subset_plan_t *plan) const
859 subset_plan cmap_subset_plan;
861 if (unlikely (!_create_plan (plan, &cmap_subset_plan)))
863 DEBUG_MSG(SUBSET, nullptr, "Failed to generate a cmap subsetting plan.");
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);
875 if (unlikely (!_subset (plan, cmap_subset_plan, dest_sz, dest)))
877 DEBUG_MSG(SUBSET, nullptr, "Failed to perform subsetting of cmap.");
882 // all done, write the blob into dest
883 hb_blob_t *cmap_prime = hb_blob_create ((const char *)dest,
885 HB_MEMORY_MODE_READONLY,
888 bool result = plan->add_table (HB_OT_TAG_cmap, cmap_prime);
889 hb_blob_destroy (cmap_prime);
895 inline void init (hb_face_t *face)
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;
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);
915 subtable = cmap->find_subtable (3, 0);
916 if (subtable) symbol = true;
919 if (!subtable) subtable = &Null(OT::CmapSubtable);
924 const OT::CmapSubtable *st = cmap->find_subtable (0, 5);
925 if (st && st->u.format == 14)
926 subtable_uvs = &st->u.format14;
929 if (!subtable_uvs) subtable_uvs = &Null(OT::CmapSubtableFormat14);
931 this->uvs_table = subtable_uvs;
933 this->get_glyph_data = subtable;
934 if (unlikely (symbol))
936 this->get_glyph_func = get_glyph_from_symbol<OT::CmapSubtable>;
937 this->get_all_codepoints_func = null_get_all_codepoints_func;
939 switch (subtable->u.format) {
940 /* Accelerate format 4 and format 12. */
942 this->get_glyph_func = get_glyph_from<OT::CmapSubtable>;
943 this->get_all_codepoints_func = null_get_all_codepoints_func;
946 this->get_glyph_func = get_glyph_from<OT::CmapSubtableFormat12>;
947 this->get_all_codepoints_func = get_all_codepoints_from<OT::CmapSubtableFormat12>;
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;
961 inline void fini (void)
963 hb_blob_destroy (this->blob);
966 inline bool get_nominal_glyph (hb_codepoint_t unicode,
967 hb_codepoint_t *glyph) const
969 return this->get_glyph_func (this->get_glyph_data, unicode, glyph);
972 inline bool get_variation_glyph (hb_codepoint_t unicode,
973 hb_codepoint_t variation_selector,
974 hb_codepoint_t *glyph) const
976 switch (this->uvs_table->get_glyph_variant (unicode,
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;
985 return get_nominal_glyph (unicode, glyph);
988 inline void get_all_codepoints (hb_set_t *out) const
990 this->get_all_codepoints_func (get_glyph_data, out);
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,
1000 static inline void null_get_all_codepoints_func (const void *obj, hb_set_t *out)
1005 template <typename Type>
1006 static inline bool get_glyph_from (const void *obj,
1007 hb_codepoint_t codepoint,
1008 hb_codepoint_t *glyph)
1010 const Type *typed_obj = (const Type *) obj;
1011 return typed_obj->get_glyph (codepoint, glyph);
1014 template <typename Type>
1015 static inline void get_all_codepoints_from (const void *obj,
1018 const Type *typed_obj = (const Type *) obj;
1019 typed_obj->get_all_codepoints (out);
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)
1027 const Type *typed_obj = (const Type *) obj;
1028 if (likely (typed_obj->get_glyph (codepoint, glyph)))
1031 if (codepoint <= 0x00FFu)
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);
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;
1049 OT::CmapSubtableFormat4::accelerator_t format4_accel;
1051 const OT::CmapSubtableFormat14 *uvs_table;
1057 inline const CmapSubtable *find_subtable (unsigned int platform_id,
1058 unsigned int encoding_id) const
1061 key.platformID.set (platform_id);
1062 key.encodingID.set (encoding_id);
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)
1071 return &(this+encodingRecord[result].subtable);
1075 HBUINT16 version; /* Table version number (0). */
1076 SortedArrayOf<EncodingRecord>
1077 encodingRecord; /* Encoding tables. */
1079 DEFINE_SIZE_ARRAY (4, encodingRecord);
1083 } /* namespace OT */
1086 #endif /* HB_OT_CMAP_TABLE_HH */