1 /*
2 * Copyright © 2014 Google, Inc.
3 *
4 * This is part of HarfBuzz, a text shaping library.
5 *
6 * Permission is hereby granted, without written agreement and without
7 * license or royalty fees, to use, copy, modify, and distribute this
8 * software and its documentation for any purpose, provided that the
9 * above copyright notice and the following two paragraphs appear in
10 * all copies of this software.
11 *
12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16 * DAMAGE.
17 *
18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23 *
24 * Google Author(s): Behdad Esfahbod
25 */
26
27 #ifndef HB_OT_CMAP_TABLE_HH
28 #define HB_OT_CMAP_TABLE_HH
29
30 #include "hb-ot-os2-table.hh"
31 #include "hb-ot-shaper-arabic-pua.hh"
32 #include "hb-open-type.hh"
33 #include "hb-set.hh"
34 #include "hb-cache.hh"
35
36 /*
37 * cmap -- Character to Glyph Index Mapping
38 * https://docs.microsoft.com/en-us/typography/opentype/spec/cmap
39 */
40 #define HB_OT_TAG_cmap HB_TAG('c','m','a','p')
41
42 namespace OT {
43
unicode_to_macroman(hb_codepoint_t u)44 static inline uint8_t unicode_to_macroman (hb_codepoint_t u)
45 {
46 static const struct unicode_to_macroman_t
47 {
48 uint16_t unicode;
49 uint8_t macroman;
50 }
51 mapping[] =
52 {
53 { 0x00A0, 0xCA },
54 { 0x00A1, 0xC1 },
55 { 0x00A2, 0xA2 },
56 { 0x00A3, 0xA3 },
57 { 0x00A5, 0xB4 },
58 { 0x00A7, 0xA4 },
59 { 0x00A8, 0xAC },
60 { 0x00A9, 0xA9 },
61 { 0x00AA, 0xBB },
62 { 0x00AB, 0xC7 },
63 { 0x00AC, 0xC2 },
64 { 0x00AE, 0xA8 },
65 { 0x00AF, 0xF8 },
66 { 0x00B0, 0xA1 },
67 { 0x00B1, 0xB1 },
68 { 0x00B4, 0xAB },
69 { 0x00B5, 0xB5 },
70 { 0x00B6, 0xA6 },
71 { 0x00B7, 0xE1 },
72 { 0x00B8, 0xFC },
73 { 0x00BA, 0xBC },
74 { 0x00BB, 0xC8 },
75 { 0x00BF, 0xC0 },
76 { 0x00C0, 0xCB },
77 { 0x00C1, 0xE7 },
78 { 0x00C2, 0xE5 },
79 { 0x00C3, 0xCC },
80 { 0x00C4, 0x80 },
81 { 0x00C5, 0x81 },
82 { 0x00C6, 0xAE },
83 { 0x00C7, 0x82 },
84 { 0x00C8, 0xE9 },
85 { 0x00C9, 0x83 },
86 { 0x00CA, 0xE6 },
87 { 0x00CB, 0xE8 },
88 { 0x00CC, 0xED },
89 { 0x00CD, 0xEA },
90 { 0x00CE, 0xEB },
91 { 0x00CF, 0xEC },
92 { 0x00D1, 0x84 },
93 { 0x00D2, 0xF1 },
94 { 0x00D3, 0xEE },
95 { 0x00D4, 0xEF },
96 { 0x00D5, 0xCD },
97 { 0x00D6, 0x85 },
98 { 0x00D8, 0xAF },
99 { 0x00D9, 0xF4 },
100 { 0x00DA, 0xF2 },
101 { 0x00DB, 0xF3 },
102 { 0x00DC, 0x86 },
103 { 0x00DF, 0xA7 },
104 { 0x00E0, 0x88 },
105 { 0x00E1, 0x87 },
106 { 0x00E2, 0x89 },
107 { 0x00E3, 0x8B },
108 { 0x00E4, 0x8A },
109 { 0x00E5, 0x8C },
110 { 0x00E6, 0xBE },
111 { 0x00E7, 0x8D },
112 { 0x00E8, 0x8F },
113 { 0x00E9, 0x8E },
114 { 0x00EA, 0x90 },
115 { 0x00EB, 0x91 },
116 { 0x00EC, 0x93 },
117 { 0x00ED, 0x92 },
118 { 0x00EE, 0x94 },
119 { 0x00EF, 0x95 },
120 { 0x00F1, 0x96 },
121 { 0x00F2, 0x98 },
122 { 0x00F3, 0x97 },
123 { 0x00F4, 0x99 },
124 { 0x00F5, 0x9B },
125 { 0x00F6, 0x9A },
126 { 0x00F7, 0xD6 },
127 { 0x00F8, 0xBF },
128 { 0x00F9, 0x9D },
129 { 0x00FA, 0x9C },
130 { 0x00FB, 0x9E },
131 { 0x00FC, 0x9F },
132 { 0x00FF, 0xD8 },
133 { 0x0131, 0xF5 },
134 { 0x0152, 0xCE },
135 { 0x0153, 0xCF },
136 { 0x0178, 0xD9 },
137 { 0x0192, 0xC4 },
138 { 0x02C6, 0xF6 },
139 { 0x02C7, 0xFF },
140 { 0x02D8, 0xF9 },
141 { 0x02D9, 0xFA },
142 { 0x02DA, 0xFB },
143 { 0x02DB, 0xFE },
144 { 0x02DC, 0xF7 },
145 { 0x02DD, 0xFD },
146 { 0x03A9, 0xBD },
147 { 0x03C0, 0xB9 },
148 { 0x2013, 0xD0 },
149 { 0x2014, 0xD1 },
150 { 0x2018, 0xD4 },
151 { 0x2019, 0xD5 },
152 { 0x201A, 0xE2 },
153 { 0x201C, 0xD2 },
154 { 0x201D, 0xD3 },
155 { 0x201E, 0xE3 },
156 { 0x2020, 0xA0 },
157 { 0x2021, 0xE0 },
158 { 0x2022, 0xA5 },
159 { 0x2026, 0xC9 },
160 { 0x2030, 0xE4 },
161 { 0x2039, 0xDC },
162 { 0x203A, 0xDD },
163 { 0x2044, 0xDA },
164 { 0x20AC, 0xDB },
165 { 0x2122, 0xAA },
166 { 0x2202, 0xB6 },
167 { 0x2206, 0xC6 },
168 { 0x220F, 0xB8 },
169 { 0x2211, 0xB7 },
170 { 0x221A, 0xC3 },
171 { 0x221E, 0xB0 },
172 { 0x222B, 0xBA },
173 { 0x2248, 0xC5 },
174 { 0x2260, 0xAD },
175 { 0x2264, 0xB2 },
176 { 0x2265, 0xB3 },
177 { 0x25CA, 0xD7 },
178 { 0xF8FF, 0xF0 },
179 { 0xFB01, 0xDE },
180 { 0xFB02, 0xDF },
181 };
182 auto *c = hb_bsearch (u, mapping, ARRAY_LENGTH (mapping), sizeof (mapping[0]),
183 _hb_cmp_operator<uint16_t, uint16_t>);
184 return c ? c->macroman : 0;
185 }
186
187 struct CmapSubtableFormat0
188 {
get_glyphOT::CmapSubtableFormat0189 bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
190 {
191 hb_codepoint_t gid = codepoint < 256 ? glyphIdArray[codepoint] : 0;
192 if (unlikely (!gid))
193 return false;
194 *glyph = gid;
195 return true;
196 }
197
get_languageOT::CmapSubtableFormat0198 unsigned get_language () const
199 {
200 return language;
201 }
202
collect_unicodesOT::CmapSubtableFormat0203 void collect_unicodes (hb_set_t *out) const
204 {
205 for (unsigned int i = 0; i < 256; i++)
206 if (glyphIdArray[i])
207 out->add (i);
208 }
209
collect_mappingOT::CmapSubtableFormat0210 void collect_mapping (hb_set_t *unicodes, /* OUT */
211 hb_map_t *mapping /* OUT */) const
212 {
213 for (unsigned i = 0; i < 256; i++)
214 if (glyphIdArray[i])
215 {
216 hb_codepoint_t glyph = glyphIdArray[i];
217 unicodes->add (i);
218 mapping->set (i, glyph);
219 }
220 }
221
sanitizeOT::CmapSubtableFormat0222 bool sanitize (hb_sanitize_context_t *c) const
223 {
224 TRACE_SANITIZE (this);
225 return_trace (c->check_struct (this));
226 }
227
228 protected:
229 HBUINT16 format; /* Format number is set to 0. */
230 HBUINT16 length; /* Byte length of this subtable. */
231 HBUINT16 language; /* Ignore. */
232 HBUINT8 glyphIdArray[256];/* An array that maps character
233 * code to glyph index values. */
234 public:
235 DEFINE_SIZE_STATIC (6 + 256);
236 };
237
238 struct CmapSubtableFormat4
239 {
240
241
242 template<typename Iterator,
243 typename Writer,
244 hb_requires (hb_is_iterator (Iterator))>
to_rangesOT::CmapSubtableFormat4245 void to_ranges (Iterator it, Writer& range_writer)
246 {
247 hb_codepoint_t start_cp = 0, prev_run_start_cp = 0, run_start_cp = 0, end_cp = 0, last_gid = 0;
248 int run_length = 0 , delta = 0, prev_delta = 0;
249
250 enum {
251 FIRST_SUB_RANGE,
252 FOLLOWING_SUB_RANGE,
253 } mode;
254
255 while (it) {
256 // Start a new range
257 {
258 const auto& pair = *it;
259 start_cp = pair.first;
260 prev_run_start_cp = start_cp;
261 run_start_cp = start_cp;
262 end_cp = start_cp;
263 last_gid = pair.second;
264 run_length = 1;
265 prev_delta = 0;
266 }
267
268 delta = last_gid - start_cp;
269 mode = FIRST_SUB_RANGE;
270 it++;
271
272 while (it) {
273 // Process range
274 const auto& pair = *it;
275 hb_codepoint_t next_cp = pair.first;
276 hb_codepoint_t next_gid = pair.second;
277 if (next_cp != end_cp + 1) {
278 // Current range is over, stop processing.
279 break;
280 }
281
282 if (next_gid == last_gid + 1) {
283 // The current run continues.
284 end_cp = next_cp;
285 run_length++;
286 last_gid = next_gid;
287 it++;
288 continue;
289 }
290
291 // A new run is starting, decide if we want to commit the current run.
292 int split_cost = (mode == FIRST_SUB_RANGE) ? 8 : 16;
293 int run_cost = run_length * 2;
294 if (run_cost >= split_cost) {
295 commit_current_range(start_cp,
296 prev_run_start_cp,
297 run_start_cp,
298 end_cp,
299 delta,
300 prev_delta,
301 split_cost,
302 range_writer);
303 start_cp = next_cp;
304 }
305
306 // Start the new run
307 mode = FOLLOWING_SUB_RANGE;
308 prev_run_start_cp = run_start_cp;
309 run_start_cp = next_cp;
310 end_cp = next_cp;
311 prev_delta = delta;
312 delta = next_gid - run_start_cp;
313 run_length = 1;
314 last_gid = next_gid;
315 it++;
316 }
317
318 // Finalize range
319 commit_current_range (start_cp,
320 prev_run_start_cp,
321 run_start_cp,
322 end_cp,
323 delta,
324 prev_delta,
325 8,
326 range_writer);
327 }
328
329 if (likely (end_cp != 0xFFFF)) {
330 range_writer (0xFFFF, 0xFFFF, 1);
331 }
332 }
333
334 /*
335 * Writes the current range as either one or two ranges depending on what is most efficient.
336 */
337 template<typename Writer>
commit_current_rangeOT::CmapSubtableFormat4338 void commit_current_range (hb_codepoint_t start,
339 hb_codepoint_t prev_run_start,
340 hb_codepoint_t run_start,
341 hb_codepoint_t end,
342 int run_delta,
343 int previous_run_delta,
344 int split_cost,
345 Writer& range_writer) {
346 bool should_split = false;
347 if (start < run_start && run_start < end) {
348 int run_cost = (end - run_start + 1) * 2;
349 if (run_cost >= split_cost) {
350 should_split = true;
351 }
352 }
353
354 // TODO(grieger): handle case where delta is legitimately 0, mark range offset array instead?
355 if (should_split) {
356 if (start == prev_run_start)
357 range_writer (start, run_start - 1, previous_run_delta);
358 else
359 range_writer (start, run_start - 1, 0);
360 range_writer (run_start, end, run_delta);
361 return;
362 }
363
364
365 if (start == run_start) {
366 // Range is only a run
367 range_writer (start, end, run_delta);
368 return;
369 }
370
371 // Write only a single non-run range.
372 range_writer (start, end, 0);
373 }
374
375 template<typename Iterator,
376 hb_requires (hb_is_iterator (Iterator))>
serialize_find_segcountOT::CmapSubtableFormat4377 unsigned serialize_find_segcount (Iterator it) {
378 struct Counter {
379 unsigned segcount = 0;
380
381 void operator() (hb_codepoint_t start,
382 hb_codepoint_t end,
383 int delta) {
384 segcount++;
385 }
386 } counter;
387
388 to_ranges (+it, counter);
389 return counter.segcount;
390 }
391
392
393 template<typename Iterator,
394 hb_requires (hb_is_iterator (Iterator))>
serialize_start_end_delta_arraysOT::CmapSubtableFormat4395 bool serialize_start_end_delta_arrays (hb_serialize_context_t *c,
396 Iterator it,
397 int segcount)
398 {
399 struct Writer {
400 hb_serialize_context_t *serializer_;
401 HBUINT16* end_code_;
402 HBUINT16* start_code_;
403 HBINT16* id_delta_;
404 int index_;
405
406 Writer(hb_serialize_context_t *serializer)
407 : serializer_(serializer),
408 end_code_(nullptr),
409 start_code_(nullptr),
410 id_delta_(nullptr),
411 index_ (0) {}
412 void operator() (hb_codepoint_t start,
413 hb_codepoint_t end,
414 int delta) {
415 start_code_[index_] = start;
416 end_code_[index_] = end;
417 id_delta_[index_] = delta;
418 index_++;
419 }
420 } writer(c);
421
422 writer.end_code_ = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount, false);
423 (void) c->allocate_size<HBUINT16> (2); // padding
424 writer.start_code_ = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount, false);
425 writer.id_delta_ = c->allocate_size<HBINT16> (HBINT16::static_size * segcount, false);
426
427 if (unlikely (!writer.end_code_ || !writer.start_code_ || !writer.id_delta_)) return false;
428
429 to_ranges (+it, writer);
430 return true;
431 }
432
433 template<typename Iterator,
434 hb_requires (hb_is_iterator (Iterator))>
serialize_rangeoffset_glyidOT::CmapSubtableFormat4435 HBUINT16* serialize_rangeoffset_glyid (hb_serialize_context_t *c,
436 Iterator it,
437 HBUINT16 *endCode,
438 HBUINT16 *startCode,
439 HBINT16 *idDelta,
440 unsigned segcount)
441 {
442 hb_map_t cp_to_gid { it };
443
444 HBUINT16 *idRangeOffset = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount);
445 if (unlikely (!c->check_success (idRangeOffset))) return nullptr;
446 if (unlikely ((char *)idRangeOffset - (char *)idDelta != (int) segcount * (int) HBINT16::static_size)) return nullptr;
447
448 for (unsigned i : + hb_range (segcount)
449 | hb_filter ([&] (const unsigned _) { return idDelta[_] == 0; }))
450 {
451 idRangeOffset[i] = 2 * (c->start_embed<HBUINT16> () - idRangeOffset - i);
452 for (hb_codepoint_t cp = startCode[i]; cp <= endCode[i]; cp++)
453 {
454 HBUINT16 gid;
455 gid = cp_to_gid[cp];
456 c->copy<HBUINT16> (gid);
457 }
458 }
459
460 return idRangeOffset;
461 }
462
463 template<typename Iterator,
464 hb_requires (hb_is_iterator (Iterator))>
serializeOT::CmapSubtableFormat4465 void serialize (hb_serialize_context_t *c,
466 Iterator it)
467 {
468 auto format4_iter =
469 + it
470 | hb_filter ([&] (const hb_codepoint_pair_t _)
471 { return _.first <= 0xFFFF; })
472 ;
473
474 if (!format4_iter) return;
475
476 unsigned table_initpos = c->length ();
477 if (unlikely (!c->extend_min (this))) return;
478 this->format = 4;
479
480 hb_vector_t<hb_codepoint_pair_t> cp_to_gid {
481 format4_iter
482 };
483
484 //serialize endCode[], startCode[], idDelta[]
485 HBUINT16* endCode = c->start_embed<HBUINT16> ();
486 unsigned segcount = serialize_find_segcount (cp_to_gid.iter());
487 if (unlikely (!serialize_start_end_delta_arrays (c, cp_to_gid.iter(), segcount)))
488 return;
489
490 HBUINT16 *startCode = endCode + segcount + 1;
491 HBINT16 *idDelta = ((HBINT16*)startCode) + segcount;
492
493 HBUINT16 *idRangeOffset = serialize_rangeoffset_glyid (c,
494 cp_to_gid.iter (),
495 endCode,
496 startCode,
497 idDelta,
498 segcount);
499 if (unlikely (!c->check_success (idRangeOffset))) return;
500
501 this->length = c->length () - table_initpos;
502 if ((long long) this->length != (long long) c->length () - table_initpos)
503 {
504 // Length overflowed. Discard the current object before setting the error condition, otherwise
505 // discard is a noop which prevents the higher level code from reverting the serializer to the
506 // pre-error state in cmap4 overflow handling code.
507 c->pop_discard ();
508 c->err (HB_SERIALIZE_ERROR_INT_OVERFLOW);
509 return;
510 }
511
512 this->segCountX2 = segcount * 2;
513 this->entrySelector = hb_max (1u, hb_bit_storage (segcount)) - 1;
514 this->searchRange = 2 * (1u << this->entrySelector);
515 this->rangeShift = segcount * 2 > this->searchRange
516 ? 2 * segcount - this->searchRange
517 : 0;
518 }
519
get_languageOT::CmapSubtableFormat4520 unsigned get_language () const
521 {
522 return language;
523 }
524
525 struct accelerator_t
526 {
accelerator_tOT::CmapSubtableFormat4::accelerator_t527 accelerator_t () {}
accelerator_tOT::CmapSubtableFormat4::accelerator_t528 accelerator_t (const CmapSubtableFormat4 *subtable) { init (subtable); }
529
initOT::CmapSubtableFormat4::accelerator_t530 void init (const CmapSubtableFormat4 *subtable)
531 {
532 segCount = subtable->segCountX2 / 2;
533 endCount = subtable->values.arrayZ;
534 startCount = endCount + segCount + 1;
535 idDelta = startCount + segCount;
536 idRangeOffset = idDelta + segCount;
537 glyphIdArray = idRangeOffset + segCount;
538 glyphIdArrayLength = (subtable->length - 16 - 8 * segCount) / 2;
539 }
540
get_glyphOT::CmapSubtableFormat4::accelerator_t541 bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
542 {
543 struct CustomRange
544 {
545 int cmp (hb_codepoint_t k,
546 unsigned distance) const
547 {
548 if (k > last) return +1;
549 if (k < (&last)[distance]/*first*/) return -1;
550 return 0;
551 }
552 HBUINT16 last;
553 };
554
555 const HBUINT16 *found = hb_bsearch (codepoint,
556 this->endCount,
557 this->segCount,
558 sizeof (CustomRange),
559 _hb_cmp_method<hb_codepoint_t, CustomRange, unsigned>,
560 this->segCount + 1);
561 if (unlikely (!found))
562 return false;
563 unsigned int i = found - endCount;
564
565 hb_codepoint_t gid;
566 unsigned int rangeOffset = this->idRangeOffset[i];
567 if (rangeOffset == 0)
568 gid = codepoint + this->idDelta[i];
569 else
570 {
571 /* Somebody has been smoking... */
572 unsigned int index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount;
573 if (unlikely (index >= this->glyphIdArrayLength))
574 return false;
575 gid = this->glyphIdArray[index];
576 if (unlikely (!gid))
577 return false;
578 gid += this->idDelta[i];
579 }
580 gid &= 0xFFFFu;
581 if (unlikely (!gid))
582 return false;
583 *glyph = gid;
584 return true;
585 }
586
get_glyph_funcOT::CmapSubtableFormat4::accelerator_t587 HB_INTERNAL static bool get_glyph_func (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph)
588 { return ((const accelerator_t *) obj)->get_glyph (codepoint, glyph); }
589
collect_unicodesOT::CmapSubtableFormat4::accelerator_t590 void collect_unicodes (hb_set_t *out) const
591 {
592 unsigned int count = this->segCount;
593 if (count && this->startCount[count - 1] == 0xFFFFu)
594 count--; /* Skip sentinel segment. */
595 for (unsigned int i = 0; i < count; i++)
596 {
597 hb_codepoint_t start = this->startCount[i];
598 hb_codepoint_t end = this->endCount[i];
599 unsigned int rangeOffset = this->idRangeOffset[i];
600 out->add_range(start, end);
601 if (rangeOffset == 0)
602 {
603 for (hb_codepoint_t codepoint = start; codepoint <= end; codepoint++)
604 {
605 hb_codepoint_t gid = (codepoint + this->idDelta[i]) & 0xFFFFu;
606 if (unlikely (!gid))
607 out->del(codepoint);
608 }
609 }
610 else
611 {
612 for (hb_codepoint_t codepoint = start; codepoint <= end; codepoint++)
613 {
614 unsigned int index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount;
615 if (unlikely (index >= this->glyphIdArrayLength))
616 {
617 out->del_range (codepoint, end);
618 break;
619 }
620 hb_codepoint_t gid = this->glyphIdArray[index];
621 if (unlikely (!gid))
622 out->del(codepoint);
623 }
624 }
625 }
626 }
627
collect_mappingOT::CmapSubtableFormat4::accelerator_t628 void collect_mapping (hb_set_t *unicodes, /* OUT */
629 hb_map_t *mapping /* OUT */) const
630 {
631 // TODO(grieger): optimize similar to collect_unicodes
632 // (ie. use add_range())
633 unsigned count = this->segCount;
634 if (count && this->startCount[count - 1] == 0xFFFFu)
635 count--; /* Skip sentinel segment. */
636 for (unsigned i = 0; i < count; i++)
637 {
638 hb_codepoint_t start = this->startCount[i];
639 hb_codepoint_t end = this->endCount[i];
640 unsigned rangeOffset = this->idRangeOffset[i];
641 if (rangeOffset == 0)
642 {
643 for (hb_codepoint_t codepoint = start; codepoint <= end; codepoint++)
644 {
645 hb_codepoint_t gid = (codepoint + this->idDelta[i]) & 0xFFFFu;
646 if (unlikely (!gid))
647 continue;
648 unicodes->add (codepoint);
649 mapping->set (codepoint, gid);
650 }
651 }
652 else
653 {
654 for (hb_codepoint_t codepoint = start; codepoint <= end; codepoint++)
655 {
656 unsigned index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount;
657 if (unlikely (index >= this->glyphIdArrayLength))
658 break;
659 hb_codepoint_t gid = this->glyphIdArray[index];
660 if (unlikely (!gid))
661 continue;
662 unicodes->add (codepoint);
663 mapping->set (codepoint, gid);
664 }
665 }
666 }
667 }
668
669 const HBUINT16 *endCount;
670 const HBUINT16 *startCount;
671 const HBUINT16 *idDelta;
672 const HBUINT16 *idRangeOffset;
673 const HBUINT16 *glyphIdArray;
674 unsigned int segCount;
675 unsigned int glyphIdArrayLength;
676 };
677
get_glyphOT::CmapSubtableFormat4678 bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
679 {
680 accelerator_t accel (this);
681 return accel.get_glyph_func (&accel, codepoint, glyph);
682 }
collect_unicodesOT::CmapSubtableFormat4683 void collect_unicodes (hb_set_t *out) const
684 {
685 accelerator_t accel (this);
686 accel.collect_unicodes (out);
687 }
688
collect_mappingOT::CmapSubtableFormat4689 void collect_mapping (hb_set_t *unicodes, /* OUT */
690 hb_map_t *mapping /* OUT */) const
691 {
692 accelerator_t accel (this);
693 accel.collect_mapping (unicodes, mapping);
694 }
695
sanitizeOT::CmapSubtableFormat4696 bool sanitize (hb_sanitize_context_t *c) const
697 {
698 TRACE_SANITIZE (this);
699 if (unlikely (!c->check_struct (this)))
700 return_trace (false);
701 hb_barrier ();
702
703 if (unlikely (!c->check_range (this, length)))
704 {
705 /* Some broken fonts have too long of a "length" value.
706 * If that is the case, just change the value to truncate
707 * the subtable at the end of the blob. */
708 uint16_t new_length = (uint16_t) hb_min ((uintptr_t) 65535,
709 (uintptr_t) (c->end -
710 (char *) this));
711 if (!c->try_set (&length, new_length))
712 return_trace (false);
713 }
714
715 return_trace (16 + 4 * (unsigned int) segCountX2 <= length);
716 }
717
718
719
720 protected:
721 HBUINT16 format; /* Format number is set to 4. */
722 HBUINT16 length; /* This is the length in bytes of the
723 * subtable. */
724 HBUINT16 language; /* Ignore. */
725 HBUINT16 segCountX2; /* 2 x segCount. */
726 HBUINT16 searchRange; /* 2 * (2**floor(log2(segCount))) */
727 HBUINT16 entrySelector; /* log2(searchRange/2) */
728 HBUINT16 rangeShift; /* 2 x segCount - searchRange */
729
730 UnsizedArrayOf<HBUINT16>
731 values;
732 #if 0
733 HBUINT16 endCount[segCount]; /* End characterCode for each segment,
734 * last=0xFFFFu. */
735 HBUINT16 reservedPad; /* Set to 0. */
736 HBUINT16 startCount[segCount]; /* Start character code for each segment. */
737 HBINT16 idDelta[segCount]; /* Delta for all character codes in segment. */
738 HBUINT16 idRangeOffset[segCount];/* Offsets into glyphIdArray or 0 */
739 UnsizedArrayOf<HBUINT16>
740 glyphIdArray; /* Glyph index array (arbitrary length) */
741 #endif
742
743 public:
744 DEFINE_SIZE_ARRAY (14, values);
745 };
746
747 struct CmapSubtableLongGroup
748 {
749 friend struct CmapSubtableFormat12;
750 friend struct CmapSubtableFormat13;
751 template<typename U>
752 friend struct CmapSubtableLongSegmented;
753 friend struct cmap;
754
cmpOT::CmapSubtableLongGroup755 int cmp (hb_codepoint_t codepoint) const
756 {
757 if (codepoint < startCharCode) return -1;
758 if (codepoint > endCharCode) return +1;
759 return 0;
760 }
761
sanitizeOT::CmapSubtableLongGroup762 bool sanitize (hb_sanitize_context_t *c) const
763 {
764 TRACE_SANITIZE (this);
765 return_trace (c->check_struct (this));
766 }
767
768 private:
769 HBUINT32 startCharCode; /* First character code in this group. */
770 HBUINT32 endCharCode; /* Last character code in this group. */
771 HBUINT32 glyphID; /* Glyph index; interpretation depends on
772 * subtable format. */
773 public:
774 DEFINE_SIZE_STATIC (12);
775 };
776 DECLARE_NULL_NAMESPACE_BYTES (OT, CmapSubtableLongGroup);
777
778 template <typename UINT>
779 struct CmapSubtableTrimmed
780 {
get_glyphOT::CmapSubtableTrimmed781 bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
782 {
783 /* Rely on our implicit array bound-checking. */
784 hb_codepoint_t gid = glyphIdArray[codepoint - startCharCode];
785 if (unlikely (!gid))
786 return false;
787 *glyph = gid;
788 return true;
789 }
790
get_languageOT::CmapSubtableTrimmed791 unsigned get_language () const
792 {
793 return language;
794 }
795
collect_unicodesOT::CmapSubtableTrimmed796 void collect_unicodes (hb_set_t *out) const
797 {
798 hb_codepoint_t start = startCharCode;
799 unsigned int count = glyphIdArray.len;
800 for (unsigned int i = 0; i < count; i++)
801 if (glyphIdArray[i])
802 out->add (start + i);
803 }
804
collect_mappingOT::CmapSubtableTrimmed805 void collect_mapping (hb_set_t *unicodes, /* OUT */
806 hb_map_t *mapping /* OUT */) const
807 {
808 hb_codepoint_t start_cp = startCharCode;
809 unsigned count = glyphIdArray.len;
810 for (unsigned i = 0; i < count; i++)
811 if (glyphIdArray[i])
812 {
813 hb_codepoint_t unicode = start_cp + i;
814 hb_codepoint_t glyphid = glyphIdArray[i];
815 unicodes->add (unicode);
816 mapping->set (unicode, glyphid);
817 }
818 }
819
sanitizeOT::CmapSubtableTrimmed820 bool sanitize (hb_sanitize_context_t *c) const
821 {
822 TRACE_SANITIZE (this);
823 return_trace (c->check_struct (this) && glyphIdArray.sanitize (c));
824 }
825
826 protected:
827 UINT formatReserved; /* Subtable format and (maybe) padding. */
828 UINT length; /* Byte length of this subtable. */
829 UINT language; /* Ignore. */
830 UINT startCharCode; /* First character code covered. */
831 ArrayOf<HBGlyphID16, UINT>
832 glyphIdArray; /* Array of glyph index values for character
833 * codes in the range. */
834 public:
835 DEFINE_SIZE_ARRAY (5 * sizeof (UINT), glyphIdArray);
836 };
837
838 struct CmapSubtableFormat6 : CmapSubtableTrimmed<HBUINT16> {};
839 struct CmapSubtableFormat10 : CmapSubtableTrimmed<HBUINT32> {};
840
841 template <typename T>
842 struct CmapSubtableLongSegmented
843 {
844 friend struct cmap;
845
get_glyphOT::CmapSubtableLongSegmented846 bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
847 {
848 hb_codepoint_t gid = T::group_get_glyph (groups.bsearch (codepoint), codepoint);
849 if (unlikely (!gid))
850 return false;
851 *glyph = gid;
852 return true;
853 }
854
get_languageOT::CmapSubtableLongSegmented855 unsigned get_language () const
856 {
857 return language;
858 }
859
collect_unicodesOT::CmapSubtableLongSegmented860 void collect_unicodes (hb_set_t *out, unsigned int num_glyphs) const
861 {
862 for (unsigned int i = 0; i < this->groups.len; i++)
863 {
864 hb_codepoint_t start = this->groups[i].startCharCode;
865 hb_codepoint_t end = hb_min ((hb_codepoint_t) this->groups[i].endCharCode,
866 (hb_codepoint_t) HB_UNICODE_MAX);
867 hb_codepoint_t gid = this->groups[i].glyphID;
868 if (!gid)
869 {
870 /* Intention is: if (hb_is_same (T, CmapSubtableFormat13)) continue; */
871 if (! T::group_get_glyph (this->groups[i], end)) continue;
872 start++;
873 gid++;
874 }
875 if (unlikely ((unsigned int) gid >= num_glyphs)) continue;
876 if (unlikely ((unsigned int) (gid + end - start) >= num_glyphs))
877 end = start + (hb_codepoint_t) num_glyphs - gid;
878
879 out->add_range (start, hb_min (end, 0x10FFFFu));
880 }
881 }
882
collect_mappingOT::CmapSubtableLongSegmented883 void collect_mapping (hb_set_t *unicodes, /* OUT */
884 hb_map_t *mapping, /* OUT */
885 unsigned num_glyphs) const
886 {
887 hb_codepoint_t last_end = 0;
888 unsigned count = this->groups.len;
889 for (unsigned i = 0; i < count; i++)
890 {
891 hb_codepoint_t start = this->groups.arrayZ[i].startCharCode;
892 hb_codepoint_t end = hb_min ((hb_codepoint_t) this->groups.arrayZ[i].endCharCode,
893 (hb_codepoint_t) HB_UNICODE_MAX);
894 if (unlikely (start > end || start < last_end)) {
895 // Range is not in order and is invalid, skip it.
896 continue;
897 }
898 last_end = end;
899
900
901 hb_codepoint_t gid = this->groups.arrayZ[i].glyphID;
902 if (!gid)
903 {
904 if (T::formatNumber == 13) continue;
905 start++;
906 gid++;
907 }
908 if (unlikely ((unsigned int) gid >= num_glyphs)) continue;
909 if (unlikely ((unsigned int) (gid + end - start) >= num_glyphs))
910 end = start + (hb_codepoint_t) num_glyphs - gid;
911
912 mapping->alloc (mapping->get_population () + end - start + 1);
913
914 unicodes->add_range (start, end);
915 for (unsigned cp = start; cp <= end; cp++)
916 {
917 mapping->set (cp, gid);
918 gid += T::increment;
919 }
920 }
921 }
922
sanitizeOT::CmapSubtableLongSegmented923 bool sanitize (hb_sanitize_context_t *c) const
924 {
925 TRACE_SANITIZE (this);
926 return_trace (c->check_struct (this) && groups.sanitize (c));
927 }
928
929 protected:
930 HBUINT16 format; /* Subtable format; set to 12. */
931 HBUINT16 reserved; /* Reserved; set to 0. */
932 HBUINT32 length; /* Byte length of this subtable. */
933 HBUINT32 language; /* Ignore. */
934 SortedArray32Of<CmapSubtableLongGroup>
935 groups; /* Groupings. */
936 public:
937 DEFINE_SIZE_ARRAY (16, groups);
938 };
939
940 struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
941 {
942 static constexpr int increment = 1;
943 static constexpr int formatNumber = 12;
944
group_get_glyphOT::CmapSubtableFormat12945 static hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
946 hb_codepoint_t u)
947 { return likely (group.startCharCode <= group.endCharCode) ?
948 group.glyphID + (u - group.startCharCode) : 0; }
949
950
951 template<typename Iterator,
952 hb_requires (hb_is_iterator (Iterator))>
serializeOT::CmapSubtableFormat12953 void serialize (hb_serialize_context_t *c,
954 Iterator it)
955 {
956 if (!it) return;
957 unsigned table_initpos = c->length ();
958 if (unlikely (!c->extend_min (this))) return;
959
960 hb_codepoint_t startCharCode = (hb_codepoint_t) -1, endCharCode = (hb_codepoint_t) -1;
961 hb_codepoint_t glyphID = 0;
962
963 for (const auto& _ : +it)
964 {
965 if (startCharCode == (hb_codepoint_t) -1)
966 {
967 startCharCode = _.first;
968 endCharCode = _.first;
969 glyphID = _.second;
970 }
971 else if (!_is_gid_consecutive (endCharCode, startCharCode, glyphID, _.first, _.second))
972 {
973 CmapSubtableLongGroup grouprecord;
974 grouprecord.startCharCode = startCharCode;
975 grouprecord.endCharCode = endCharCode;
976 grouprecord.glyphID = glyphID;
977 c->copy<CmapSubtableLongGroup> (grouprecord);
978
979 startCharCode = _.first;
980 endCharCode = _.first;
981 glyphID = _.second;
982 }
983 else
984 endCharCode = _.first;
985 }
986
987 CmapSubtableLongGroup record;
988 record.startCharCode = startCharCode;
989 record.endCharCode = endCharCode;
990 record.glyphID = glyphID;
991 c->copy<CmapSubtableLongGroup> (record);
992
993 this->format = 12;
994 this->reserved = 0;
995 this->length = c->length () - table_initpos;
996 this->groups.len = (this->length - min_size) / CmapSubtableLongGroup::static_size;
997 }
998
get_sub_table_sizeOT::CmapSubtableFormat12999 static size_t get_sub_table_size (const hb_sorted_vector_t<CmapSubtableLongGroup> &groups_data)
1000 { return 16 + 12 * groups_data.length; }
1001
1002 private:
_is_gid_consecutiveOT::CmapSubtableFormat121003 static bool _is_gid_consecutive (hb_codepoint_t endCharCode,
1004 hb_codepoint_t startCharCode,
1005 hb_codepoint_t glyphID,
1006 hb_codepoint_t cp,
1007 hb_codepoint_t new_gid)
1008 {
1009 return (cp - 1 == endCharCode) &&
1010 new_gid == glyphID + (cp - startCharCode);
1011 }
1012
1013 };
1014
1015 struct CmapSubtableFormat13 : CmapSubtableLongSegmented<CmapSubtableFormat13>
1016 {
1017 static constexpr int increment = 0;
1018 static constexpr int formatNumber = 13;
1019
group_get_glyphOT::CmapSubtableFormat131020 static hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
1021 hb_codepoint_t u HB_UNUSED)
1022 { return group.glyphID; }
1023 };
1024
1025 typedef enum
1026 {
1027 GLYPH_VARIANT_NOT_FOUND = 0,
1028 GLYPH_VARIANT_FOUND = 1,
1029 GLYPH_VARIANT_USE_DEFAULT = 2
1030 } glyph_variant_t;
1031
1032 struct UnicodeValueRange
1033 {
cmpOT::UnicodeValueRange1034 int cmp (const hb_codepoint_t &codepoint) const
1035 {
1036 if (codepoint < startUnicodeValue) return -1;
1037 if (codepoint > startUnicodeValue + additionalCount) return +1;
1038 return 0;
1039 }
1040
sanitizeOT::UnicodeValueRange1041 bool sanitize (hb_sanitize_context_t *c) const
1042 {
1043 TRACE_SANITIZE (this);
1044 return_trace (c->check_struct (this));
1045 }
1046
1047 HBUINT24 startUnicodeValue; /* First value in this range. */
1048 HBUINT8 additionalCount; /* Number of additional values in this
1049 * range. */
1050 public:
1051 DEFINE_SIZE_STATIC (4);
1052 };
1053
1054 struct DefaultUVS : SortedArray32Of<UnicodeValueRange>
1055 {
collect_unicodesOT::DefaultUVS1056 void collect_unicodes (hb_set_t *out) const
1057 {
1058 unsigned int count = len;
1059 for (unsigned int i = 0; i < count; i++)
1060 {
1061 hb_codepoint_t first = arrayZ[i].startUnicodeValue;
1062 hb_codepoint_t last = hb_min ((hb_codepoint_t) (first + arrayZ[i].additionalCount),
1063 (hb_codepoint_t) HB_UNICODE_MAX);
1064 out->add_range (first, last);
1065 }
1066 }
1067
copyOT::DefaultUVS1068 DefaultUVS* copy (hb_serialize_context_t *c,
1069 const hb_set_t *unicodes) const
1070 {
1071 auto *out = c->start_embed<DefaultUVS> ();
1072 auto snap = c->snapshot ();
1073
1074 HBUINT32 len;
1075 len = 0;
1076 if (unlikely (!c->copy<HBUINT32> (len))) return nullptr;
1077 unsigned init_len = c->length ();
1078
1079 if (this->len > unicodes->get_population () * hb_bit_storage ((unsigned) this->len))
1080 {
1081 hb_codepoint_t start = HB_SET_VALUE_INVALID;
1082 hb_codepoint_t end = HB_SET_VALUE_INVALID;
1083
1084 for (auto u : *unicodes)
1085 {
1086 if (!as_array ().bsearch (u))
1087 continue;
1088 if (start == HB_SET_VALUE_INVALID)
1089 {
1090 start = u;
1091 end = start - 1;
1092 }
1093 if (end + 1 != u || end - start == 255)
1094 {
1095 UnicodeValueRange rec;
1096 rec.startUnicodeValue = start;
1097 rec.additionalCount = end - start;
1098 c->copy<UnicodeValueRange> (rec);
1099 start = u;
1100 }
1101 end = u;
1102 }
1103 if (start != HB_SET_VALUE_INVALID)
1104 {
1105 UnicodeValueRange rec;
1106 rec.startUnicodeValue = start;
1107 rec.additionalCount = end - start;
1108 c->copy<UnicodeValueRange> (rec);
1109 }
1110
1111 }
1112 else
1113 {
1114 hb_codepoint_t lastCode = HB_SET_VALUE_INVALID;
1115 int count = -1;
1116
1117 for (const UnicodeValueRange& _ : *this)
1118 {
1119 hb_codepoint_t curEntry = (hb_codepoint_t) (_.startUnicodeValue - 1);
1120 hb_codepoint_t end = curEntry + _.additionalCount + 2;
1121
1122 for (; unicodes->next (&curEntry) && curEntry < end;)
1123 {
1124 count += 1;
1125 if (lastCode == HB_SET_VALUE_INVALID)
1126 lastCode = curEntry;
1127 else if (lastCode + count != curEntry)
1128 {
1129 UnicodeValueRange rec;
1130 rec.startUnicodeValue = lastCode;
1131 rec.additionalCount = count - 1;
1132 c->copy<UnicodeValueRange> (rec);
1133
1134 lastCode = curEntry;
1135 count = 0;
1136 }
1137 }
1138 }
1139
1140 if (lastCode != HB_MAP_VALUE_INVALID)
1141 {
1142 UnicodeValueRange rec;
1143 rec.startUnicodeValue = lastCode;
1144 rec.additionalCount = count;
1145 c->copy<UnicodeValueRange> (rec);
1146 }
1147 }
1148
1149 if (c->length () - init_len == 0)
1150 {
1151 c->revert (snap);
1152 return nullptr;
1153 }
1154 else
1155 {
1156 if (unlikely (!c->check_assign (out->len,
1157 (c->length () - init_len) / UnicodeValueRange::static_size,
1158 HB_SERIALIZE_ERROR_INT_OVERFLOW))) return nullptr;
1159 return out;
1160 }
1161 }
1162
1163 public:
1164 DEFINE_SIZE_ARRAY (4, *this);
1165 };
1166
1167 struct UVSMapping
1168 {
cmpOT::UVSMapping1169 int cmp (const hb_codepoint_t &codepoint) const
1170 { return unicodeValue.cmp (codepoint); }
1171
sanitizeOT::UVSMapping1172 bool sanitize (hb_sanitize_context_t *c) const
1173 {
1174 TRACE_SANITIZE (this);
1175 return_trace (c->check_struct (this));
1176 }
1177
1178 HBUINT24 unicodeValue; /* Base Unicode value of the UVS */
1179 HBGlyphID16 glyphID; /* Glyph ID of the UVS */
1180 public:
1181 DEFINE_SIZE_STATIC (5);
1182 };
1183
1184 struct NonDefaultUVS : SortedArray32Of<UVSMapping>
1185 {
collect_unicodesOT::NonDefaultUVS1186 void collect_unicodes (hb_set_t *out) const
1187 {
1188 for (const auto& a : as_array ())
1189 out->add (a.unicodeValue);
1190 }
1191
collect_mappingOT::NonDefaultUVS1192 void collect_mapping (hb_set_t *unicodes, /* OUT */
1193 hb_map_t *mapping /* OUT */) const
1194 {
1195 for (const auto& a : as_array ())
1196 {
1197 hb_codepoint_t unicode = a.unicodeValue;
1198 hb_codepoint_t glyphid = a.glyphID;
1199 unicodes->add (unicode);
1200 mapping->set (unicode, glyphid);
1201 }
1202 }
1203
closure_glyphsOT::NonDefaultUVS1204 void closure_glyphs (const hb_set_t *unicodes,
1205 hb_set_t *glyphset) const
1206 {
1207 + as_array ()
1208 | hb_filter (unicodes, &UVSMapping::unicodeValue)
1209 | hb_map (&UVSMapping::glyphID)
1210 | hb_sink (glyphset)
1211 ;
1212 }
1213
copyOT::NonDefaultUVS1214 NonDefaultUVS* copy (hb_serialize_context_t *c,
1215 const hb_set_t *unicodes,
1216 const hb_set_t *glyphs_requested,
1217 const hb_map_t *glyph_map) const
1218 {
1219 auto *out = c->start_embed<NonDefaultUVS> ();
1220 auto it =
1221 + as_array ()
1222 | hb_filter ([&] (const UVSMapping& _)
1223 {
1224 return unicodes->has (_.unicodeValue) || glyphs_requested->has (_.glyphID);
1225 })
1226 ;
1227
1228 if (!it) return nullptr;
1229
1230 HBUINT32 len;
1231 len = it.len ();
1232 if (unlikely (!c->copy<HBUINT32> (len))) return nullptr;
1233
1234 for (const UVSMapping& _ : it)
1235 {
1236 UVSMapping mapping;
1237 mapping.unicodeValue = _.unicodeValue;
1238 mapping.glyphID = glyph_map->get (_.glyphID);
1239 c->copy<UVSMapping> (mapping);
1240 }
1241
1242 return out;
1243 }
1244
1245 public:
1246 DEFINE_SIZE_ARRAY (4, *this);
1247 };
1248
1249 struct VariationSelectorRecord
1250 {
get_glyphOT::VariationSelectorRecord1251 glyph_variant_t get_glyph (hb_codepoint_t codepoint,
1252 hb_codepoint_t *glyph,
1253 const void *base) const
1254 {
1255 if ((base+defaultUVS).bfind (codepoint))
1256 return GLYPH_VARIANT_USE_DEFAULT;
1257 const UVSMapping &nonDefault = (base+nonDefaultUVS).bsearch (codepoint);
1258 if (nonDefault.glyphID)
1259 {
1260 *glyph = nonDefault.glyphID;
1261 return GLYPH_VARIANT_FOUND;
1262 }
1263 return GLYPH_VARIANT_NOT_FOUND;
1264 }
1265
VariationSelectorRecordOT::VariationSelectorRecord1266 VariationSelectorRecord(const VariationSelectorRecord& other)
1267 {
1268 *this = other;
1269 }
1270
operator =OT::VariationSelectorRecord1271 void operator= (const VariationSelectorRecord& other)
1272 {
1273 varSelector = other.varSelector;
1274 HBUINT32 offset = other.defaultUVS;
1275 defaultUVS = offset;
1276 offset = other.nonDefaultUVS;
1277 nonDefaultUVS = offset;
1278 }
1279
collect_unicodesOT::VariationSelectorRecord1280 void collect_unicodes (hb_set_t *out, const void *base) const
1281 {
1282 (base+defaultUVS).collect_unicodes (out);
1283 (base+nonDefaultUVS).collect_unicodes (out);
1284 }
1285
collect_mappingOT::VariationSelectorRecord1286 void collect_mapping (const void *base,
1287 hb_set_t *unicodes, /* OUT */
1288 hb_map_t *mapping /* OUT */) const
1289 {
1290 (base+defaultUVS).collect_unicodes (unicodes);
1291 (base+nonDefaultUVS).collect_mapping (unicodes, mapping);
1292 }
1293
cmpOT::VariationSelectorRecord1294 int cmp (const hb_codepoint_t &variation_selector) const
1295 { return varSelector.cmp (variation_selector); }
1296
sanitizeOT::VariationSelectorRecord1297 bool sanitize (hb_sanitize_context_t *c, const void *base) const
1298 {
1299 TRACE_SANITIZE (this);
1300 return_trace (c->check_struct (this) &&
1301 defaultUVS.sanitize (c, base) &&
1302 nonDefaultUVS.sanitize (c, base));
1303 }
1304
1305 hb_pair_t<unsigned, unsigned>
copyOT::VariationSelectorRecord1306 copy (hb_serialize_context_t *c,
1307 const hb_set_t *unicodes,
1308 const hb_set_t *glyphs_requested,
1309 const hb_map_t *glyph_map,
1310 const void *base) const
1311 {
1312 auto snap = c->snapshot ();
1313 auto *out = c->embed<VariationSelectorRecord> (*this);
1314 if (unlikely (!out)) return hb_pair (0, 0);
1315
1316 out->defaultUVS = 0;
1317 out->nonDefaultUVS = 0;
1318
1319 unsigned non_default_uvs_objidx = 0;
1320 if (nonDefaultUVS != 0)
1321 {
1322 c->push ();
1323 if (c->copy (base+nonDefaultUVS, unicodes, glyphs_requested, glyph_map))
1324 non_default_uvs_objidx = c->pop_pack ();
1325 else c->pop_discard ();
1326 }
1327
1328 unsigned default_uvs_objidx = 0;
1329 if (defaultUVS != 0)
1330 {
1331 c->push ();
1332 if (c->copy (base+defaultUVS, unicodes))
1333 default_uvs_objidx = c->pop_pack ();
1334 else c->pop_discard ();
1335 }
1336
1337
1338 if (!default_uvs_objidx && !non_default_uvs_objidx)
1339 c->revert (snap);
1340
1341 return hb_pair (default_uvs_objidx, non_default_uvs_objidx);
1342 }
1343
1344 HBUINT24 varSelector; /* Variation selector. */
1345 Offset32To<DefaultUVS>
1346 defaultUVS; /* Offset to Default UVS Table. May be 0. */
1347 Offset32To<NonDefaultUVS>
1348 nonDefaultUVS; /* Offset to Non-Default UVS Table. May be 0. */
1349 public:
1350 DEFINE_SIZE_STATIC (11);
1351 };
1352
1353 struct CmapSubtableFormat14
1354 {
get_glyph_variantOT::CmapSubtableFormat141355 glyph_variant_t get_glyph_variant (hb_codepoint_t codepoint,
1356 hb_codepoint_t variation_selector,
1357 hb_codepoint_t *glyph) const
1358 { return record.bsearch (variation_selector).get_glyph (codepoint, glyph, this); }
1359
collect_variation_selectorsOT::CmapSubtableFormat141360 void collect_variation_selectors (hb_set_t *out) const
1361 {
1362 for (const auto& a : record.as_array ())
1363 out->add (a.varSelector);
1364 }
collect_variation_unicodesOT::CmapSubtableFormat141365 void collect_variation_unicodes (hb_codepoint_t variation_selector,
1366 hb_set_t *out) const
1367 { record.bsearch (variation_selector).collect_unicodes (out, this); }
1368
serializeOT::CmapSubtableFormat141369 void serialize (hb_serialize_context_t *c,
1370 const hb_set_t *unicodes,
1371 const hb_set_t *glyphs_requested,
1372 const hb_map_t *glyph_map,
1373 const void *base)
1374 {
1375 auto snap = c->snapshot ();
1376 unsigned table_initpos = c->length ();
1377 const char* init_tail = c->tail;
1378
1379 if (unlikely (!c->extend_min (this))) return;
1380 this->format = 14;
1381
1382 auto src_tbl = reinterpret_cast<const CmapSubtableFormat14*> (base);
1383
1384 /*
1385 * Some versions of OTS require that offsets are in order. Due to the use
1386 * of push()/pop_pack() serializing the variation records in order results
1387 * in the offsets being in reverse order (first record has the largest
1388 * offset). While this is perfectly valid, it will cause some versions of
1389 * OTS to consider this table bad.
1390 *
1391 * So to prevent this issue we serialize the variation records in reverse
1392 * order, so that the offsets are ordered from small to large. Since
1393 * variation records are supposed to be in increasing order of varSelector
1394 * we then have to reverse the order of the written variation selector
1395 * records after everything is finalized.
1396 */
1397 hb_vector_t<hb_pair_t<unsigned, unsigned>> obj_indices;
1398 for (int i = src_tbl->record.len - 1; i >= 0; i--)
1399 {
1400 if (!unicodes->has(src_tbl->record[i].varSelector))
1401 continue;
1402
1403 hb_pair_t<unsigned, unsigned> result = src_tbl->record[i].copy (c, unicodes, glyphs_requested, glyph_map, base);
1404 if (result.first || result.second)
1405 obj_indices.push (result);
1406 }
1407
1408 if (c->length () - table_initpos == CmapSubtableFormat14::min_size)
1409 {
1410 c->revert (snap);
1411 return;
1412 }
1413
1414 if (unlikely (!c->check_success (!obj_indices.in_error ())))
1415 return;
1416
1417 int tail_len = init_tail - c->tail;
1418 c->check_assign (this->length, c->length () - table_initpos + tail_len,
1419 HB_SERIALIZE_ERROR_INT_OVERFLOW);
1420 c->check_assign (this->record.len,
1421 (c->length () - table_initpos - CmapSubtableFormat14::min_size) /
1422 VariationSelectorRecord::static_size,
1423 HB_SERIALIZE_ERROR_INT_OVERFLOW);
1424
1425 /* Correct the incorrect write order by reversing the order of the variation
1426 records array. */
1427 _reverse_variation_records ();
1428
1429 /* Now that records are in the right order, we can set up the offsets. */
1430 _add_links_to_variation_records (c, obj_indices);
1431 }
1432
_reverse_variation_recordsOT::CmapSubtableFormat141433 void _reverse_variation_records ()
1434 {
1435 record.as_array ().reverse ();
1436 }
1437
_add_links_to_variation_recordsOT::CmapSubtableFormat141438 void _add_links_to_variation_records (hb_serialize_context_t *c,
1439 const hb_vector_t<hb_pair_t<unsigned, unsigned>>& obj_indices)
1440 {
1441 for (unsigned i = 0; i < obj_indices.length; i++)
1442 {
1443 /*
1444 * Since the record array has been reversed (see comments in copy())
1445 * but obj_indices has not been, the indices at obj_indices[i]
1446 * are for the variation record at record[j].
1447 */
1448 int j = obj_indices.length - 1 - i;
1449 c->add_link (record[j].defaultUVS, obj_indices[i].first);
1450 c->add_link (record[j].nonDefaultUVS, obj_indices[i].second);
1451 }
1452 }
1453
closure_glyphsOT::CmapSubtableFormat141454 void closure_glyphs (const hb_set_t *unicodes,
1455 hb_set_t *glyphset) const
1456 {
1457 + hb_iter (record)
1458 | hb_filter (hb_bool, &VariationSelectorRecord::nonDefaultUVS)
1459 | hb_filter (unicodes, &VariationSelectorRecord::varSelector)
1460 | hb_map (&VariationSelectorRecord::nonDefaultUVS)
1461 | hb_map (hb_add (this))
1462 | hb_apply ([=] (const NonDefaultUVS& _) { _.closure_glyphs (unicodes, glyphset); })
1463 ;
1464 }
1465
collect_unicodesOT::CmapSubtableFormat141466 void collect_unicodes (hb_set_t *out) const
1467 {
1468 for (const VariationSelectorRecord& _ : record)
1469 _.collect_unicodes (out, this);
1470 }
1471
collect_mappingOT::CmapSubtableFormat141472 void collect_mapping (hb_set_t *unicodes, /* OUT */
1473 hb_map_t *mapping /* OUT */) const
1474 {
1475 for (const VariationSelectorRecord& _ : record)
1476 _.collect_mapping (this, unicodes, mapping);
1477 }
1478
sanitizeOT::CmapSubtableFormat141479 bool sanitize (hb_sanitize_context_t *c) const
1480 {
1481 TRACE_SANITIZE (this);
1482 return_trace (c->check_struct (this) &&
1483 record.sanitize (c, this));
1484 }
1485
1486 protected:
1487 HBUINT16 format; /* Format number is set to 14. */
1488 HBUINT32 length; /* Byte length of this subtable. */
1489 SortedArray32Of<VariationSelectorRecord>
1490 record; /* Variation selector records; sorted
1491 * in increasing order of `varSelector'. */
1492 public:
1493 DEFINE_SIZE_ARRAY (10, record);
1494 };
1495
1496 struct CmapSubtable
1497 {
1498 /* Note: We intentionally do NOT implement subtable formats 2 and 8. */
1499
get_glyphOT::CmapSubtable1500 bool get_glyph (hb_codepoint_t codepoint,
1501 hb_codepoint_t *glyph) const
1502 {
1503 switch (u.format) {
1504 case 0: hb_barrier (); return u.format0 .get_glyph (codepoint, glyph);
1505 case 4: hb_barrier (); return u.format4 .get_glyph (codepoint, glyph);
1506 case 6: hb_barrier (); return u.format6 .get_glyph (codepoint, glyph);
1507 case 10: hb_barrier (); return u.format10.get_glyph (codepoint, glyph);
1508 case 12: hb_barrier (); return u.format12.get_glyph (codepoint, glyph);
1509 case 13: hb_barrier (); return u.format13.get_glyph (codepoint, glyph);
1510 case 14:
1511 default: return false;
1512 }
1513 }
collect_unicodesOT::CmapSubtable1514 void collect_unicodes (hb_set_t *out, unsigned int num_glyphs = UINT_MAX) const
1515 {
1516 switch (u.format) {
1517 case 0: hb_barrier (); u.format0 .collect_unicodes (out); return;
1518 case 4: hb_barrier (); u.format4 .collect_unicodes (out); return;
1519 case 6: hb_barrier (); u.format6 .collect_unicodes (out); return;
1520 case 10: hb_barrier (); u.format10.collect_unicodes (out); return;
1521 case 12: hb_barrier (); u.format12.collect_unicodes (out, num_glyphs); return;
1522 case 13: hb_barrier (); u.format13.collect_unicodes (out, num_glyphs); return;
1523 case 14:
1524 default: return;
1525 }
1526 }
1527
collect_mappingOT::CmapSubtable1528 void collect_mapping (hb_set_t *unicodes, /* OUT */
1529 hb_map_t *mapping, /* OUT */
1530 unsigned num_glyphs = UINT_MAX) const
1531 {
1532 switch (u.format) {
1533 case 0: hb_barrier (); u.format0 .collect_mapping (unicodes, mapping); return;
1534 case 4: hb_barrier (); u.format4 .collect_mapping (unicodes, mapping); return;
1535 case 6: hb_barrier (); u.format6 .collect_mapping (unicodes, mapping); return;
1536 case 10: hb_barrier (); u.format10.collect_mapping (unicodes, mapping); return;
1537 case 12: hb_barrier (); u.format12.collect_mapping (unicodes, mapping, num_glyphs); return;
1538 case 13: hb_barrier (); u.format13.collect_mapping (unicodes, mapping, num_glyphs); return;
1539 case 14:
1540 default: return;
1541 }
1542 }
1543
get_languageOT::CmapSubtable1544 unsigned get_language () const
1545 {
1546 switch (u.format) {
1547 case 0: hb_barrier (); return u.format0 .get_language ();
1548 case 4: hb_barrier (); return u.format4 .get_language ();
1549 case 6: hb_barrier (); return u.format6 .get_language ();
1550 case 10: hb_barrier (); return u.format10.get_language ();
1551 case 12: hb_barrier (); return u.format12.get_language ();
1552 case 13: hb_barrier (); return u.format13.get_language ();
1553 case 14:
1554 default: return 0;
1555 }
1556 }
1557
1558 template<typename Iterator,
1559 hb_requires (hb_is_iterator (Iterator))>
serializeOT::CmapSubtable1560 void serialize (hb_serialize_context_t *c,
1561 Iterator it,
1562 unsigned format,
1563 const hb_subset_plan_t *plan,
1564 const void *base)
1565 {
1566 switch (format) {
1567 case 4: hb_barrier (); return u.format4.serialize (c, it);
1568 case 12: hb_barrier (); return u.format12.serialize (c, it);
1569 case 14: hb_barrier (); return u.format14.serialize (c, &plan->unicodes, &plan->glyphs_requested, plan->glyph_map, base);
1570 default: return;
1571 }
1572 }
1573
sanitizeOT::CmapSubtable1574 bool sanitize (hb_sanitize_context_t *c) const
1575 {
1576 TRACE_SANITIZE (this);
1577 if (!u.format.sanitize (c)) return_trace (false);
1578 hb_barrier ();
1579 switch (u.format) {
1580 case 0: hb_barrier (); return_trace (u.format0 .sanitize (c));
1581 case 4: hb_barrier (); return_trace (u.format4 .sanitize (c));
1582 case 6: hb_barrier (); return_trace (u.format6 .sanitize (c));
1583 case 10: hb_barrier (); return_trace (u.format10.sanitize (c));
1584 case 12: hb_barrier (); return_trace (u.format12.sanitize (c));
1585 case 13: hb_barrier (); return_trace (u.format13.sanitize (c));
1586 case 14: hb_barrier (); return_trace (u.format14.sanitize (c));
1587 default:return_trace (true);
1588 }
1589 }
1590
1591 public:
1592 union {
1593 HBUINT16 format; /* Format identifier */
1594 CmapSubtableFormat0 format0;
1595 CmapSubtableFormat4 format4;
1596 CmapSubtableFormat6 format6;
1597 CmapSubtableFormat10 format10;
1598 CmapSubtableFormat12 format12;
1599 CmapSubtableFormat13 format13;
1600 CmapSubtableFormat14 format14;
1601 } u;
1602 public:
1603 DEFINE_SIZE_UNION (2, format);
1604 };
1605
1606
1607 struct EncodingRecord
1608 {
cmpOT::EncodingRecord1609 int cmp (const EncodingRecord &other) const
1610 {
1611 int ret;
1612 ret = platformID.cmp (other.platformID);
1613 if (ret) return ret;
1614 if (other.encodingID != 0xFFFF)
1615 {
1616 ret = encodingID.cmp (other.encodingID);
1617 if (ret) return ret;
1618 }
1619 return 0;
1620 }
1621
sanitizeOT::EncodingRecord1622 bool sanitize (hb_sanitize_context_t *c, const void *base) const
1623 {
1624 TRACE_SANITIZE (this);
1625 return_trace (c->check_struct (this) &&
1626 subtable.sanitize (c, base));
1627 }
1628
1629 template<typename Iterator,
1630 hb_requires (hb_is_iterator (Iterator))>
copyOT::EncodingRecord1631 EncodingRecord* copy (hb_serialize_context_t *c,
1632 Iterator it,
1633 unsigned format,
1634 const void *base,
1635 const hb_subset_plan_t *plan,
1636 /* INOUT */ unsigned *objidx) const
1637 {
1638 TRACE_SERIALIZE (this);
1639 auto snap = c->snapshot ();
1640 auto *out = c->embed (this);
1641 if (unlikely (!out)) return_trace (nullptr);
1642 out->subtable = 0;
1643
1644 if (*objidx == 0)
1645 {
1646 CmapSubtable *cmapsubtable = c->push<CmapSubtable> ();
1647 unsigned origin_length = c->length ();
1648 cmapsubtable->serialize (c, it, format, plan, &(base+subtable));
1649 if (c->length () - origin_length > 0) *objidx = c->pop_pack ();
1650 else c->pop_discard ();
1651 }
1652
1653 if (*objidx == 0)
1654 {
1655 c->revert (snap);
1656 return_trace (nullptr);
1657 }
1658
1659 c->add_link (out->subtable, *objidx);
1660 return_trace (out);
1661 }
1662
1663 HBUINT16 platformID; /* Platform ID. */
1664 HBUINT16 encodingID; /* Platform-specific encoding ID. */
1665 Offset32To<CmapSubtable>
1666 subtable; /* Byte offset from beginning of table to the subtable for this encoding. */
1667 public:
1668 DEFINE_SIZE_STATIC (8);
1669 };
1670
1671 struct cmap;
1672
1673 struct SubtableUnicodesCache {
1674
1675 private:
1676 hb_blob_ptr_t<cmap> base_blob;
1677 const char* base;
1678 hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> cached_unicodes;
1679
1680 public:
1681
createOT::SubtableUnicodesCache1682 static SubtableUnicodesCache* create (hb_blob_ptr_t<cmap> source_table)
1683 {
1684 SubtableUnicodesCache* cache =
1685 (SubtableUnicodesCache*) hb_malloc (sizeof(SubtableUnicodesCache));
1686 new (cache) SubtableUnicodesCache (source_table);
1687 return cache;
1688 }
1689
destroyOT::SubtableUnicodesCache1690 static void destroy (void* value) {
1691 if (!value) return;
1692
1693 SubtableUnicodesCache* cache = (SubtableUnicodesCache*) value;
1694 cache->~SubtableUnicodesCache ();
1695 hb_free (cache);
1696 }
1697
SubtableUnicodesCacheOT::SubtableUnicodesCache1698 SubtableUnicodesCache(const void* cmap_base)
1699 : base_blob(),
1700 base ((const char*) cmap_base),
1701 cached_unicodes ()
1702 {}
1703
SubtableUnicodesCacheOT::SubtableUnicodesCache1704 SubtableUnicodesCache(hb_blob_ptr_t<cmap> base_blob_)
1705 : base_blob(base_blob_),
1706 base ((const char *) base_blob.get()),
1707 cached_unicodes ()
1708 {}
1709
~SubtableUnicodesCacheOT::SubtableUnicodesCache1710 ~SubtableUnicodesCache()
1711 {
1712 base_blob.destroy ();
1713 }
1714
same_baseOT::SubtableUnicodesCache1715 bool same_base(const void* other) const
1716 {
1717 return other == (const void*) base;
1718 }
1719
set_forOT::SubtableUnicodesCache1720 const hb_set_t* set_for (const EncodingRecord* record,
1721 SubtableUnicodesCache& mutable_cache) const
1722 {
1723 if (cached_unicodes.has ((unsigned) ((const char *) record - base)))
1724 return cached_unicodes.get ((unsigned) ((const char *) record - base));
1725
1726 return mutable_cache.set_for (record);
1727 }
1728
set_forOT::SubtableUnicodesCache1729 const hb_set_t* set_for (const EncodingRecord* record)
1730 {
1731 if (!cached_unicodes.has ((unsigned) ((const char *) record - base)))
1732 {
1733 hb_set_t *s = hb_set_create ();
1734 if (unlikely (s->in_error ()))
1735 return hb_set_get_empty ();
1736
1737 (base+record->subtable).collect_unicodes (s);
1738
1739 if (unlikely (!cached_unicodes.set ((unsigned) ((const char *) record - base), hb::unique_ptr<hb_set_t> {s})))
1740 return hb_set_get_empty ();
1741
1742 return s;
1743 }
1744 return cached_unicodes.get ((unsigned) ((const char *) record - base));
1745 }
1746
1747 };
1748
1749 static inline uint_fast16_t
_hb_symbol_pua_map(unsigned codepoint)1750 _hb_symbol_pua_map (unsigned codepoint)
1751 {
1752 if (codepoint <= 0x00FFu)
1753 {
1754 /* For symbol-encoded OpenType fonts, we duplicate the
1755 * U+F000..F0FF range at U+0000..U+00FF. That's what
1756 * Windows seems to do, and that's hinted about at:
1757 * https://docs.microsoft.com/en-us/typography/opentype/spec/recom
1758 * under "Non-Standard (Symbol) Fonts". */
1759 return 0xF000u + codepoint;
1760 }
1761 return 0;
1762 }
1763
1764 struct cmap
1765 {
1766 static constexpr hb_tag_t tableTag = HB_OT_TAG_cmap;
1767
1768
create_filled_cacheOT::cmap1769 static SubtableUnicodesCache* create_filled_cache(hb_blob_ptr_t<cmap> source_table) {
1770 const cmap* cmap = source_table.get();
1771 auto it =
1772 + hb_iter (cmap->encodingRecord)
1773 | hb_filter ([&](const EncodingRecord& _) {
1774 return cmap::filter_encoding_records_for_subset (cmap, _);
1775 })
1776 ;
1777
1778 SubtableUnicodesCache* cache = SubtableUnicodesCache::create(source_table);
1779 for (const EncodingRecord& _ : it)
1780 cache->set_for(&_); // populate the cache for this encoding record.
1781
1782 return cache;
1783 }
1784
1785 template<typename Iterator, typename EncodingRecIter,
1786 hb_requires (hb_is_iterator (EncodingRecIter))>
serializeOT::cmap1787 bool serialize (hb_serialize_context_t *c,
1788 Iterator it,
1789 EncodingRecIter encodingrec_iter,
1790 const void *base,
1791 hb_subset_plan_t *plan,
1792 bool drop_format_4 = false)
1793 {
1794 if (unlikely (!c->extend_min ((*this)))) return false;
1795 this->version = 0;
1796
1797 unsigned format4objidx = 0, format12objidx = 0, format14objidx = 0;
1798 auto snap = c->snapshot ();
1799
1800 SubtableUnicodesCache local_unicodes_cache (base);
1801 const SubtableUnicodesCache* unicodes_cache = &local_unicodes_cache;
1802
1803 if (plan->accelerator &&
1804 plan->accelerator->cmap_cache &&
1805 plan->accelerator->cmap_cache->same_base (base))
1806 unicodes_cache = plan->accelerator->cmap_cache;
1807
1808 for (const EncodingRecord& _ : encodingrec_iter)
1809 {
1810 if (c->in_error ())
1811 return false;
1812
1813 unsigned format = (base+_.subtable).u.format;
1814 if (format != 4 && format != 12 && format != 14) continue;
1815
1816 const hb_set_t* unicodes_set = unicodes_cache->set_for (&_, local_unicodes_cache);
1817
1818 if (!drop_format_4 && format == 4)
1819 {
1820 c->copy (_, + it | hb_filter (*unicodes_set, hb_first), 4u, base, plan, &format4objidx);
1821 if (c->in_error () && c->only_overflow ())
1822 {
1823 // cmap4 overflowed, reset and retry serialization without format 4 subtables.
1824 c->revert (snap);
1825 return serialize (c, it,
1826 encodingrec_iter,
1827 base,
1828 plan,
1829 true);
1830 }
1831 }
1832
1833 else if (format == 12)
1834 {
1835 if (_can_drop (_,
1836 *unicodes_set,
1837 base,
1838 *unicodes_cache,
1839 local_unicodes_cache,
1840 + it | hb_map (hb_first), encodingrec_iter))
1841 continue;
1842 c->copy (_, + it | hb_filter (*unicodes_set, hb_first), 12u, base, plan, &format12objidx);
1843 }
1844 else if (format == 14) c->copy (_, it, 14u, base, plan, &format14objidx);
1845 }
1846 c->check_assign(this->encodingRecord.len,
1847 (c->length () - cmap::min_size)/EncodingRecord::static_size,
1848 HB_SERIALIZE_ERROR_INT_OVERFLOW);
1849
1850 // Fail if format 4 was dropped and there is no cmap12.
1851 return !drop_format_4 || format12objidx;
1852 }
1853
1854 template<typename Iterator, typename EncodingRecordIterator,
1855 hb_requires (hb_is_iterator (Iterator)),
1856 hb_requires (hb_is_iterator (EncodingRecordIterator))>
_can_dropOT::cmap1857 bool _can_drop (const EncodingRecord& cmap12,
1858 const hb_set_t& cmap12_unicodes,
1859 const void* base,
1860 const SubtableUnicodesCache& unicodes_cache,
1861 SubtableUnicodesCache& local_unicodes_cache,
1862 Iterator subset_unicodes,
1863 EncodingRecordIterator encoding_records)
1864 {
1865 for (auto cp : + subset_unicodes | hb_filter (cmap12_unicodes))
1866 {
1867 if (cp >= 0x10000) return false;
1868 }
1869
1870 unsigned target_platform;
1871 unsigned target_encoding;
1872 unsigned target_language = (base+cmap12.subtable).get_language ();
1873
1874 if (cmap12.platformID == 0 && cmap12.encodingID == 4)
1875 {
1876 target_platform = 0;
1877 target_encoding = 3;
1878 } else if (cmap12.platformID == 3 && cmap12.encodingID == 10) {
1879 target_platform = 3;
1880 target_encoding = 1;
1881 } else {
1882 return false;
1883 }
1884
1885 for (const auto& _ : encoding_records)
1886 {
1887 if (_.platformID != target_platform
1888 || _.encodingID != target_encoding
1889 || (base+_.subtable).get_language() != target_language)
1890 continue;
1891
1892 const hb_set_t* sibling_unicodes = unicodes_cache.set_for (&_, local_unicodes_cache);
1893
1894 auto cmap12 = + subset_unicodes | hb_filter (cmap12_unicodes);
1895 auto sibling = + subset_unicodes | hb_filter (*sibling_unicodes);
1896 for (; cmap12 && sibling; cmap12++, sibling++)
1897 {
1898 unsigned a = *cmap12;
1899 unsigned b = *sibling;
1900 if (a != b) return false;
1901 }
1902
1903 return !cmap12 && !sibling;
1904 }
1905
1906 return false;
1907 }
1908
closure_glyphsOT::cmap1909 void closure_glyphs (const hb_set_t *unicodes,
1910 hb_set_t *glyphset) const
1911 {
1912 + hb_iter (encodingRecord)
1913 | hb_map (&EncodingRecord::subtable)
1914 | hb_map (hb_add (this))
1915 | hb_filter ([&] (const CmapSubtable& _) { return _.u.format == 14; })
1916 | hb_apply ([=] (const CmapSubtable& _) { _.u.format14.closure_glyphs (unicodes, glyphset); })
1917 ;
1918 }
1919
subsetOT::cmap1920 bool subset (hb_subset_context_t *c) const
1921 {
1922 TRACE_SUBSET (this);
1923
1924 cmap *cmap_prime = c->serializer->start_embed<cmap> ();
1925
1926 auto encodingrec_iter =
1927 + hb_iter (encodingRecord)
1928 | hb_filter ([&](const EncodingRecord& _) {
1929 return cmap::filter_encoding_records_for_subset (this, _);
1930 })
1931 ;
1932
1933 if (unlikely (!encodingrec_iter.len ())) return_trace (false);
1934
1935 const EncodingRecord *unicode_bmp= nullptr, *unicode_ucs4 = nullptr, *ms_bmp = nullptr, *ms_ucs4 = nullptr;
1936 bool has_format12 = false;
1937
1938 for (const EncodingRecord& _ : encodingrec_iter)
1939 {
1940 unsigned format = (this + _.subtable).u.format;
1941 if (format == 12) has_format12 = true;
1942
1943 const EncodingRecord *table = std::addressof (_);
1944 if (_.platformID == 0 && _.encodingID == 3) unicode_bmp = table;
1945 else if (_.platformID == 0 && _.encodingID == 4) unicode_ucs4 = table;
1946 else if (_.platformID == 3 && _.encodingID == 1) ms_bmp = table;
1947 else if (_.platformID == 3 && _.encodingID == 10) ms_ucs4 = table;
1948 }
1949
1950 if (unlikely (!has_format12 && !unicode_bmp && !ms_bmp)) return_trace (false);
1951 if (unlikely (has_format12 && (!unicode_ucs4 && !ms_ucs4))) return_trace (false);
1952
1953 auto it =
1954 + c->plan->unicode_to_new_gid_list.iter ()
1955 | hb_filter ([&] (const hb_codepoint_pair_t _)
1956 { return (_.second != HB_MAP_VALUE_INVALID); })
1957 ;
1958
1959 return_trace (cmap_prime->serialize (c->serializer,
1960 it,
1961 encodingrec_iter,
1962 this,
1963 c->plan));
1964 }
1965
find_best_subtableOT::cmap1966 const CmapSubtable *find_best_subtable (bool *symbol = nullptr,
1967 bool *mac = nullptr,
1968 bool *macroman = nullptr) const
1969 {
1970 if (symbol) *symbol = false;
1971 if (mac) *mac = false;
1972 if (macroman) *macroman = false;
1973
1974 const CmapSubtable *subtable;
1975
1976 /* Symbol subtable.
1977 * Prefer symbol if available.
1978 * https://github.com/harfbuzz/harfbuzz/issues/1918 */
1979 if ((subtable = this->find_subtable (3, 0)))
1980 {
1981 if (symbol) *symbol = true;
1982 return subtable;
1983 }
1984
1985 /* 32-bit subtables. */
1986 if ((subtable = this->find_subtable (3, 10))) return subtable;
1987 if ((subtable = this->find_subtable (0, 6))) return subtable;
1988 if ((subtable = this->find_subtable (0, 4))) return subtable;
1989
1990 /* 16-bit subtables. */
1991 if ((subtable = this->find_subtable (3, 1))) return subtable;
1992 if ((subtable = this->find_subtable (0, 3))) return subtable;
1993 if ((subtable = this->find_subtable (0, 2))) return subtable;
1994 if ((subtable = this->find_subtable (0, 1))) return subtable;
1995 if ((subtable = this->find_subtable (0, 0))) return subtable;
1996
1997 /* MacRoman subtable. */
1998 if ((subtable = this->find_subtable (1, 0)))
1999 {
2000 if (mac) *mac = true;
2001 if (macroman) *macroman = true;
2002 return subtable;
2003 }
2004 /* Any other Mac subtable; we just map ASCII for these. */
2005 if ((subtable = this->find_subtable (1, 0xFFFF)))
2006 {
2007 if (mac) *mac = true;
2008 return subtable;
2009 }
2010
2011 /* Meh. */
2012 return &Null (CmapSubtable);
2013 }
2014
2015 struct accelerator_t
2016 {
2017 using cache_t = hb_cache_t<21, 16, 8, true>;
2018
accelerator_tOT::cmap::accelerator_t2019 accelerator_t (hb_face_t *face)
2020 {
2021 this->table = hb_sanitize_context_t ().reference_table<cmap> (face);
2022 bool symbol, mac, macroman;
2023 this->subtable = table->find_best_subtable (&symbol, &mac, ¯oman);
2024 this->subtable_uvs = &Null (CmapSubtableFormat14);
2025 {
2026 const CmapSubtable *st = table->find_subtable (0, 5);
2027 if (st && st->u.format == 14)
2028 subtable_uvs = &st->u.format14;
2029 }
2030
2031 this->get_glyph_data = subtable;
2032 #ifndef HB_NO_CMAP_LEGACY_SUBTABLES
2033 if (unlikely (symbol))
2034 {
2035 switch ((unsigned) face->table.OS2->get_font_page ()) {
2036 case OS2::font_page_t::FONT_PAGE_NONE:
2037 this->get_glyph_funcZ = get_glyph_from_symbol<CmapSubtable, _hb_symbol_pua_map>;
2038 break;
2039 #ifndef HB_NO_OT_SHAPER_ARABIC_FALLBACK
2040 case OS2::font_page_t::FONT_PAGE_SIMP_ARABIC:
2041 this->get_glyph_funcZ = get_glyph_from_symbol<CmapSubtable, _hb_arabic_pua_simp_map>;
2042 break;
2043 case OS2::font_page_t::FONT_PAGE_TRAD_ARABIC:
2044 this->get_glyph_funcZ = get_glyph_from_symbol<CmapSubtable, _hb_arabic_pua_trad_map>;
2045 break;
2046 #endif
2047 default:
2048 this->get_glyph_funcZ = get_glyph_from<CmapSubtable>;
2049 break;
2050 }
2051 }
2052 else if (unlikely (macroman))
2053 {
2054 this->get_glyph_funcZ = get_glyph_from_macroman<CmapSubtable>;
2055 }
2056 else if (unlikely (mac))
2057 {
2058 this->get_glyph_funcZ = get_glyph_from_ascii<CmapSubtable>;
2059 }
2060 else
2061 #endif
2062 {
2063 switch (subtable->u.format) {
2064 /* Accelerate format 4 and format 12. */
2065 default:
2066 this->get_glyph_funcZ = get_glyph_from<CmapSubtable>;
2067 break;
2068 case 12:
2069 this->get_glyph_funcZ = get_glyph_from<CmapSubtableFormat12>;
2070 break;
2071 case 4:
2072 {
2073 this->format4_accel.init (&subtable->u.format4);
2074 this->get_glyph_data = &this->format4_accel;
2075 this->get_glyph_funcZ = this->format4_accel.get_glyph_func;
2076 break;
2077 }
2078 }
2079 }
2080 }
~accelerator_tOT::cmap::accelerator_t2081 ~accelerator_t () { this->table.destroy (); }
2082
_cached_getOT::cmap::accelerator_t2083 inline bool _cached_get (hb_codepoint_t unicode,
2084 hb_codepoint_t *glyph,
2085 cache_t *cache) const
2086 {
2087 unsigned v;
2088 if (cache && cache->get (unicode, &v))
2089 {
2090 *glyph = v;
2091 return true;
2092 }
2093 bool ret = this->get_glyph_funcZ (this->get_glyph_data, unicode, glyph);
2094
2095 if (cache && ret)
2096 cache->set (unicode, *glyph);
2097 return ret;
2098 }
2099
get_nominal_glyphOT::cmap::accelerator_t2100 bool get_nominal_glyph (hb_codepoint_t unicode,
2101 hb_codepoint_t *glyph,
2102 cache_t *cache = nullptr) const
2103 {
2104 if (unlikely (!this->get_glyph_funcZ)) return false;
2105 return _cached_get (unicode, glyph, cache);
2106 }
2107
get_nominal_glyphsOT::cmap::accelerator_t2108 unsigned int get_nominal_glyphs (unsigned int count,
2109 const hb_codepoint_t *first_unicode,
2110 unsigned int unicode_stride,
2111 hb_codepoint_t *first_glyph,
2112 unsigned int glyph_stride,
2113 cache_t *cache = nullptr) const
2114 {
2115 if (unlikely (!this->get_glyph_funcZ)) return 0;
2116
2117 unsigned int done;
2118 for (done = 0;
2119 done < count && _cached_get (*first_unicode, first_glyph, cache);
2120 done++)
2121 {
2122 first_unicode = &StructAtOffsetUnaligned<hb_codepoint_t> (first_unicode, unicode_stride);
2123 first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
2124 }
2125 return done;
2126 }
2127
get_variation_glyphOT::cmap::accelerator_t2128 bool get_variation_glyph (hb_codepoint_t unicode,
2129 hb_codepoint_t variation_selector,
2130 hb_codepoint_t *glyph,
2131 cache_t *cache = nullptr) const
2132 {
2133 switch (this->subtable_uvs->get_glyph_variant (unicode,
2134 variation_selector,
2135 glyph))
2136 {
2137 case GLYPH_VARIANT_NOT_FOUND: return false;
2138 case GLYPH_VARIANT_FOUND: return true;
2139 case GLYPH_VARIANT_USE_DEFAULT: break;
2140 }
2141
2142 return get_nominal_glyph (unicode, glyph, cache);
2143 }
2144
collect_unicodesOT::cmap::accelerator_t2145 void collect_unicodes (hb_set_t *out, unsigned int num_glyphs) const
2146 { subtable->collect_unicodes (out, num_glyphs); }
collect_mappingOT::cmap::accelerator_t2147 void collect_mapping (hb_set_t *unicodes, hb_map_t *mapping,
2148 unsigned num_glyphs = UINT_MAX) const
2149 { subtable->collect_mapping (unicodes, mapping, num_glyphs); }
collect_variation_selectorsOT::cmap::accelerator_t2150 void collect_variation_selectors (hb_set_t *out) const
2151 { subtable_uvs->collect_variation_selectors (out); }
collect_variation_unicodesOT::cmap::accelerator_t2152 void collect_variation_unicodes (hb_codepoint_t variation_selector,
2153 hb_set_t *out) const
2154 { subtable_uvs->collect_variation_unicodes (variation_selector, out); }
2155
2156 protected:
2157 typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj,
2158 hb_codepoint_t codepoint,
2159 hb_codepoint_t *glyph);
2160 typedef uint_fast16_t (*hb_pua_remap_func_t) (unsigned);
2161
2162 template <typename Type>
get_glyph_fromOT::cmap::accelerator_t2163 HB_INTERNAL static bool get_glyph_from (const void *obj,
2164 hb_codepoint_t codepoint,
2165 hb_codepoint_t *glyph)
2166 {
2167 const Type *typed_obj = (const Type *) obj;
2168 return typed_obj->get_glyph (codepoint, glyph);
2169 }
2170
2171 template <typename Type, hb_pua_remap_func_t remap>
get_glyph_from_symbolOT::cmap::accelerator_t2172 HB_INTERNAL static bool get_glyph_from_symbol (const void *obj,
2173 hb_codepoint_t codepoint,
2174 hb_codepoint_t *glyph)
2175 {
2176 const Type *typed_obj = (const Type *) obj;
2177 if (likely (typed_obj->get_glyph (codepoint, glyph)))
2178 return true;
2179
2180 if (hb_codepoint_t c = remap (codepoint))
2181 return typed_obj->get_glyph (c, glyph);
2182
2183 return false;
2184 }
2185
2186 template <typename Type>
get_glyph_from_asciiOT::cmap::accelerator_t2187 HB_INTERNAL static bool get_glyph_from_ascii (const void *obj,
2188 hb_codepoint_t codepoint,
2189 hb_codepoint_t *glyph)
2190 {
2191 const Type *typed_obj = (const Type *) obj;
2192 return codepoint < 0x80 && typed_obj->get_glyph (codepoint, glyph);
2193 }
2194
2195 template <typename Type>
get_glyph_from_macromanOT::cmap::accelerator_t2196 HB_INTERNAL static bool get_glyph_from_macroman (const void *obj,
2197 hb_codepoint_t codepoint,
2198 hb_codepoint_t *glyph)
2199 {
2200 if (get_glyph_from_ascii<Type> (obj, codepoint, glyph))
2201 return true;
2202
2203 const Type *typed_obj = (const Type *) obj;
2204 unsigned c = unicode_to_macroman (codepoint);
2205 return c && typed_obj->get_glyph (c, glyph);
2206 }
2207
2208 private:
2209 hb_nonnull_ptr_t<const CmapSubtable> subtable;
2210 hb_nonnull_ptr_t<const CmapSubtableFormat14> subtable_uvs;
2211
2212 hb_cmap_get_glyph_func_t get_glyph_funcZ;
2213 const void *get_glyph_data;
2214
2215 CmapSubtableFormat4::accelerator_t format4_accel;
2216
2217 public:
2218 hb_blob_ptr_t<cmap> table;
2219 };
2220
2221 protected:
2222
find_subtableOT::cmap2223 const CmapSubtable *find_subtable (unsigned int platform_id,
2224 unsigned int encoding_id) const
2225 {
2226 EncodingRecord key;
2227 key.platformID = platform_id;
2228 key.encodingID = encoding_id;
2229
2230 const EncodingRecord &result = encodingRecord.bsearch (key);
2231 if (!result.subtable)
2232 return nullptr;
2233
2234 return &(this+result.subtable);
2235 }
2236
2237 public:
2238
sanitizeOT::cmap2239 bool sanitize (hb_sanitize_context_t *c) const
2240 {
2241 TRACE_SANITIZE (this);
2242 return_trace (c->check_struct (this) &&
2243 hb_barrier () &&
2244 likely (version == 0) &&
2245 encodingRecord.sanitize (c, this));
2246 }
2247
2248 private:
2249
filter_encoding_records_for_subsetOT::cmap2250 static bool filter_encoding_records_for_subset(const cmap* cmap,
2251 const EncodingRecord& _)
2252 {
2253 return
2254 (_.platformID == 0 && _.encodingID == 3) ||
2255 (_.platformID == 0 && _.encodingID == 4) ||
2256 (_.platformID == 3 && _.encodingID == 1) ||
2257 (_.platformID == 3 && _.encodingID == 10) ||
2258 (cmap + _.subtable).u.format == 14;
2259 }
2260
2261 protected:
2262 HBUINT16 version; /* Table version number (0). */
2263 SortedArray16Of<EncodingRecord>
2264 encodingRecord; /* Encoding tables. */
2265 public:
2266 DEFINE_SIZE_ARRAY (4, encodingRecord);
2267 };
2268
2269 struct cmap_accelerator_t : cmap::accelerator_t {
cmap_accelerator_tOT::cmap_accelerator_t2270 cmap_accelerator_t (hb_face_t *face) : cmap::accelerator_t (face) {}
2271 };
2272
2273 } /* namespace OT */
2274
2275
2276 #endif /* HB_OT_CMAP_TABLE_HH */
2277