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 hb_pair_t<unsigned, unsigned> result = src_tbl->record[i].copy (c, unicodes, glyphs_requested, glyph_map, base);
1401 if (result.first || result.second)
1402 obj_indices.push (result);
1403 }
1404
1405 if (c->length () - table_initpos == CmapSubtableFormat14::min_size)
1406 {
1407 c->revert (snap);
1408 return;
1409 }
1410
1411 if (unlikely (!c->check_success (!obj_indices.in_error ())))
1412 return;
1413
1414 int tail_len = init_tail - c->tail;
1415 c->check_assign (this->length, c->length () - table_initpos + tail_len,
1416 HB_SERIALIZE_ERROR_INT_OVERFLOW);
1417 c->check_assign (this->record.len,
1418 (c->length () - table_initpos - CmapSubtableFormat14::min_size) /
1419 VariationSelectorRecord::static_size,
1420 HB_SERIALIZE_ERROR_INT_OVERFLOW);
1421
1422 /* Correct the incorrect write order by reversing the order of the variation
1423 records array. */
1424 _reverse_variation_records ();
1425
1426 /* Now that records are in the right order, we can set up the offsets. */
1427 _add_links_to_variation_records (c, obj_indices);
1428 }
1429
_reverse_variation_recordsOT::CmapSubtableFormat141430 void _reverse_variation_records ()
1431 {
1432 record.as_array ().reverse ();
1433 }
1434
_add_links_to_variation_recordsOT::CmapSubtableFormat141435 void _add_links_to_variation_records (hb_serialize_context_t *c,
1436 const hb_vector_t<hb_pair_t<unsigned, unsigned>>& obj_indices)
1437 {
1438 for (unsigned i = 0; i < obj_indices.length; i++)
1439 {
1440 /*
1441 * Since the record array has been reversed (see comments in copy())
1442 * but obj_indices has not been, the indices at obj_indices[i]
1443 * are for the variation record at record[j].
1444 */
1445 int j = obj_indices.length - 1 - i;
1446 c->add_link (record[j].defaultUVS, obj_indices[i].first);
1447 c->add_link (record[j].nonDefaultUVS, obj_indices[i].second);
1448 }
1449 }
1450
closure_glyphsOT::CmapSubtableFormat141451 void closure_glyphs (const hb_set_t *unicodes,
1452 hb_set_t *glyphset) const
1453 {
1454 + hb_iter (record)
1455 | hb_filter (hb_bool, &VariationSelectorRecord::nonDefaultUVS)
1456 | hb_map (&VariationSelectorRecord::nonDefaultUVS)
1457 | hb_map (hb_add (this))
1458 | hb_apply ([=] (const NonDefaultUVS& _) { _.closure_glyphs (unicodes, glyphset); })
1459 ;
1460 }
1461
collect_unicodesOT::CmapSubtableFormat141462 void collect_unicodes (hb_set_t *out) const
1463 {
1464 for (const VariationSelectorRecord& _ : record)
1465 _.collect_unicodes (out, this);
1466 }
1467
collect_mappingOT::CmapSubtableFormat141468 void collect_mapping (hb_set_t *unicodes, /* OUT */
1469 hb_map_t *mapping /* OUT */) const
1470 {
1471 for (const VariationSelectorRecord& _ : record)
1472 _.collect_mapping (this, unicodes, mapping);
1473 }
1474
sanitizeOT::CmapSubtableFormat141475 bool sanitize (hb_sanitize_context_t *c) const
1476 {
1477 TRACE_SANITIZE (this);
1478 return_trace (c->check_struct (this) &&
1479 record.sanitize (c, this));
1480 }
1481
1482 protected:
1483 HBUINT16 format; /* Format number is set to 14. */
1484 HBUINT32 length; /* Byte length of this subtable. */
1485 SortedArray32Of<VariationSelectorRecord>
1486 record; /* Variation selector records; sorted
1487 * in increasing order of `varSelector'. */
1488 public:
1489 DEFINE_SIZE_ARRAY (10, record);
1490 };
1491
1492 struct CmapSubtable
1493 {
1494 /* Note: We intentionally do NOT implement subtable formats 2 and 8. */
1495
get_glyphOT::CmapSubtable1496 bool get_glyph (hb_codepoint_t codepoint,
1497 hb_codepoint_t *glyph) const
1498 {
1499 switch (u.format) {
1500 case 0: hb_barrier (); return u.format0 .get_glyph (codepoint, glyph);
1501 case 4: hb_barrier (); return u.format4 .get_glyph (codepoint, glyph);
1502 case 6: hb_barrier (); return u.format6 .get_glyph (codepoint, glyph);
1503 case 10: hb_barrier (); return u.format10.get_glyph (codepoint, glyph);
1504 case 12: hb_barrier (); return u.format12.get_glyph (codepoint, glyph);
1505 case 13: hb_barrier (); return u.format13.get_glyph (codepoint, glyph);
1506 case 14:
1507 default: return false;
1508 }
1509 }
collect_unicodesOT::CmapSubtable1510 void collect_unicodes (hb_set_t *out, unsigned int num_glyphs = UINT_MAX) const
1511 {
1512 switch (u.format) {
1513 case 0: hb_barrier (); u.format0 .collect_unicodes (out); return;
1514 case 4: hb_barrier (); u.format4 .collect_unicodes (out); return;
1515 case 6: hb_barrier (); u.format6 .collect_unicodes (out); return;
1516 case 10: hb_barrier (); u.format10.collect_unicodes (out); return;
1517 case 12: hb_barrier (); u.format12.collect_unicodes (out, num_glyphs); return;
1518 case 13: hb_barrier (); u.format13.collect_unicodes (out, num_glyphs); return;
1519 case 14:
1520 default: return;
1521 }
1522 }
1523
collect_mappingOT::CmapSubtable1524 void collect_mapping (hb_set_t *unicodes, /* OUT */
1525 hb_map_t *mapping, /* OUT */
1526 unsigned num_glyphs = UINT_MAX) const
1527 {
1528 switch (u.format) {
1529 case 0: hb_barrier (); u.format0 .collect_mapping (unicodes, mapping); return;
1530 case 4: hb_barrier (); u.format4 .collect_mapping (unicodes, mapping); return;
1531 case 6: hb_barrier (); u.format6 .collect_mapping (unicodes, mapping); return;
1532 case 10: hb_barrier (); u.format10.collect_mapping (unicodes, mapping); return;
1533 case 12: hb_barrier (); u.format12.collect_mapping (unicodes, mapping, num_glyphs); return;
1534 case 13: hb_barrier (); u.format13.collect_mapping (unicodes, mapping, num_glyphs); return;
1535 case 14:
1536 default: return;
1537 }
1538 }
1539
get_languageOT::CmapSubtable1540 unsigned get_language () const
1541 {
1542 switch (u.format) {
1543 case 0: hb_barrier (); return u.format0 .get_language ();
1544 case 4: hb_barrier (); return u.format4 .get_language ();
1545 case 6: hb_barrier (); return u.format6 .get_language ();
1546 case 10: hb_barrier (); return u.format10.get_language ();
1547 case 12: hb_barrier (); return u.format12.get_language ();
1548 case 13: hb_barrier (); return u.format13.get_language ();
1549 case 14:
1550 default: return 0;
1551 }
1552 }
1553
1554 template<typename Iterator,
1555 hb_requires (hb_is_iterator (Iterator))>
serializeOT::CmapSubtable1556 void serialize (hb_serialize_context_t *c,
1557 Iterator it,
1558 unsigned format,
1559 const hb_subset_plan_t *plan,
1560 const void *base)
1561 {
1562 switch (format) {
1563 case 4: hb_barrier (); return u.format4.serialize (c, it);
1564 case 12: hb_barrier (); return u.format12.serialize (c, it);
1565 case 14: hb_barrier (); return u.format14.serialize (c, &plan->unicodes, &plan->glyphs_requested, plan->glyph_map, base);
1566 default: return;
1567 }
1568 }
1569
sanitizeOT::CmapSubtable1570 bool sanitize (hb_sanitize_context_t *c) const
1571 {
1572 TRACE_SANITIZE (this);
1573 if (!u.format.sanitize (c)) return_trace (false);
1574 hb_barrier ();
1575 switch (u.format) {
1576 case 0: hb_barrier (); return_trace (u.format0 .sanitize (c));
1577 case 4: hb_barrier (); return_trace (u.format4 .sanitize (c));
1578 case 6: hb_barrier (); return_trace (u.format6 .sanitize (c));
1579 case 10: hb_barrier (); return_trace (u.format10.sanitize (c));
1580 case 12: hb_barrier (); return_trace (u.format12.sanitize (c));
1581 case 13: hb_barrier (); return_trace (u.format13.sanitize (c));
1582 case 14: hb_barrier (); return_trace (u.format14.sanitize (c));
1583 default:return_trace (true);
1584 }
1585 }
1586
1587 public:
1588 union {
1589 HBUINT16 format; /* Format identifier */
1590 CmapSubtableFormat0 format0;
1591 CmapSubtableFormat4 format4;
1592 CmapSubtableFormat6 format6;
1593 CmapSubtableFormat10 format10;
1594 CmapSubtableFormat12 format12;
1595 CmapSubtableFormat13 format13;
1596 CmapSubtableFormat14 format14;
1597 } u;
1598 public:
1599 DEFINE_SIZE_UNION (2, format);
1600 };
1601
1602
1603 struct EncodingRecord
1604 {
cmpOT::EncodingRecord1605 int cmp (const EncodingRecord &other) const
1606 {
1607 int ret;
1608 ret = platformID.cmp (other.platformID);
1609 if (ret) return ret;
1610 if (other.encodingID != 0xFFFF)
1611 {
1612 ret = encodingID.cmp (other.encodingID);
1613 if (ret) return ret;
1614 }
1615 return 0;
1616 }
1617
sanitizeOT::EncodingRecord1618 bool sanitize (hb_sanitize_context_t *c, const void *base) const
1619 {
1620 TRACE_SANITIZE (this);
1621 return_trace (c->check_struct (this) &&
1622 subtable.sanitize (c, base));
1623 }
1624
1625 template<typename Iterator,
1626 hb_requires (hb_is_iterator (Iterator))>
copyOT::EncodingRecord1627 EncodingRecord* copy (hb_serialize_context_t *c,
1628 Iterator it,
1629 unsigned format,
1630 const void *base,
1631 const hb_subset_plan_t *plan,
1632 /* INOUT */ unsigned *objidx) const
1633 {
1634 TRACE_SERIALIZE (this);
1635 auto snap = c->snapshot ();
1636 auto *out = c->embed (this);
1637 if (unlikely (!out)) return_trace (nullptr);
1638 out->subtable = 0;
1639
1640 if (*objidx == 0)
1641 {
1642 CmapSubtable *cmapsubtable = c->push<CmapSubtable> ();
1643 unsigned origin_length = c->length ();
1644 cmapsubtable->serialize (c, it, format, plan, &(base+subtable));
1645 if (c->length () - origin_length > 0) *objidx = c->pop_pack ();
1646 else c->pop_discard ();
1647 }
1648
1649 if (*objidx == 0)
1650 {
1651 c->revert (snap);
1652 return_trace (nullptr);
1653 }
1654
1655 c->add_link (out->subtable, *objidx);
1656 return_trace (out);
1657 }
1658
1659 HBUINT16 platformID; /* Platform ID. */
1660 HBUINT16 encodingID; /* Platform-specific encoding ID. */
1661 Offset32To<CmapSubtable>
1662 subtable; /* Byte offset from beginning of table to the subtable for this encoding. */
1663 public:
1664 DEFINE_SIZE_STATIC (8);
1665 };
1666
1667 struct cmap;
1668
1669 struct SubtableUnicodesCache {
1670
1671 private:
1672 hb_blob_ptr_t<cmap> base_blob;
1673 const char* base;
1674 hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> cached_unicodes;
1675
1676 public:
1677
createOT::SubtableUnicodesCache1678 static SubtableUnicodesCache* create (hb_blob_ptr_t<cmap> source_table)
1679 {
1680 SubtableUnicodesCache* cache =
1681 (SubtableUnicodesCache*) hb_malloc (sizeof(SubtableUnicodesCache));
1682 new (cache) SubtableUnicodesCache (source_table);
1683 return cache;
1684 }
1685
destroyOT::SubtableUnicodesCache1686 static void destroy (void* value) {
1687 if (!value) return;
1688
1689 SubtableUnicodesCache* cache = (SubtableUnicodesCache*) value;
1690 cache->~SubtableUnicodesCache ();
1691 hb_free (cache);
1692 }
1693
SubtableUnicodesCacheOT::SubtableUnicodesCache1694 SubtableUnicodesCache(const void* cmap_base)
1695 : base_blob(),
1696 base ((const char*) cmap_base),
1697 cached_unicodes ()
1698 {}
1699
SubtableUnicodesCacheOT::SubtableUnicodesCache1700 SubtableUnicodesCache(hb_blob_ptr_t<cmap> base_blob_)
1701 : base_blob(base_blob_),
1702 base ((const char *) base_blob.get()),
1703 cached_unicodes ()
1704 {}
1705
~SubtableUnicodesCacheOT::SubtableUnicodesCache1706 ~SubtableUnicodesCache()
1707 {
1708 base_blob.destroy ();
1709 }
1710
same_baseOT::SubtableUnicodesCache1711 bool same_base(const void* other) const
1712 {
1713 return other == (const void*) base;
1714 }
1715
set_forOT::SubtableUnicodesCache1716 const hb_set_t* set_for (const EncodingRecord* record,
1717 SubtableUnicodesCache& mutable_cache) const
1718 {
1719 if (cached_unicodes.has ((unsigned) ((const char *) record - base)))
1720 return cached_unicodes.get ((unsigned) ((const char *) record - base));
1721
1722 return mutable_cache.set_for (record);
1723 }
1724
set_forOT::SubtableUnicodesCache1725 const hb_set_t* set_for (const EncodingRecord* record)
1726 {
1727 if (!cached_unicodes.has ((unsigned) ((const char *) record - base)))
1728 {
1729 hb_set_t *s = hb_set_create ();
1730 if (unlikely (s->in_error ()))
1731 return hb_set_get_empty ();
1732
1733 (base+record->subtable).collect_unicodes (s);
1734
1735 if (unlikely (!cached_unicodes.set ((unsigned) ((const char *) record - base), hb::unique_ptr<hb_set_t> {s})))
1736 return hb_set_get_empty ();
1737
1738 return s;
1739 }
1740 return cached_unicodes.get ((unsigned) ((const char *) record - base));
1741 }
1742
1743 };
1744
1745 static inline uint_fast16_t
_hb_symbol_pua_map(unsigned codepoint)1746 _hb_symbol_pua_map (unsigned codepoint)
1747 {
1748 if (codepoint <= 0x00FFu)
1749 {
1750 /* For symbol-encoded OpenType fonts, we duplicate the
1751 * U+F000..F0FF range at U+0000..U+00FF. That's what
1752 * Windows seems to do, and that's hinted about at:
1753 * https://docs.microsoft.com/en-us/typography/opentype/spec/recom
1754 * under "Non-Standard (Symbol) Fonts". */
1755 return 0xF000u + codepoint;
1756 }
1757 return 0;
1758 }
1759
1760 struct cmap
1761 {
1762 static constexpr hb_tag_t tableTag = HB_OT_TAG_cmap;
1763
1764
create_filled_cacheOT::cmap1765 static SubtableUnicodesCache* create_filled_cache(hb_blob_ptr_t<cmap> source_table) {
1766 const cmap* cmap = source_table.get();
1767 auto it =
1768 + hb_iter (cmap->encodingRecord)
1769 | hb_filter ([&](const EncodingRecord& _) {
1770 return cmap::filter_encoding_records_for_subset (cmap, _);
1771 })
1772 ;
1773
1774 SubtableUnicodesCache* cache = SubtableUnicodesCache::create(source_table);
1775 for (const EncodingRecord& _ : it)
1776 cache->set_for(&_); // populate the cache for this encoding record.
1777
1778 return cache;
1779 }
1780
1781 template<typename Iterator, typename EncodingRecIter,
1782 hb_requires (hb_is_iterator (EncodingRecIter))>
serializeOT::cmap1783 bool serialize (hb_serialize_context_t *c,
1784 Iterator it,
1785 EncodingRecIter encodingrec_iter,
1786 const void *base,
1787 hb_subset_plan_t *plan,
1788 bool drop_format_4 = false)
1789 {
1790 if (unlikely (!c->extend_min ((*this)))) return false;
1791 this->version = 0;
1792
1793 unsigned format4objidx = 0, format12objidx = 0, format14objidx = 0;
1794 auto snap = c->snapshot ();
1795
1796 SubtableUnicodesCache local_unicodes_cache (base);
1797 const SubtableUnicodesCache* unicodes_cache = &local_unicodes_cache;
1798
1799 if (plan->accelerator &&
1800 plan->accelerator->cmap_cache &&
1801 plan->accelerator->cmap_cache->same_base (base))
1802 unicodes_cache = plan->accelerator->cmap_cache;
1803
1804 for (const EncodingRecord& _ : encodingrec_iter)
1805 {
1806 if (c->in_error ())
1807 return false;
1808
1809 unsigned format = (base+_.subtable).u.format;
1810 if (format != 4 && format != 12 && format != 14) continue;
1811
1812 const hb_set_t* unicodes_set = unicodes_cache->set_for (&_, local_unicodes_cache);
1813
1814 if (!drop_format_4 && format == 4)
1815 {
1816 c->copy (_, + it | hb_filter (*unicodes_set, hb_first), 4u, base, plan, &format4objidx);
1817 if (c->in_error () && c->only_overflow ())
1818 {
1819 // cmap4 overflowed, reset and retry serialization without format 4 subtables.
1820 c->revert (snap);
1821 return serialize (c, it,
1822 encodingrec_iter,
1823 base,
1824 plan,
1825 true);
1826 }
1827 }
1828
1829 else if (format == 12)
1830 {
1831 if (_can_drop (_,
1832 *unicodes_set,
1833 base,
1834 *unicodes_cache,
1835 local_unicodes_cache,
1836 + it | hb_map (hb_first), encodingrec_iter))
1837 continue;
1838 c->copy (_, + it | hb_filter (*unicodes_set, hb_first), 12u, base, plan, &format12objidx);
1839 }
1840 else if (format == 14) c->copy (_, it, 14u, base, plan, &format14objidx);
1841 }
1842 c->check_assign(this->encodingRecord.len,
1843 (c->length () - cmap::min_size)/EncodingRecord::static_size,
1844 HB_SERIALIZE_ERROR_INT_OVERFLOW);
1845
1846 // Fail if format 4 was dropped and there is no cmap12.
1847 return !drop_format_4 || format12objidx;
1848 }
1849
1850 template<typename Iterator, typename EncodingRecordIterator,
1851 hb_requires (hb_is_iterator (Iterator)),
1852 hb_requires (hb_is_iterator (EncodingRecordIterator))>
_can_dropOT::cmap1853 bool _can_drop (const EncodingRecord& cmap12,
1854 const hb_set_t& cmap12_unicodes,
1855 const void* base,
1856 const SubtableUnicodesCache& unicodes_cache,
1857 SubtableUnicodesCache& local_unicodes_cache,
1858 Iterator subset_unicodes,
1859 EncodingRecordIterator encoding_records)
1860 {
1861 for (auto cp : + subset_unicodes | hb_filter (cmap12_unicodes))
1862 {
1863 if (cp >= 0x10000) return false;
1864 }
1865
1866 unsigned target_platform;
1867 unsigned target_encoding;
1868 unsigned target_language = (base+cmap12.subtable).get_language ();
1869
1870 if (cmap12.platformID == 0 && cmap12.encodingID == 4)
1871 {
1872 target_platform = 0;
1873 target_encoding = 3;
1874 } else if (cmap12.platformID == 3 && cmap12.encodingID == 10) {
1875 target_platform = 3;
1876 target_encoding = 1;
1877 } else {
1878 return false;
1879 }
1880
1881 for (const auto& _ : encoding_records)
1882 {
1883 if (_.platformID != target_platform
1884 || _.encodingID != target_encoding
1885 || (base+_.subtable).get_language() != target_language)
1886 continue;
1887
1888 const hb_set_t* sibling_unicodes = unicodes_cache.set_for (&_, local_unicodes_cache);
1889
1890 auto cmap12 = + subset_unicodes | hb_filter (cmap12_unicodes);
1891 auto sibling = + subset_unicodes | hb_filter (*sibling_unicodes);
1892 for (; cmap12 && sibling; cmap12++, sibling++)
1893 {
1894 unsigned a = *cmap12;
1895 unsigned b = *sibling;
1896 if (a != b) return false;
1897 }
1898
1899 return !cmap12 && !sibling;
1900 }
1901
1902 return false;
1903 }
1904
closure_glyphsOT::cmap1905 void closure_glyphs (const hb_set_t *unicodes,
1906 hb_set_t *glyphset) const
1907 {
1908 + hb_iter (encodingRecord)
1909 | hb_map (&EncodingRecord::subtable)
1910 | hb_map (hb_add (this))
1911 | hb_filter ([&] (const CmapSubtable& _) { return _.u.format == 14; })
1912 | hb_apply ([=] (const CmapSubtable& _) { _.u.format14.closure_glyphs (unicodes, glyphset); })
1913 ;
1914 }
1915
subsetOT::cmap1916 bool subset (hb_subset_context_t *c) const
1917 {
1918 TRACE_SUBSET (this);
1919
1920 cmap *cmap_prime = c->serializer->start_embed<cmap> ();
1921
1922 auto encodingrec_iter =
1923 + hb_iter (encodingRecord)
1924 | hb_filter ([&](const EncodingRecord& _) {
1925 return cmap::filter_encoding_records_for_subset (this, _);
1926 })
1927 ;
1928
1929 if (unlikely (!encodingrec_iter.len ())) return_trace (false);
1930
1931 const EncodingRecord *unicode_bmp= nullptr, *unicode_ucs4 = nullptr, *ms_bmp = nullptr, *ms_ucs4 = nullptr;
1932 bool has_format12 = false;
1933
1934 for (const EncodingRecord& _ : encodingrec_iter)
1935 {
1936 unsigned format = (this + _.subtable).u.format;
1937 if (format == 12) has_format12 = true;
1938
1939 const EncodingRecord *table = std::addressof (_);
1940 if (_.platformID == 0 && _.encodingID == 3) unicode_bmp = table;
1941 else if (_.platformID == 0 && _.encodingID == 4) unicode_ucs4 = table;
1942 else if (_.platformID == 3 && _.encodingID == 1) ms_bmp = table;
1943 else if (_.platformID == 3 && _.encodingID == 10) ms_ucs4 = table;
1944 }
1945
1946 if (unlikely (!has_format12 && !unicode_bmp && !ms_bmp)) return_trace (false);
1947 if (unlikely (has_format12 && (!unicode_ucs4 && !ms_ucs4))) return_trace (false);
1948
1949 auto it =
1950 + c->plan->unicode_to_new_gid_list.iter ()
1951 | hb_filter ([&] (const hb_codepoint_pair_t _)
1952 { return (_.second != HB_MAP_VALUE_INVALID); })
1953 ;
1954
1955 return_trace (cmap_prime->serialize (c->serializer,
1956 it,
1957 encodingrec_iter,
1958 this,
1959 c->plan));
1960 }
1961
find_best_subtableOT::cmap1962 const CmapSubtable *find_best_subtable (bool *symbol = nullptr,
1963 bool *mac = nullptr,
1964 bool *macroman = nullptr) const
1965 {
1966 if (symbol) *symbol = false;
1967 if (mac) *mac = false;
1968 if (macroman) *macroman = false;
1969
1970 const CmapSubtable *subtable;
1971
1972 /* Symbol subtable.
1973 * Prefer symbol if available.
1974 * https://github.com/harfbuzz/harfbuzz/issues/1918 */
1975 if ((subtable = this->find_subtable (3, 0)))
1976 {
1977 if (symbol) *symbol = true;
1978 return subtable;
1979 }
1980
1981 /* 32-bit subtables. */
1982 if ((subtable = this->find_subtable (3, 10))) return subtable;
1983 if ((subtable = this->find_subtable (0, 6))) return subtable;
1984 if ((subtable = this->find_subtable (0, 4))) return subtable;
1985
1986 /* 16-bit subtables. */
1987 if ((subtable = this->find_subtable (3, 1))) return subtable;
1988 if ((subtable = this->find_subtable (0, 3))) return subtable;
1989 if ((subtable = this->find_subtable (0, 2))) return subtable;
1990 if ((subtable = this->find_subtable (0, 1))) return subtable;
1991 if ((subtable = this->find_subtable (0, 0))) return subtable;
1992
1993 /* MacRoman subtable. */
1994 if ((subtable = this->find_subtable (1, 0)))
1995 {
1996 if (mac) *mac = true;
1997 if (macroman) *macroman = true;
1998 return subtable;
1999 }
2000 /* Any other Mac subtable; we just map ASCII for these. */
2001 if ((subtable = this->find_subtable (1, 0xFFFF)))
2002 {
2003 if (mac) *mac = true;
2004 return subtable;
2005 }
2006
2007 /* Meh. */
2008 return &Null (CmapSubtable);
2009 }
2010
2011 struct accelerator_t
2012 {
2013 using cache_t = hb_cache_t<21, 16, 8, true>;
2014
accelerator_tOT::cmap::accelerator_t2015 accelerator_t (hb_face_t *face)
2016 {
2017 this->table = hb_sanitize_context_t ().reference_table<cmap> (face);
2018 bool symbol, mac, macroman;
2019 this->subtable = table->find_best_subtable (&symbol, &mac, ¯oman);
2020 this->subtable_uvs = &Null (CmapSubtableFormat14);
2021 {
2022 const CmapSubtable *st = table->find_subtable (0, 5);
2023 if (st && st->u.format == 14)
2024 subtable_uvs = &st->u.format14;
2025 }
2026
2027 this->get_glyph_data = subtable;
2028 #ifndef HB_NO_CMAP_LEGACY_SUBTABLES
2029 if (unlikely (symbol))
2030 {
2031 switch ((unsigned) face->table.OS2->get_font_page ()) {
2032 case OS2::font_page_t::FONT_PAGE_NONE:
2033 this->get_glyph_funcZ = get_glyph_from_symbol<CmapSubtable, _hb_symbol_pua_map>;
2034 break;
2035 #ifndef HB_NO_OT_SHAPER_ARABIC_FALLBACK
2036 case OS2::font_page_t::FONT_PAGE_SIMP_ARABIC:
2037 this->get_glyph_funcZ = get_glyph_from_symbol<CmapSubtable, _hb_arabic_pua_simp_map>;
2038 break;
2039 case OS2::font_page_t::FONT_PAGE_TRAD_ARABIC:
2040 this->get_glyph_funcZ = get_glyph_from_symbol<CmapSubtable, _hb_arabic_pua_trad_map>;
2041 break;
2042 #endif
2043 default:
2044 this->get_glyph_funcZ = get_glyph_from<CmapSubtable>;
2045 break;
2046 }
2047 }
2048 else if (unlikely (macroman))
2049 {
2050 this->get_glyph_funcZ = get_glyph_from_macroman<CmapSubtable>;
2051 }
2052 else if (unlikely (mac))
2053 {
2054 this->get_glyph_funcZ = get_glyph_from_ascii<CmapSubtable>;
2055 }
2056 else
2057 #endif
2058 {
2059 switch (subtable->u.format) {
2060 /* Accelerate format 4 and format 12. */
2061 default:
2062 this->get_glyph_funcZ = get_glyph_from<CmapSubtable>;
2063 break;
2064 case 12:
2065 this->get_glyph_funcZ = get_glyph_from<CmapSubtableFormat12>;
2066 break;
2067 case 4:
2068 {
2069 this->format4_accel.init (&subtable->u.format4);
2070 this->get_glyph_data = &this->format4_accel;
2071 this->get_glyph_funcZ = this->format4_accel.get_glyph_func;
2072 break;
2073 }
2074 }
2075 }
2076 }
~accelerator_tOT::cmap::accelerator_t2077 ~accelerator_t () { this->table.destroy (); }
2078
_cached_getOT::cmap::accelerator_t2079 inline bool _cached_get (hb_codepoint_t unicode,
2080 hb_codepoint_t *glyph,
2081 cache_t *cache) const
2082 {
2083 unsigned v;
2084 if (cache && cache->get (unicode, &v))
2085 {
2086 *glyph = v;
2087 return true;
2088 }
2089 bool ret = this->get_glyph_funcZ (this->get_glyph_data, unicode, glyph);
2090
2091 if (cache && ret)
2092 cache->set (unicode, *glyph);
2093 return ret;
2094 }
2095
get_nominal_glyphOT::cmap::accelerator_t2096 bool get_nominal_glyph (hb_codepoint_t unicode,
2097 hb_codepoint_t *glyph,
2098 cache_t *cache = nullptr) const
2099 {
2100 if (unlikely (!this->get_glyph_funcZ)) return false;
2101 return _cached_get (unicode, glyph, cache);
2102 }
2103
get_nominal_glyphsOT::cmap::accelerator_t2104 unsigned int get_nominal_glyphs (unsigned int count,
2105 const hb_codepoint_t *first_unicode,
2106 unsigned int unicode_stride,
2107 hb_codepoint_t *first_glyph,
2108 unsigned int glyph_stride,
2109 cache_t *cache = nullptr) const
2110 {
2111 if (unlikely (!this->get_glyph_funcZ)) return 0;
2112
2113 unsigned int done;
2114 for (done = 0;
2115 done < count && _cached_get (*first_unicode, first_glyph, cache);
2116 done++)
2117 {
2118 first_unicode = &StructAtOffsetUnaligned<hb_codepoint_t> (first_unicode, unicode_stride);
2119 first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
2120 }
2121 return done;
2122 }
2123
get_variation_glyphOT::cmap::accelerator_t2124 bool get_variation_glyph (hb_codepoint_t unicode,
2125 hb_codepoint_t variation_selector,
2126 hb_codepoint_t *glyph,
2127 cache_t *cache = nullptr) const
2128 {
2129 switch (this->subtable_uvs->get_glyph_variant (unicode,
2130 variation_selector,
2131 glyph))
2132 {
2133 case GLYPH_VARIANT_NOT_FOUND: return false;
2134 case GLYPH_VARIANT_FOUND: return true;
2135 case GLYPH_VARIANT_USE_DEFAULT: break;
2136 }
2137
2138 return get_nominal_glyph (unicode, glyph, cache);
2139 }
2140
collect_unicodesOT::cmap::accelerator_t2141 void collect_unicodes (hb_set_t *out, unsigned int num_glyphs) const
2142 { subtable->collect_unicodes (out, num_glyphs); }
collect_mappingOT::cmap::accelerator_t2143 void collect_mapping (hb_set_t *unicodes, hb_map_t *mapping,
2144 unsigned num_glyphs = UINT_MAX) const
2145 { subtable->collect_mapping (unicodes, mapping, num_glyphs); }
collect_variation_selectorsOT::cmap::accelerator_t2146 void collect_variation_selectors (hb_set_t *out) const
2147 { subtable_uvs->collect_variation_selectors (out); }
collect_variation_unicodesOT::cmap::accelerator_t2148 void collect_variation_unicodes (hb_codepoint_t variation_selector,
2149 hb_set_t *out) const
2150 { subtable_uvs->collect_variation_unicodes (variation_selector, out); }
2151
2152 protected:
2153 typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj,
2154 hb_codepoint_t codepoint,
2155 hb_codepoint_t *glyph);
2156 typedef uint_fast16_t (*hb_pua_remap_func_t) (unsigned);
2157
2158 template <typename Type>
get_glyph_fromOT::cmap::accelerator_t2159 HB_INTERNAL static bool get_glyph_from (const void *obj,
2160 hb_codepoint_t codepoint,
2161 hb_codepoint_t *glyph)
2162 {
2163 const Type *typed_obj = (const Type *) obj;
2164 return typed_obj->get_glyph (codepoint, glyph);
2165 }
2166
2167 template <typename Type, hb_pua_remap_func_t remap>
get_glyph_from_symbolOT::cmap::accelerator_t2168 HB_INTERNAL static bool get_glyph_from_symbol (const void *obj,
2169 hb_codepoint_t codepoint,
2170 hb_codepoint_t *glyph)
2171 {
2172 const Type *typed_obj = (const Type *) obj;
2173 if (likely (typed_obj->get_glyph (codepoint, glyph)))
2174 return true;
2175
2176 if (hb_codepoint_t c = remap (codepoint))
2177 return typed_obj->get_glyph (c, glyph);
2178
2179 return false;
2180 }
2181
2182 template <typename Type>
get_glyph_from_asciiOT::cmap::accelerator_t2183 HB_INTERNAL static bool get_glyph_from_ascii (const void *obj,
2184 hb_codepoint_t codepoint,
2185 hb_codepoint_t *glyph)
2186 {
2187 const Type *typed_obj = (const Type *) obj;
2188 return codepoint < 0x80 && typed_obj->get_glyph (codepoint, glyph);
2189 }
2190
2191 template <typename Type>
get_glyph_from_macromanOT::cmap::accelerator_t2192 HB_INTERNAL static bool get_glyph_from_macroman (const void *obj,
2193 hb_codepoint_t codepoint,
2194 hb_codepoint_t *glyph)
2195 {
2196 if (get_glyph_from_ascii<Type> (obj, codepoint, glyph))
2197 return true;
2198
2199 const Type *typed_obj = (const Type *) obj;
2200 unsigned c = unicode_to_macroman (codepoint);
2201 return c && typed_obj->get_glyph (c, glyph);
2202 }
2203
2204 private:
2205 hb_nonnull_ptr_t<const CmapSubtable> subtable;
2206 hb_nonnull_ptr_t<const CmapSubtableFormat14> subtable_uvs;
2207
2208 hb_cmap_get_glyph_func_t get_glyph_funcZ;
2209 const void *get_glyph_data;
2210
2211 CmapSubtableFormat4::accelerator_t format4_accel;
2212
2213 public:
2214 hb_blob_ptr_t<cmap> table;
2215 };
2216
2217 protected:
2218
find_subtableOT::cmap2219 const CmapSubtable *find_subtable (unsigned int platform_id,
2220 unsigned int encoding_id) const
2221 {
2222 EncodingRecord key;
2223 key.platformID = platform_id;
2224 key.encodingID = encoding_id;
2225
2226 const EncodingRecord &result = encodingRecord.bsearch (key);
2227 if (!result.subtable)
2228 return nullptr;
2229
2230 return &(this+result.subtable);
2231 }
2232
2233 public:
2234
sanitizeOT::cmap2235 bool sanitize (hb_sanitize_context_t *c) const
2236 {
2237 TRACE_SANITIZE (this);
2238 return_trace (c->check_struct (this) &&
2239 hb_barrier () &&
2240 likely (version == 0) &&
2241 encodingRecord.sanitize (c, this));
2242 }
2243
2244 private:
2245
filter_encoding_records_for_subsetOT::cmap2246 static bool filter_encoding_records_for_subset(const cmap* cmap,
2247 const EncodingRecord& _)
2248 {
2249 return
2250 (_.platformID == 0 && _.encodingID == 3) ||
2251 (_.platformID == 0 && _.encodingID == 4) ||
2252 (_.platformID == 3 && _.encodingID == 1) ||
2253 (_.platformID == 3 && _.encodingID == 10) ||
2254 (cmap + _.subtable).u.format == 14;
2255 }
2256
2257 protected:
2258 HBUINT16 version; /* Table version number (0). */
2259 SortedArray16Of<EncodingRecord>
2260 encodingRecord; /* Encoding tables. */
2261 public:
2262 DEFINE_SIZE_ARRAY (4, encodingRecord);
2263 };
2264
2265 struct cmap_accelerator_t : cmap::accelerator_t {
cmap_accelerator_tOT::cmap_accelerator_t2266 cmap_accelerator_t (hb_face_t *face) : cmap::accelerator_t (face) {}
2267 };
2268
2269 } /* namespace OT */
2270
2271
2272 #endif /* HB_OT_CMAP_TABLE_HH */
2273