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; |
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. */ |
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, |
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) |
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 }; |