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
35 /*
36 * cmap -- Character to Glyph Index Mapping
37 * https://docs.microsoft.com/en-us/typography/opentype/spec/cmap
38 */
39 #define HB_OT_TAG_cmap HB_TAG('c','m','a','p')
40
41 namespace OT {
42
43
44 struct CmapSubtableFormat0
45 {
get_glyphOT::CmapSubtableFormat046 bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
47 {
48 hb_codepoint_t gid = codepoint < 256 ? glyphIdArray[codepoint] : 0;
49 if (unlikely (!gid))
50 return false;
51 *glyph = gid;
52 return true;
53 }
54
get_languageOT::CmapSubtableFormat055 unsigned get_language () const
56 {
57 return language;
58 }
59
collect_unicodesOT::CmapSubtableFormat060 void collect_unicodes (hb_set_t *out) const
61 {
62 for (unsigned int i = 0; i < 256; i++)
63 if (glyphIdArray[i])
64 out->add (i);
65 }
66
collect_mappingOT::CmapSubtableFormat067 void collect_mapping (hb_set_t *unicodes, /* OUT */
68 hb_map_t *mapping /* OUT */) const
69 {
70 for (unsigned i = 0; i < 256; i++)
71 if (glyphIdArray[i])
72 {
73 hb_codepoint_t glyph = glyphIdArray[i];
74 unicodes->add (i);
75 mapping->set (i, glyph);
76 }
77 }
78
sanitizeOT::CmapSubtableFormat079 bool sanitize (hb_sanitize_context_t *c) const
80 {
81 TRACE_SANITIZE (this);
82 return_trace (c->check_struct (this));
83 }
84
85 protected:
86 HBUINT16 format; /* Format number is set to 0. */
87 HBUINT16 length; /* Byte length of this subtable. */
88 HBUINT16 language; /* Ignore. */
89 HBUINT8 glyphIdArray[256];/* An array that maps character
90 * code to glyph index values. */
91 public:
92 DEFINE_SIZE_STATIC (6 + 256);
93 };
94
95 struct CmapSubtableFormat4
96 {
97
98
99 template<typename Iterator,
100 typename Writer,
101 hb_requires (hb_is_iterator (Iterator))>
to_rangesOT::CmapSubtableFormat4102 void to_ranges (Iterator it, Writer& range_writer)
103 {
104 hb_codepoint_t start_cp = 0, prev_run_start_cp = 0, run_start_cp = 0, end_cp = 0, last_gid = 0;
105 int run_length = 0 , delta = 0, prev_delta = 0;
106
107 enum {
108 FIRST_SUB_RANGE,
109 FOLLOWING_SUB_RANGE,
110 } mode;
111
112 while (it) {
113 // Start a new range
114 {
115 const auto& pair = *it;
116 start_cp = pair.first;
117 prev_run_start_cp = start_cp;
118 run_start_cp = start_cp;
119 end_cp = start_cp;
120 last_gid = pair.second;
121 run_length = 1;
122 prev_delta = 0;
123 }
124
125 delta = last_gid - start_cp;
126 mode = FIRST_SUB_RANGE;
127 it++;
128
129 while (it) {
130 // Process range
131 const auto& pair = *it;
132 hb_codepoint_t next_cp = pair.first;
133 hb_codepoint_t next_gid = pair.second;
134 if (next_cp != end_cp + 1) {
135 // Current range is over, stop processing.
136 break;
137 }
138
139 if (next_gid == last_gid + 1) {
140 // The current run continues.
141 end_cp = next_cp;
142 run_length++;
143 last_gid = next_gid;
144 it++;
145 continue;
146 }
147
148 // A new run is starting, decide if we want to commit the current run.
149 int split_cost = (mode == FIRST_SUB_RANGE) ? 8 : 16;
150 int run_cost = run_length * 2;
151 if (run_cost >= split_cost) {
152 commit_current_range(start_cp,
153 prev_run_start_cp,
154 run_start_cp,
155 end_cp,
156 delta,
157 prev_delta,
158 split_cost,
159 range_writer);
160 start_cp = next_cp;
161 }
162
163 // Start the new run
164 mode = FOLLOWING_SUB_RANGE;
165 prev_run_start_cp = run_start_cp;
166 run_start_cp = next_cp;
167 end_cp = next_cp;
168 prev_delta = delta;
169 delta = next_gid - run_start_cp;
170 run_length = 1;
171 last_gid = next_gid;
172 it++;
173 }
174
175 // Finalize range
176 commit_current_range (start_cp,
177 prev_run_start_cp,
178 run_start_cp,
179 end_cp,
180 delta,
181 prev_delta,
182 8,
183 range_writer);
184 }
185
186 if (likely (end_cp != 0xFFFF)) {
187 range_writer (0xFFFF, 0xFFFF, 1);
188 }
189 }
190
191 /*
192 * Writes the current range as either one or two ranges depending on what is most efficient.
193 */
194 template<typename Writer>
commit_current_rangeOT::CmapSubtableFormat4195 void commit_current_range (hb_codepoint_t start,
196 hb_codepoint_t prev_run_start,
197 hb_codepoint_t run_start,
198 hb_codepoint_t end,
199 int run_delta,
200 int previous_run_delta,
201 int split_cost,
202 Writer& range_writer) {
203 bool should_split = false;
204 if (start < run_start && run_start < end) {
205 int run_cost = (end - run_start + 1) * 2;
206 if (run_cost >= split_cost) {
207 should_split = true;
208 }
209 }
210
211 // TODO(grieger): handle case where delta is legitimately 0, mark range offset array instead?
212 if (should_split) {
213 if (start == prev_run_start)
214 range_writer (start, run_start - 1, previous_run_delta);
215 else
216 range_writer (start, run_start - 1, 0);
217 range_writer (run_start, end, run_delta);
218 return;
219 }
220
221
222 if (start == run_start) {
223 // Range is only a run
224 range_writer (start, end, run_delta);
225 return;
226 }
227
228 // Write only a single non-run range.
229 range_writer (start, end, 0);
230 }
231
232 template<typename Iterator,
233 hb_requires (hb_is_iterator (Iterator))>
serialize_find_segcountOT::CmapSubtableFormat4234 unsigned serialize_find_segcount (Iterator it) {
235 struct Counter {
236 unsigned segcount = 0;
237
238 void operator() (hb_codepoint_t start,
239 hb_codepoint_t end,
240 int delta) {
241 segcount++;
242 }
243 } counter;
244
245 to_ranges (+it, counter);
246 return counter.segcount;
247 }
248
249
250 template<typename Iterator,
251 hb_requires (hb_is_iterator (Iterator))>
serialize_start_end_delta_arraysOT::CmapSubtableFormat4252 bool serialize_start_end_delta_arrays (hb_serialize_context_t *c,
253 Iterator it,
254 int segcount)
255 {
256 struct Writer {
257 hb_serialize_context_t *serializer_;
258 HBUINT16* end_code_;
259 HBUINT16* start_code_;
260 HBINT16* id_delta_;
261 int index_;
262
263 Writer(hb_serialize_context_t *serializer)
264 : serializer_(serializer),
265 end_code_(nullptr),
266 start_code_(nullptr),
267 id_delta_(nullptr),
268 index_ (0) {}
269 void operator() (hb_codepoint_t start,
270 hb_codepoint_t end,
271 int delta) {
272 start_code_[index_] = start;
273 end_code_[index_] = end;
274 id_delta_[index_] = delta;
275 index_++;
276 }
277 } writer(c);
278
279 writer.end_code_ = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount);
280 c->allocate_size<HBUINT16> (2); // padding
281 writer.start_code_ = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount);
282 writer.id_delta_ = c->allocate_size<HBINT16> (HBINT16::static_size * segcount);
283
284 if (unlikely (!writer.end_code_ || !writer.start_code_ || !writer.id_delta_)) return false;
285
286 to_ranges (+it, writer);
287 return true;
288 }
289
290 template<typename Iterator,
291 hb_requires (hb_is_iterator (Iterator))>
serialize_rangeoffset_glyidOT::CmapSubtableFormat4292 HBUINT16* serialize_rangeoffset_glyid (hb_serialize_context_t *c,
293 Iterator it,
294 HBUINT16 *endCode,
295 HBUINT16 *startCode,
296 HBINT16 *idDelta,
297 unsigned segcount)
298 {
299 hb_map_t cp_to_gid { it };
300
301 HBUINT16 *idRangeOffset = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount);
302 if (unlikely (!c->check_success (idRangeOffset))) return nullptr;
303 if (unlikely ((char *)idRangeOffset - (char *)idDelta != (int) segcount * (int) HBINT16::static_size)) return nullptr;
304
305 for (unsigned i : + hb_range (segcount)
306 | hb_filter ([&] (const unsigned _) { return idDelta[_] == 0; }))
307 {
308 idRangeOffset[i] = 2 * (c->start_embed<HBUINT16> () - idRangeOffset - i);
309 for (hb_codepoint_t cp = startCode[i]; cp <= endCode[i]; cp++)
310 {
311 HBUINT16 gid;
312 gid = cp_to_gid[cp];
313 c->copy<HBUINT16> (gid);
314 }
315 }
316
317 return idRangeOffset;
318 }
319
320 template<typename Iterator,
321 hb_requires (hb_is_iterator (Iterator))>
serializeOT::CmapSubtableFormat4322 void serialize (hb_serialize_context_t *c,
323 Iterator it)
324 {
325 auto format4_iter =
326 + it
327 | hb_filter ([&] (const hb_pair_t<hb_codepoint_t, hb_codepoint_t> _)
328 { return _.first <= 0xFFFF; })
329 ;
330
331 if (!format4_iter) return;
332
333 unsigned table_initpos = c->length ();
334 if (unlikely (!c->extend_min (this))) return;
335 this->format = 4;
336
337 hb_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> cp_to_gid {
338 format4_iter
339 };
340
341 //serialize endCode[], startCode[], idDelta[]
342 HBUINT16* endCode = c->start_embed<HBUINT16> ();
343 unsigned segcount = serialize_find_segcount (cp_to_gid.iter());
344 if (unlikely (!serialize_start_end_delta_arrays (c, cp_to_gid.iter(), segcount)))
345 return;
346
347 HBUINT16 *startCode = endCode + segcount + 1;
348 HBINT16 *idDelta = ((HBINT16*)startCode) + segcount;
349
350 HBUINT16 *idRangeOffset = serialize_rangeoffset_glyid (c,
351 cp_to_gid.iter (),
352 endCode,
353 startCode,
354 idDelta,
355 segcount);
356 if (unlikely (!c->check_success (idRangeOffset))) return;
357
358 this->length = c->length () - table_initpos;
359 if ((long long) this->length != (long long) c->length () - table_initpos)
360 {
361 // Length overflowed. Discard the current object before setting the error condition, otherwise
362 // discard is a noop which prevents the higher level code from reverting the serializer to the
363 // pre-error state in cmap4 overflow handling code.
364 c->pop_discard ();
365 c->err (HB_SERIALIZE_ERROR_INT_OVERFLOW);
366 return;
367 }
368
369 this->segCountX2 = segcount * 2;
370 this->entrySelector = hb_max (1u, hb_bit_storage (segcount)) - 1;
371 this->searchRange = 2 * (1u << this->entrySelector);
372 this->rangeShift = segcount * 2 > this->searchRange
373 ? 2 * segcount - this->searchRange
374 : 0;
375 }
376
get_languageOT::CmapSubtableFormat4377 unsigned get_language () const
378 {
379 return language;
380 }
381
382 struct accelerator_t
383 {
accelerator_tOT::CmapSubtableFormat4::accelerator_t384 accelerator_t () {}
accelerator_tOT::CmapSubtableFormat4::accelerator_t385 accelerator_t (const CmapSubtableFormat4 *subtable) { init (subtable); }
386
initOT::CmapSubtableFormat4::accelerator_t387 void init (const CmapSubtableFormat4 *subtable)
388 {
389 segCount = subtable->segCountX2 / 2;
390 endCount = subtable->values.arrayZ;
391 startCount = endCount + segCount + 1;
392 idDelta = startCount + segCount;
393 idRangeOffset = idDelta + segCount;
394 glyphIdArray = idRangeOffset + segCount;
395 glyphIdArrayLength = (subtable->length - 16 - 8 * segCount) / 2;
396 }
397
get_glyphOT::CmapSubtableFormat4::accelerator_t398 bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
399 {
400 struct CustomRange
401 {
402 int cmp (hb_codepoint_t k,
403 unsigned distance) const
404 {
405 if (k > last) return +1;
406 if (k < (&last)[distance]) return -1;
407 return 0;
408 }
409 HBUINT16 last;
410 };
411
412 const HBUINT16 *found = hb_bsearch (codepoint,
413 this->endCount,
414 this->segCount,
415 2,
416 _hb_cmp_method<hb_codepoint_t, CustomRange, unsigned>,
417 this->segCount + 1);
418 if (unlikely (!found))
419 return false;
420 unsigned int i = found - endCount;
421
422 hb_codepoint_t gid;
423 unsigned int rangeOffset = this->idRangeOffset[i];
424 if (rangeOffset == 0)
425 gid = codepoint + this->idDelta[i];
426 else
427 {
428 /* Somebody has been smoking... */
429 unsigned int index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount;
430 if (unlikely (index >= this->glyphIdArrayLength))
431 return false;
432 gid = this->glyphIdArray[index];
433 if (unlikely (!gid))
434 return false;
435 gid += this->idDelta[i];
436 }
437 gid &= 0xFFFFu;
438 if (unlikely (!gid))
439 return false;
440 *glyph = gid;
441 return true;
442 }
443
get_glyph_funcOT::CmapSubtableFormat4::accelerator_t444 HB_INTERNAL static bool get_glyph_func (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph)
445 { return ((const accelerator_t *) obj)->get_glyph (codepoint, glyph); }
446
collect_unicodesOT::CmapSubtableFormat4::accelerator_t447 void collect_unicodes (hb_set_t *out) const
448 {
449 unsigned int count = this->segCount;
450 if (count && this->startCount[count - 1] == 0xFFFFu)
451 count--; /* Skip sentinel segment. */
452 for (unsigned int i = 0; i < count; i++)
453 {
454 hb_codepoint_t start = this->startCount[i];
455 hb_codepoint_t end = this->endCount[i];
456 unsigned int rangeOffset = this->idRangeOffset[i];
457 out->add_range(start, end);
458 if (rangeOffset == 0)
459 {
460 for (hb_codepoint_t codepoint = start; codepoint <= end; codepoint++)
461 {
462 hb_codepoint_t gid = (codepoint + this->idDelta[i]) & 0xFFFFu;
463 if (unlikely (!gid))
464 out->del(codepoint);
465 }
466 }
467 else
468 {
469 for (hb_codepoint_t codepoint = start; codepoint <= end; codepoint++)
470 {
471 unsigned int index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount;
472 if (unlikely (index >= this->glyphIdArrayLength))
473 {
474 out->del_range (codepoint, end);
475 break;
476 }
477 hb_codepoint_t gid = this->glyphIdArray[index];
478 if (unlikely (!gid))
479 out->del(codepoint);
480 }
481 }
482 }
483 }
484
collect_mappingOT::CmapSubtableFormat4::accelerator_t485 void collect_mapping (hb_set_t *unicodes, /* OUT */
486 hb_map_t *mapping /* OUT */) const
487 {
488 // TODO(grieger): optimize similar to collect_unicodes
489 // (ie. use add_range())
490 unsigned count = this->segCount;
491 if (count && this->startCount[count - 1] == 0xFFFFu)
492 count--; /* Skip sentinel segment. */
493 for (unsigned i = 0; i < count; i++)
494 {
495 hb_codepoint_t start = this->startCount[i];
496 hb_codepoint_t end = this->endCount[i];
497 unsigned rangeOffset = this->idRangeOffset[i];
498 if (rangeOffset == 0)
499 {
500 for (hb_codepoint_t codepoint = start; codepoint <= end; codepoint++)
501 {
502 hb_codepoint_t gid = (codepoint + this->idDelta[i]) & 0xFFFFu;
503 if (unlikely (!gid))
504 continue;
505 unicodes->add (codepoint);
506 mapping->set (codepoint, gid);
507 }
508 }
509 else
510 {
511 for (hb_codepoint_t codepoint = start; codepoint <= end; codepoint++)
512 {
513 unsigned index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount;
514 if (unlikely (index >= this->glyphIdArrayLength))
515 break;
516 hb_codepoint_t gid = this->glyphIdArray[index];
517 if (unlikely (!gid))
518 continue;
519 unicodes->add (codepoint);
520 mapping->set (codepoint, gid);
521 }
522 }
523 }
524 }
525
526 const HBUINT16 *endCount;
527 const HBUINT16 *startCount;
528 const HBUINT16 *idDelta;
529 const HBUINT16 *idRangeOffset;
530 const HBUINT16 *glyphIdArray;
531 unsigned int segCount;
532 unsigned int glyphIdArrayLength;
533 };
534
get_glyphOT::CmapSubtableFormat4535 bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
536 {
537 accelerator_t accel (this);
538 return accel.get_glyph_func (&accel, codepoint, glyph);
539 }
collect_unicodesOT::CmapSubtableFormat4540 void collect_unicodes (hb_set_t *out) const
541 {
542 accelerator_t accel (this);
543 accel.collect_unicodes (out);
544 }
545
collect_mappingOT::CmapSubtableFormat4546 void collect_mapping (hb_set_t *unicodes, /* OUT */
547 hb_map_t *mapping /* OUT */) const
548 {
549 accelerator_t accel (this);
550 accel.collect_mapping (unicodes, mapping);
551 }
552
sanitizeOT::CmapSubtableFormat4553 bool sanitize (hb_sanitize_context_t *c) const
554 {
555 TRACE_SANITIZE (this);
556 if (unlikely (!c->check_struct (this)))
557 return_trace (false);
558
559 if (unlikely (!c->check_range (this, length)))
560 {
561 /* Some broken fonts have too long of a "length" value.
562 * If that is the case, just change the value to truncate
563 * the subtable at the end of the blob. */
564 uint16_t new_length = (uint16_t) hb_min ((uintptr_t) 65535,
565 (uintptr_t) (c->end -
566 (char *) this));
567 if (!c->try_set (&length, new_length))
568 return_trace (false);
569 }
570
571 return_trace (16 + 4 * (unsigned int) segCountX2 <= length);
572 }
573
574
575
576 protected:
577 HBUINT16 format; /* Format number is set to 4. */
578 HBUINT16 length; /* This is the length in bytes of the
579 * subtable. */
580 HBUINT16 language; /* Ignore. */
581 HBUINT16 segCountX2; /* 2 x segCount. */
582 HBUINT16 searchRange; /* 2 * (2**floor(log2(segCount))) */
583 HBUINT16 entrySelector; /* log2(searchRange/2) */
584 HBUINT16 rangeShift; /* 2 x segCount - searchRange */
585
586 UnsizedArrayOf<HBUINT16>
587 values;
588 #if 0
589 HBUINT16 endCount[segCount]; /* End characterCode for each segment,
590 * last=0xFFFFu. */
591 HBUINT16 reservedPad; /* Set to 0. */
592 HBUINT16 startCount[segCount]; /* Start character code for each segment. */
593 HBINT16 idDelta[segCount]; /* Delta for all character codes in segment. */
594 HBUINT16 idRangeOffset[segCount];/* Offsets into glyphIdArray or 0 */
595 UnsizedArrayOf<HBUINT16>
596 glyphIdArray; /* Glyph index array (arbitrary length) */
597 #endif
598
599 public:
600 DEFINE_SIZE_ARRAY (14, values);
601 };
602
603 struct CmapSubtableLongGroup
604 {
605 friend struct CmapSubtableFormat12;
606 friend struct CmapSubtableFormat13;
607 template<typename U>
608 friend struct CmapSubtableLongSegmented;
609 friend struct cmap;
610
cmpOT::CmapSubtableLongGroup611 int cmp (hb_codepoint_t codepoint) const
612 {
613 if (codepoint < startCharCode) return -1;
614 if (codepoint > endCharCode) return +1;
615 return 0;
616 }
617
sanitizeOT::CmapSubtableLongGroup618 bool sanitize (hb_sanitize_context_t *c) const
619 {
620 TRACE_SANITIZE (this);
621 return_trace (c->check_struct (this));
622 }
623
624 private:
625 HBUINT32 startCharCode; /* First character code in this group. */
626 HBUINT32 endCharCode; /* Last character code in this group. */
627 HBUINT32 glyphID; /* Glyph index; interpretation depends on
628 * subtable format. */
629 public:
630 DEFINE_SIZE_STATIC (12);
631 };
632 DECLARE_NULL_NAMESPACE_BYTES (OT, CmapSubtableLongGroup);
633
634 template <typename UINT>
635 struct CmapSubtableTrimmed
636 {
get_glyphOT::CmapSubtableTrimmed637 bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
638 {
639 /* Rely on our implicit array bound-checking. */
640 hb_codepoint_t gid = glyphIdArray[codepoint - startCharCode];
641 if (unlikely (!gid))
642 return false;
643 *glyph = gid;
644 return true;
645 }
646
get_languageOT::CmapSubtableTrimmed647 unsigned get_language () const
648 {
649 return language;
650 }
651
collect_unicodesOT::CmapSubtableTrimmed652 void collect_unicodes (hb_set_t *out) const
653 {
654 hb_codepoint_t start = startCharCode;
655 unsigned int count = glyphIdArray.len;
656 for (unsigned int i = 0; i < count; i++)
657 if (glyphIdArray[i])
658 out->add (start + i);
659 }
660
collect_mappingOT::CmapSubtableTrimmed661 void collect_mapping (hb_set_t *unicodes, /* OUT */
662 hb_map_t *mapping /* OUT */) const
663 {
664 hb_codepoint_t start_cp = startCharCode;
665 unsigned count = glyphIdArray.len;
666 for (unsigned i = 0; i < count; i++)
667 if (glyphIdArray[i])
668 {
669 hb_codepoint_t unicode = start_cp + i;
670 hb_codepoint_t glyphid = glyphIdArray[i];
671 unicodes->add (unicode);
672 mapping->set (unicode, glyphid);
673 }
674 }
675
sanitizeOT::CmapSubtableTrimmed676 bool sanitize (hb_sanitize_context_t *c) const
677 {
678 TRACE_SANITIZE (this);
679 return_trace (c->check_struct (this) && glyphIdArray.sanitize (c));
680 }
681
682 protected:
683 UINT formatReserved; /* Subtable format and (maybe) padding. */
684 UINT length; /* Byte length of this subtable. */
685 UINT language; /* Ignore. */
686 UINT startCharCode; /* First character code covered. */
687 ArrayOf<HBGlyphID16, UINT>
688 glyphIdArray; /* Array of glyph index values for character
689 * codes in the range. */
690 public:
691 DEFINE_SIZE_ARRAY (5 * sizeof (UINT), glyphIdArray);
692 };
693
694 struct CmapSubtableFormat6 : CmapSubtableTrimmed<HBUINT16> {};
695 struct CmapSubtableFormat10 : CmapSubtableTrimmed<HBUINT32> {};
696
697 template <typename T>
698 struct CmapSubtableLongSegmented
699 {
700 friend struct cmap;
701
get_glyphOT::CmapSubtableLongSegmented702 bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
703 {
704 hb_codepoint_t gid = T::group_get_glyph (groups.bsearch (codepoint), codepoint);
705 if (unlikely (!gid))
706 return false;
707 *glyph = gid;
708 return true;
709 }
710
get_languageOT::CmapSubtableLongSegmented711 unsigned get_language () const
712 {
713 return language;
714 }
715
collect_unicodesOT::CmapSubtableLongSegmented716 void collect_unicodes (hb_set_t *out, unsigned int num_glyphs) const
717 {
718 for (unsigned int i = 0; i < this->groups.len; i++)
719 {
720 hb_codepoint_t start = this->groups[i].startCharCode;
721 hb_codepoint_t end = hb_min ((hb_codepoint_t) this->groups[i].endCharCode,
722 (hb_codepoint_t) HB_UNICODE_MAX);
723 hb_codepoint_t gid = this->groups[i].glyphID;
724 if (!gid)
725 {
726 /* Intention is: if (hb_is_same (T, CmapSubtableFormat13)) continue; */
727 if (! T::group_get_glyph (this->groups[i], end)) continue;
728 start++;
729 gid++;
730 }
731 if (unlikely ((unsigned int) gid >= num_glyphs)) continue;
732 if (unlikely ((unsigned int) (gid + end - start) >= num_glyphs))
733 end = start + (hb_codepoint_t) num_glyphs - gid;
734
735 out->add_range (start, hb_min (end, 0x10FFFFu));
736 }
737 }
738
collect_mappingOT::CmapSubtableLongSegmented739 void collect_mapping (hb_set_t *unicodes, /* OUT */
740 hb_map_t *mapping, /* OUT */
741 unsigned num_glyphs) const
742 {
743 hb_codepoint_t last_end = 0;
744 for (unsigned i = 0; i < this->groups.len; i++)
745 {
746 hb_codepoint_t start = this->groups[i].startCharCode;
747 hb_codepoint_t end = hb_min ((hb_codepoint_t) this->groups[i].endCharCode,
748 (hb_codepoint_t) HB_UNICODE_MAX);
749 if (unlikely (start > end || start < last_end)) {
750 // Range is not in order and is invalid, skip it.
751 continue;
752 }
753 last_end = end;
754
755
756 hb_codepoint_t gid = this->groups[i].glyphID;
757 if (!gid)
758 {
759 /* Intention is: if (hb_is_same (T, CmapSubtableFormat13)) continue; */
760 if (! T::group_get_glyph (this->groups[i], end)) continue;
761 start++;
762 gid++;
763 }
764 if (unlikely ((unsigned int) gid >= num_glyphs)) continue;
765 if (unlikely ((unsigned int) (gid + end - start) >= num_glyphs))
766 end = start + (hb_codepoint_t) num_glyphs - gid;
767
768 for (unsigned cp = start; cp <= end; cp++)
769 {
770 unicodes->add (cp);
771 mapping->set (cp, gid);
772 gid++;
773 }
774 }
775 }
776
sanitizeOT::CmapSubtableLongSegmented777 bool sanitize (hb_sanitize_context_t *c) const
778 {
779 TRACE_SANITIZE (this);
780 return_trace (c->check_struct (this) && groups.sanitize (c));
781 }
782
783 protected:
784 HBUINT16 format; /* Subtable format; set to 12. */
785 HBUINT16 reserved; /* Reserved; set to 0. */
786 HBUINT32 length; /* Byte length of this subtable. */
787 HBUINT32 language; /* Ignore. */
788 SortedArray32Of<CmapSubtableLongGroup>
789 groups; /* Groupings. */
790 public:
791 DEFINE_SIZE_ARRAY (16, groups);
792 };
793
794 struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
795 {
group_get_glyphOT::CmapSubtableFormat12796 static hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
797 hb_codepoint_t u)
798 { return likely (group.startCharCode <= group.endCharCode) ?
799 group.glyphID + (u - group.startCharCode) : 0; }
800
801
802 template<typename Iterator,
803 hb_requires (hb_is_iterator (Iterator))>
serializeOT::CmapSubtableFormat12804 void serialize (hb_serialize_context_t *c,
805 Iterator it)
806 {
807 if (!it) return;
808 unsigned table_initpos = c->length ();
809 if (unlikely (!c->extend_min (this))) return;
810
811 hb_codepoint_t startCharCode = (hb_codepoint_t) -1, endCharCode = (hb_codepoint_t) -1;
812 hb_codepoint_t glyphID = 0;
813
814 for (const auto& _ : +it)
815 {
816 if (startCharCode == (hb_codepoint_t) -1)
817 {
818 startCharCode = _.first;
819 endCharCode = _.first;
820 glyphID = _.second;
821 }
822 else if (!_is_gid_consecutive (endCharCode, startCharCode, glyphID, _.first, _.second))
823 {
824 CmapSubtableLongGroup grouprecord;
825 grouprecord.startCharCode = startCharCode;
826 grouprecord.endCharCode = endCharCode;
827 grouprecord.glyphID = glyphID;
828 c->copy<CmapSubtableLongGroup> (grouprecord);
829
830 startCharCode = _.first;
831 endCharCode = _.first;
832 glyphID = _.second;
833 }
834 else
835 endCharCode = _.first;
836 }
837
838 CmapSubtableLongGroup record;
839 record.startCharCode = startCharCode;
840 record.endCharCode = endCharCode;
841 record.glyphID = glyphID;
842 c->copy<CmapSubtableLongGroup> (record);
843
844 this->format = 12;
845 this->reserved = 0;
846 this->length = c->length () - table_initpos;
847 this->groups.len = (this->length - min_size) / CmapSubtableLongGroup::static_size;
848 }
849
get_sub_table_sizeOT::CmapSubtableFormat12850 static size_t get_sub_table_size (const hb_sorted_vector_t<CmapSubtableLongGroup> &groups_data)
851 { return 16 + 12 * groups_data.length; }
852
853 private:
_is_gid_consecutiveOT::CmapSubtableFormat12854 static bool _is_gid_consecutive (hb_codepoint_t endCharCode,
855 hb_codepoint_t startCharCode,
856 hb_codepoint_t glyphID,
857 hb_codepoint_t cp,
858 hb_codepoint_t new_gid)
859 {
860 return (cp - 1 == endCharCode) &&
861 new_gid == glyphID + (cp - startCharCode);
862 }
863
864 };
865
866 struct CmapSubtableFormat13 : CmapSubtableLongSegmented<CmapSubtableFormat13>
867 {
group_get_glyphOT::CmapSubtableFormat13868 static hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
869 hb_codepoint_t u HB_UNUSED)
870 { return group.glyphID; }
871 };
872
873 typedef enum
874 {
875 GLYPH_VARIANT_NOT_FOUND = 0,
876 GLYPH_VARIANT_FOUND = 1,
877 GLYPH_VARIANT_USE_DEFAULT = 2
878 } glyph_variant_t;
879
880 struct UnicodeValueRange
881 {
cmpOT::UnicodeValueRange882 int cmp (const hb_codepoint_t &codepoint) const
883 {
884 if (codepoint < startUnicodeValue) return -1;
885 if (codepoint > startUnicodeValue + additionalCount) return +1;
886 return 0;
887 }
888
sanitizeOT::UnicodeValueRange889 bool sanitize (hb_sanitize_context_t *c) const
890 {
891 TRACE_SANITIZE (this);
892 return_trace (c->check_struct (this));
893 }
894
895 HBUINT24 startUnicodeValue; /* First value in this range. */
896 HBUINT8 additionalCount; /* Number of additional values in this
897 * range. */
898 public:
899 DEFINE_SIZE_STATIC (4);
900 };
901
902 struct DefaultUVS : SortedArray32Of<UnicodeValueRange>
903 {
collect_unicodesOT::DefaultUVS904 void collect_unicodes (hb_set_t *out) const
905 {
906 unsigned int count = len;
907 for (unsigned int i = 0; i < count; i++)
908 {
909 hb_codepoint_t first = arrayZ[i].startUnicodeValue;
910 hb_codepoint_t last = hb_min ((hb_codepoint_t) (first + arrayZ[i].additionalCount),
911 (hb_codepoint_t) HB_UNICODE_MAX);
912 out->add_range (first, last);
913 }
914 }
915
copyOT::DefaultUVS916 DefaultUVS* copy (hb_serialize_context_t *c,
917 const hb_set_t *unicodes) const
918 {
919 DefaultUVS *out = c->start_embed<DefaultUVS> ();
920 if (unlikely (!out)) return nullptr;
921 auto snap = c->snapshot ();
922
923 HBUINT32 len;
924 len = 0;
925 if (unlikely (!c->copy<HBUINT32> (len))) return nullptr;
926 unsigned init_len = c->length ();
927
928 if (this->len > unicodes->get_population () * hb_bit_storage ((unsigned) this->len))
929 {
930 hb_codepoint_t start = HB_SET_VALUE_INVALID;
931 hb_codepoint_t end = HB_SET_VALUE_INVALID;
932
933 for (hb_codepoint_t u = HB_SET_VALUE_INVALID;
934 unicodes->next (&u);)
935 {
936 if (!as_array ().bsearch (u))
937 continue;
938 if (start == HB_SET_VALUE_INVALID)
939 {
940 start = u;
941 end = start - 1;
942 }
943 if (end + 1 != u || end - start == 255)
944 {
945 UnicodeValueRange rec;
946 rec.startUnicodeValue = start;
947 rec.additionalCount = end - start;
948 c->copy<UnicodeValueRange> (rec);
949 start = u;
950 }
951 end = u;
952 }
953 if (start != HB_SET_VALUE_INVALID)
954 {
955 UnicodeValueRange rec;
956 rec.startUnicodeValue = start;
957 rec.additionalCount = end - start;
958 c->copy<UnicodeValueRange> (rec);
959 }
960
961 }
962 else
963 {
964 hb_codepoint_t lastCode = HB_SET_VALUE_INVALID;
965 int count = -1;
966
967 for (const UnicodeValueRange& _ : *this)
968 {
969 hb_codepoint_t curEntry = (hb_codepoint_t) (_.startUnicodeValue - 1);
970 hb_codepoint_t end = curEntry + _.additionalCount + 2;
971
972 for (; unicodes->next (&curEntry) && curEntry < end;)
973 {
974 count += 1;
975 if (lastCode == HB_SET_VALUE_INVALID)
976 lastCode = curEntry;
977 else if (lastCode + count != curEntry)
978 {
979 UnicodeValueRange rec;
980 rec.startUnicodeValue = lastCode;
981 rec.additionalCount = count - 1;
982 c->copy<UnicodeValueRange> (rec);
983
984 lastCode = curEntry;
985 count = 0;
986 }
987 }
988 }
989
990 if (lastCode != HB_MAP_VALUE_INVALID)
991 {
992 UnicodeValueRange rec;
993 rec.startUnicodeValue = lastCode;
994 rec.additionalCount = count;
995 c->copy<UnicodeValueRange> (rec);
996 }
997 }
998
999 if (c->length () - init_len == 0)
1000 {
1001 c->revert (snap);
1002 return nullptr;
1003 }
1004 else
1005 {
1006 if (unlikely (!c->check_assign (out->len,
1007 (c->length () - init_len) / UnicodeValueRange::static_size,
1008 HB_SERIALIZE_ERROR_INT_OVERFLOW))) return nullptr;
1009 return out;
1010 }
1011 }
1012
1013 public:
1014 DEFINE_SIZE_ARRAY (4, *this);
1015 };
1016
1017 struct UVSMapping
1018 {
cmpOT::UVSMapping1019 int cmp (const hb_codepoint_t &codepoint) const
1020 { return unicodeValue.cmp (codepoint); }
1021
sanitizeOT::UVSMapping1022 bool sanitize (hb_sanitize_context_t *c) const
1023 {
1024 TRACE_SANITIZE (this);
1025 return_trace (c->check_struct (this));
1026 }
1027
1028 HBUINT24 unicodeValue; /* Base Unicode value of the UVS */
1029 HBGlyphID16 glyphID; /* Glyph ID of the UVS */
1030 public:
1031 DEFINE_SIZE_STATIC (5);
1032 };
1033
1034 struct NonDefaultUVS : SortedArray32Of<UVSMapping>
1035 {
collect_unicodesOT::NonDefaultUVS1036 void collect_unicodes (hb_set_t *out) const
1037 {
1038 for (const auto& a : as_array ())
1039 out->add (a.unicodeValue);
1040 }
1041
collect_mappingOT::NonDefaultUVS1042 void collect_mapping (hb_set_t *unicodes, /* OUT */
1043 hb_map_t *mapping /* OUT */) const
1044 {
1045 for (const auto& a : as_array ())
1046 {
1047 hb_codepoint_t unicode = a.unicodeValue;
1048 hb_codepoint_t glyphid = a.glyphID;
1049 unicodes->add (unicode);
1050 mapping->set (unicode, glyphid);
1051 }
1052 }
1053
closure_glyphsOT::NonDefaultUVS1054 void closure_glyphs (const hb_set_t *unicodes,
1055 hb_set_t *glyphset) const
1056 {
1057 + as_array ()
1058 | hb_filter (unicodes, &UVSMapping::unicodeValue)
1059 | hb_map (&UVSMapping::glyphID)
1060 | hb_sink (glyphset)
1061 ;
1062 }
1063
copyOT::NonDefaultUVS1064 NonDefaultUVS* copy (hb_serialize_context_t *c,
1065 const hb_set_t *unicodes,
1066 const hb_set_t *glyphs_requested,
1067 const hb_map_t *glyph_map) const
1068 {
1069 NonDefaultUVS *out = c->start_embed<NonDefaultUVS> ();
1070 if (unlikely (!out)) return nullptr;
1071
1072 auto it =
1073 + as_array ()
1074 | hb_filter ([&] (const UVSMapping& _)
1075 {
1076 return unicodes->has (_.unicodeValue) || glyphs_requested->has (_.glyphID);
1077 })
1078 ;
1079
1080 if (!it) return nullptr;
1081
1082 HBUINT32 len;
1083 len = it.len ();
1084 if (unlikely (!c->copy<HBUINT32> (len))) return nullptr;
1085
1086 for (const UVSMapping& _ : it)
1087 {
1088 UVSMapping mapping;
1089 mapping.unicodeValue = _.unicodeValue;
1090 mapping.glyphID = glyph_map->get (_.glyphID);
1091 c->copy<UVSMapping> (mapping);
1092 }
1093
1094 return out;
1095 }
1096
1097 public:
1098 DEFINE_SIZE_ARRAY (4, *this);
1099 };
1100
1101 struct VariationSelectorRecord
1102 {
get_glyphOT::VariationSelectorRecord1103 glyph_variant_t get_glyph (hb_codepoint_t codepoint,
1104 hb_codepoint_t *glyph,
1105 const void *base) const
1106 {
1107 if ((base+defaultUVS).bfind (codepoint))
1108 return GLYPH_VARIANT_USE_DEFAULT;
1109 const UVSMapping &nonDefault = (base+nonDefaultUVS).bsearch (codepoint);
1110 if (nonDefault.glyphID)
1111 {
1112 *glyph = nonDefault.glyphID;
1113 return GLYPH_VARIANT_FOUND;
1114 }
1115 return GLYPH_VARIANT_NOT_FOUND;
1116 }
1117
VariationSelectorRecordOT::VariationSelectorRecord1118 VariationSelectorRecord(const VariationSelectorRecord& other)
1119 {
1120 *this = other;
1121 }
1122
operator =OT::VariationSelectorRecord1123 void operator= (const VariationSelectorRecord& other)
1124 {
1125 varSelector = other.varSelector;
1126 HBUINT32 offset = other.defaultUVS;
1127 defaultUVS = offset;
1128 offset = other.nonDefaultUVS;
1129 nonDefaultUVS = offset;
1130 }
1131
collect_unicodesOT::VariationSelectorRecord1132 void collect_unicodes (hb_set_t *out, const void *base) const
1133 {
1134 (base+defaultUVS).collect_unicodes (out);
1135 (base+nonDefaultUVS).collect_unicodes (out);
1136 }
1137
collect_mappingOT::VariationSelectorRecord1138 void collect_mapping (const void *base,
1139 hb_set_t *unicodes, /* OUT */
1140 hb_map_t *mapping /* OUT */) const
1141 {
1142 (base+defaultUVS).collect_unicodes (unicodes);
1143 (base+nonDefaultUVS).collect_mapping (unicodes, mapping);
1144 }
1145
cmpOT::VariationSelectorRecord1146 int cmp (const hb_codepoint_t &variation_selector) const
1147 { return varSelector.cmp (variation_selector); }
1148
sanitizeOT::VariationSelectorRecord1149 bool sanitize (hb_sanitize_context_t *c, const void *base) const
1150 {
1151 TRACE_SANITIZE (this);
1152 return_trace (c->check_struct (this) &&
1153 defaultUVS.sanitize (c, base) &&
1154 nonDefaultUVS.sanitize (c, base));
1155 }
1156
1157 hb_pair_t<unsigned, unsigned>
copyOT::VariationSelectorRecord1158 copy (hb_serialize_context_t *c,
1159 const hb_set_t *unicodes,
1160 const hb_set_t *glyphs_requested,
1161 const hb_map_t *glyph_map,
1162 const void *base) const
1163 {
1164 auto snap = c->snapshot ();
1165 auto *out = c->embed<VariationSelectorRecord> (*this);
1166 if (unlikely (!out)) return hb_pair (0, 0);
1167
1168 out->defaultUVS = 0;
1169 out->nonDefaultUVS = 0;
1170
1171 unsigned non_default_uvs_objidx = 0;
1172 if (nonDefaultUVS != 0)
1173 {
1174 c->push ();
1175 if (c->copy (base+nonDefaultUVS, unicodes, glyphs_requested, glyph_map))
1176 non_default_uvs_objidx = c->pop_pack ();
1177 else c->pop_discard ();
1178 }
1179
1180 unsigned default_uvs_objidx = 0;
1181 if (defaultUVS != 0)
1182 {
1183 c->push ();
1184 if (c->copy (base+defaultUVS, unicodes))
1185 default_uvs_objidx = c->pop_pack ();
1186 else c->pop_discard ();
1187 }
1188
1189
1190 if (!default_uvs_objidx && !non_default_uvs_objidx)
1191 c->revert (snap);
1192
1193 return hb_pair (default_uvs_objidx, non_default_uvs_objidx);
1194 }
1195
1196 HBUINT24 varSelector; /* Variation selector. */
1197 Offset32To<DefaultUVS>
1198 defaultUVS; /* Offset to Default UVS Table. May be 0. */
1199 Offset32To<NonDefaultUVS>
1200 nonDefaultUVS; /* Offset to Non-Default UVS Table. May be 0. */
1201 public:
1202 DEFINE_SIZE_STATIC (11);
1203 };
1204
1205 struct CmapSubtableFormat14
1206 {
get_glyph_variantOT::CmapSubtableFormat141207 glyph_variant_t get_glyph_variant (hb_codepoint_t codepoint,
1208 hb_codepoint_t variation_selector,
1209 hb_codepoint_t *glyph) const
1210 { return record.bsearch (variation_selector).get_glyph (codepoint, glyph, this); }
1211
collect_variation_selectorsOT::CmapSubtableFormat141212 void collect_variation_selectors (hb_set_t *out) const
1213 {
1214 for (const auto& a : record.as_array ())
1215 out->add (a.varSelector);
1216 }
collect_variation_unicodesOT::CmapSubtableFormat141217 void collect_variation_unicodes (hb_codepoint_t variation_selector,
1218 hb_set_t *out) const
1219 { record.bsearch (variation_selector).collect_unicodes (out, this); }
1220
serializeOT::CmapSubtableFormat141221 void serialize (hb_serialize_context_t *c,
1222 const hb_set_t *unicodes,
1223 const hb_set_t *glyphs_requested,
1224 const hb_map_t *glyph_map,
1225 const void *base)
1226 {
1227 auto snap = c->snapshot ();
1228 unsigned table_initpos = c->length ();
1229 const char* init_tail = c->tail;
1230
1231 if (unlikely (!c->extend_min (this))) return;
1232 this->format = 14;
1233
1234 auto src_tbl = reinterpret_cast<const CmapSubtableFormat14*> (base);
1235
1236 /*
1237 * Some versions of OTS require that offsets are in order. Due to the use
1238 * of push()/pop_pack() serializing the variation records in order results
1239 * in the offsets being in reverse order (first record has the largest
1240 * offset). While this is perfectly valid, it will cause some versions of
1241 * OTS to consider this table bad.
1242 *
1243 * So to prevent this issue we serialize the variation records in reverse
1244 * order, so that the offsets are ordered from small to large. Since
1245 * variation records are supposed to be in increasing order of varSelector
1246 * we then have to reverse the order of the written variation selector
1247 * records after everything is finalized.
1248 */
1249 hb_vector_t<hb_pair_t<unsigned, unsigned>> obj_indices;
1250 for (int i = src_tbl->record.len - 1; i >= 0; i--)
1251 {
1252 hb_pair_t<unsigned, unsigned> result = src_tbl->record[i].copy (c, unicodes, glyphs_requested, glyph_map, base);
1253 if (result.first || result.second)
1254 obj_indices.push (result);
1255 }
1256
1257 if (c->length () - table_initpos == CmapSubtableFormat14::min_size)
1258 {
1259 c->revert (snap);
1260 return;
1261 }
1262
1263 if (unlikely (!c->check_success (!obj_indices.in_error ())))
1264 return;
1265
1266 int tail_len = init_tail - c->tail;
1267 c->check_assign (this->length, c->length () - table_initpos + tail_len,
1268 HB_SERIALIZE_ERROR_INT_OVERFLOW);
1269 c->check_assign (this->record.len,
1270 (c->length () - table_initpos - CmapSubtableFormat14::min_size) /
1271 VariationSelectorRecord::static_size,
1272 HB_SERIALIZE_ERROR_INT_OVERFLOW);
1273
1274 /* Correct the incorrect write order by reversing the order of the variation
1275 records array. */
1276 _reverse_variation_records ();
1277
1278 /* Now that records are in the right order, we can set up the offsets. */
1279 _add_links_to_variation_records (c, obj_indices);
1280 }
1281
_reverse_variation_recordsOT::CmapSubtableFormat141282 void _reverse_variation_records ()
1283 {
1284 record.as_array ().reverse ();
1285 }
1286
_add_links_to_variation_recordsOT::CmapSubtableFormat141287 void _add_links_to_variation_records (hb_serialize_context_t *c,
1288 const hb_vector_t<hb_pair_t<unsigned, unsigned>>& obj_indices)
1289 {
1290 for (unsigned i = 0; i < obj_indices.length; i++)
1291 {
1292 /*
1293 * Since the record array has been reversed (see comments in copy())
1294 * but obj_indices has not been, the indices at obj_indices[i]
1295 * are for the variation record at record[j].
1296 */
1297 int j = obj_indices.length - 1 - i;
1298 c->add_link (record[j].defaultUVS, obj_indices[i].first);
1299 c->add_link (record[j].nonDefaultUVS, obj_indices[i].second);
1300 }
1301 }
1302
closure_glyphsOT::CmapSubtableFormat141303 void closure_glyphs (const hb_set_t *unicodes,
1304 hb_set_t *glyphset) const
1305 {
1306 + hb_iter (record)
1307 | hb_filter (hb_bool, &VariationSelectorRecord::nonDefaultUVS)
1308 | hb_map (&VariationSelectorRecord::nonDefaultUVS)
1309 | hb_map (hb_add (this))
1310 | hb_apply ([=] (const NonDefaultUVS& _) { _.closure_glyphs (unicodes, glyphset); })
1311 ;
1312 }
1313
collect_unicodesOT::CmapSubtableFormat141314 void collect_unicodes (hb_set_t *out) const
1315 {
1316 for (const VariationSelectorRecord& _ : record)
1317 _.collect_unicodes (out, this);
1318 }
1319
collect_mappingOT::CmapSubtableFormat141320 void collect_mapping (hb_set_t *unicodes, /* OUT */
1321 hb_map_t *mapping /* OUT */) const
1322 {
1323 for (const VariationSelectorRecord& _ : record)
1324 _.collect_mapping (this, unicodes, mapping);
1325 }
1326
sanitizeOT::CmapSubtableFormat141327 bool sanitize (hb_sanitize_context_t *c) const
1328 {
1329 TRACE_SANITIZE (this);
1330 return_trace (c->check_struct (this) &&
1331 record.sanitize (c, this));
1332 }
1333
1334 protected:
1335 HBUINT16 format; /* Format number is set to 14. */
1336 HBUINT32 length; /* Byte length of this subtable. */
1337 SortedArray32Of<VariationSelectorRecord>
1338 record; /* Variation selector records; sorted
1339 * in increasing order of `varSelector'. */
1340 public:
1341 DEFINE_SIZE_ARRAY (10, record);
1342 };
1343
1344 struct CmapSubtable
1345 {
1346 /* Note: We intentionally do NOT implement subtable formats 2 and 8. */
1347
get_glyphOT::CmapSubtable1348 bool get_glyph (hb_codepoint_t codepoint,
1349 hb_codepoint_t *glyph) const
1350 {
1351 switch (u.format) {
1352 case 0: return u.format0 .get_glyph (codepoint, glyph);
1353 case 4: return u.format4 .get_glyph (codepoint, glyph);
1354 case 6: return u.format6 .get_glyph (codepoint, glyph);
1355 case 10: return u.format10.get_glyph (codepoint, glyph);
1356 case 12: return u.format12.get_glyph (codepoint, glyph);
1357 case 13: return u.format13.get_glyph (codepoint, glyph);
1358 case 14:
1359 default: return false;
1360 }
1361 }
collect_unicodesOT::CmapSubtable1362 void collect_unicodes (hb_set_t *out, unsigned int num_glyphs = UINT_MAX) const
1363 {
1364 switch (u.format) {
1365 case 0: u.format0 .collect_unicodes (out); return;
1366 case 4: u.format4 .collect_unicodes (out); return;
1367 case 6: u.format6 .collect_unicodes (out); return;
1368 case 10: u.format10.collect_unicodes (out); return;
1369 case 12: u.format12.collect_unicodes (out, num_glyphs); return;
1370 case 13: u.format13.collect_unicodes (out, num_glyphs); return;
1371 case 14:
1372 default: return;
1373 }
1374 }
1375
collect_mappingOT::CmapSubtable1376 void collect_mapping (hb_set_t *unicodes, /* OUT */
1377 hb_map_t *mapping, /* OUT */
1378 unsigned num_glyphs = UINT_MAX) const
1379 {
1380 switch (u.format) {
1381 case 0: u.format0 .collect_mapping (unicodes, mapping); return;
1382 case 4: u.format4 .collect_mapping (unicodes, mapping); return;
1383 case 6: u.format6 .collect_mapping (unicodes, mapping); return;
1384 case 10: u.format10.collect_mapping (unicodes, mapping); return;
1385 case 12: u.format12.collect_mapping (unicodes, mapping, num_glyphs); return;
1386 case 13: u.format13.collect_mapping (unicodes, mapping, num_glyphs); return;
1387 case 14:
1388 default: return;
1389 }
1390 }
1391
get_languageOT::CmapSubtable1392 unsigned get_language () const
1393 {
1394 switch (u.format) {
1395 case 0: return u.format0 .get_language ();
1396 case 4: return u.format4 .get_language ();
1397 case 6: return u.format6 .get_language ();
1398 case 10: return u.format10.get_language ();
1399 case 12: return u.format12.get_language ();
1400 case 13: return u.format13.get_language ();
1401 case 14:
1402 default: return 0;
1403 }
1404 }
1405
1406 template<typename Iterator,
1407 hb_requires (hb_is_iterator (Iterator))>
serializeOT::CmapSubtable1408 void serialize (hb_serialize_context_t *c,
1409 Iterator it,
1410 unsigned format,
1411 const hb_subset_plan_t *plan,
1412 const void *base)
1413 {
1414 switch (format) {
1415 case 4: return u.format4.serialize (c, it);
1416 case 12: return u.format12.serialize (c, it);
1417 case 14: return u.format14.serialize (c, plan->unicodes, plan->glyphs_requested, plan->glyph_map, base);
1418 default: return;
1419 }
1420 }
1421
sanitizeOT::CmapSubtable1422 bool sanitize (hb_sanitize_context_t *c) const
1423 {
1424 TRACE_SANITIZE (this);
1425 if (!u.format.sanitize (c)) return_trace (false);
1426 switch (u.format) {
1427 case 0: return_trace (u.format0 .sanitize (c));
1428 case 4: return_trace (u.format4 .sanitize (c));
1429 case 6: return_trace (u.format6 .sanitize (c));
1430 case 10: return_trace (u.format10.sanitize (c));
1431 case 12: return_trace (u.format12.sanitize (c));
1432 case 13: return_trace (u.format13.sanitize (c));
1433 case 14: return_trace (u.format14.sanitize (c));
1434 default:return_trace (true);
1435 }
1436 }
1437
1438 public:
1439 union {
1440 HBUINT16 format; /* Format identifier */
1441 CmapSubtableFormat0 format0;
1442 CmapSubtableFormat4 format4;
1443 CmapSubtableFormat6 format6;
1444 CmapSubtableFormat10 format10;
1445 CmapSubtableFormat12 format12;
1446 CmapSubtableFormat13 format13;
1447 CmapSubtableFormat14 format14;
1448 } u;
1449 public:
1450 DEFINE_SIZE_UNION (2, format);
1451 };
1452
1453
1454 struct EncodingRecord
1455 {
cmpOT::EncodingRecord1456 int cmp (const EncodingRecord &other) const
1457 {
1458 int ret;
1459 ret = platformID.cmp (other.platformID);
1460 if (ret) return ret;
1461 ret = encodingID.cmp (other.encodingID);
1462 if (ret) return ret;
1463 return 0;
1464 }
1465
sanitizeOT::EncodingRecord1466 bool sanitize (hb_sanitize_context_t *c, const void *base) const
1467 {
1468 TRACE_SANITIZE (this);
1469 return_trace (c->check_struct (this) &&
1470 subtable.sanitize (c, base));
1471 }
1472
1473 template<typename Iterator,
1474 hb_requires (hb_is_iterator (Iterator))>
copyOT::EncodingRecord1475 EncodingRecord* copy (hb_serialize_context_t *c,
1476 Iterator it,
1477 unsigned format,
1478 const void *base,
1479 const hb_subset_plan_t *plan,
1480 /* INOUT */ unsigned *objidx) const
1481 {
1482 TRACE_SERIALIZE (this);
1483 auto snap = c->snapshot ();
1484 auto *out = c->embed (this);
1485 if (unlikely (!out)) return_trace (nullptr);
1486 out->subtable = 0;
1487
1488 if (*objidx == 0)
1489 {
1490 CmapSubtable *cmapsubtable = c->push<CmapSubtable> ();
1491 unsigned origin_length = c->length ();
1492 cmapsubtable->serialize (c, it, format, plan, &(base+subtable));
1493 if (c->length () - origin_length > 0) *objidx = c->pop_pack ();
1494 else c->pop_discard ();
1495 }
1496
1497 if (*objidx == 0)
1498 {
1499 c->revert (snap);
1500 return_trace (nullptr);
1501 }
1502
1503 c->add_link (out->subtable, *objidx);
1504 return_trace (out);
1505 }
1506
1507 HBUINT16 platformID; /* Platform ID. */
1508 HBUINT16 encodingID; /* Platform-specific encoding ID. */
1509 Offset32To<CmapSubtable>
1510 subtable; /* Byte offset from beginning of table to the subtable for this encoding. */
1511 public:
1512 DEFINE_SIZE_STATIC (8);
1513 };
1514
1515 struct cmap;
1516
1517 struct SubtableUnicodesCache {
1518
1519 private:
1520 hb_blob_ptr_t<cmap> base_blob;
1521 const char* base;
1522 hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> cached_unicodes;
1523
1524 public:
1525
createOT::SubtableUnicodesCache1526 static SubtableUnicodesCache* create (hb_blob_ptr_t<cmap> source_table)
1527 {
1528 SubtableUnicodesCache* cache =
1529 (SubtableUnicodesCache*) hb_malloc (sizeof(SubtableUnicodesCache));
1530 new (cache) SubtableUnicodesCache (source_table);
1531 return cache;
1532 }
1533
destroyOT::SubtableUnicodesCache1534 static void destroy (void* value) {
1535 if (!value) return;
1536
1537 SubtableUnicodesCache* cache = (SubtableUnicodesCache*) value;
1538 cache->~SubtableUnicodesCache ();
1539 hb_free (cache);
1540 }
1541
SubtableUnicodesCacheOT::SubtableUnicodesCache1542 SubtableUnicodesCache(const void* cmap_base)
1543 : base_blob(),
1544 base ((const char*) cmap_base),
1545 cached_unicodes ()
1546 {}
1547
SubtableUnicodesCacheOT::SubtableUnicodesCache1548 SubtableUnicodesCache(hb_blob_ptr_t<cmap> base_blob_)
1549 : base_blob(base_blob_),
1550 base ((const char *) base_blob.get()),
1551 cached_unicodes ()
1552 {}
1553
~SubtableUnicodesCacheOT::SubtableUnicodesCache1554 ~SubtableUnicodesCache()
1555 {
1556 base_blob.destroy ();
1557 }
1558
same_baseOT::SubtableUnicodesCache1559 bool same_base(const void* other) const
1560 {
1561 return other == (const void*) base;
1562 }
1563
set_forOT::SubtableUnicodesCache1564 const hb_set_t* set_for (const EncodingRecord* record,
1565 SubtableUnicodesCache& mutable_cache) const
1566 {
1567 if (cached_unicodes.has ((unsigned) ((const char *) record - base)))
1568 return cached_unicodes.get ((unsigned) ((const char *) record - base));
1569
1570 return mutable_cache.set_for (record);
1571 }
1572
set_forOT::SubtableUnicodesCache1573 const hb_set_t* set_for (const EncodingRecord* record)
1574 {
1575 if (!cached_unicodes.has ((unsigned) ((const char *) record - base)))
1576 {
1577 hb_set_t *s = hb_set_create ();
1578 if (unlikely (s->in_error ()))
1579 return hb_set_get_empty ();
1580
1581 (base+record->subtable).collect_unicodes (s);
1582
1583 if (unlikely (!cached_unicodes.set ((unsigned) ((const char *) record - base), hb::unique_ptr<hb_set_t> {s})))
1584 return hb_set_get_empty ();
1585
1586 return s;
1587 }
1588 return cached_unicodes.get ((unsigned) ((const char *) record - base));
1589 }
1590
1591 };
1592
1593 static inline uint_fast16_t
_hb_symbol_pua_map(unsigned codepoint)1594 _hb_symbol_pua_map (unsigned codepoint)
1595 {
1596 if (codepoint <= 0x00FFu)
1597 {
1598 /* For symbol-encoded OpenType fonts, we duplicate the
1599 * U+F000..F0FF range at U+0000..U+00FF. That's what
1600 * Windows seems to do, and that's hinted about at:
1601 * https://docs.microsoft.com/en-us/typography/opentype/spec/recom
1602 * under "Non-Standard (Symbol) Fonts". */
1603 return 0xF000u + codepoint;
1604 }
1605 return 0;
1606 }
1607
1608 struct cmap
1609 {
1610 static constexpr hb_tag_t tableTag = HB_OT_TAG_cmap;
1611
1612
create_filled_cacheOT::cmap1613 static SubtableUnicodesCache* create_filled_cache(hb_blob_ptr_t<cmap> source_table) {
1614 const cmap* cmap = source_table.get();
1615 auto it =
1616 + hb_iter (cmap->encodingRecord)
1617 | hb_filter ([&](const EncodingRecord& _) {
1618 return cmap::filter_encoding_records_for_subset (cmap, _);
1619 })
1620 ;
1621
1622 SubtableUnicodesCache* cache = SubtableUnicodesCache::create(source_table);
1623 for (const EncodingRecord& _ : it)
1624 cache->set_for(&_); // populate the cache for this encoding record.
1625
1626 return cache;
1627 }
1628
1629 template<typename Iterator, typename EncodingRecIter,
1630 hb_requires (hb_is_iterator (EncodingRecIter))>
serializeOT::cmap1631 bool serialize (hb_serialize_context_t *c,
1632 Iterator it,
1633 EncodingRecIter encodingrec_iter,
1634 const void *base,
1635 hb_subset_plan_t *plan,
1636 bool drop_format_4 = false)
1637 {
1638 if (unlikely (!c->extend_min ((*this)))) return false;
1639 this->version = 0;
1640
1641 unsigned format4objidx = 0, format12objidx = 0, format14objidx = 0;
1642 auto snap = c->snapshot ();
1643
1644 SubtableUnicodesCache local_unicodes_cache (base);
1645 const SubtableUnicodesCache* unicodes_cache = &local_unicodes_cache;
1646
1647 if (plan->accelerator &&
1648 plan->accelerator->cmap_cache &&
1649 plan->accelerator->cmap_cache->same_base (base))
1650 unicodes_cache = plan->accelerator->cmap_cache;
1651
1652 for (const EncodingRecord& _ : encodingrec_iter)
1653 {
1654 if (c->in_error ())
1655 return false;
1656
1657 unsigned format = (base+_.subtable).u.format;
1658 if (format != 4 && format != 12 && format != 14) continue;
1659
1660 const hb_set_t* unicodes_set = unicodes_cache->set_for (&_, local_unicodes_cache);
1661
1662 if (!drop_format_4 && format == 4)
1663 {
1664 c->copy (_, + it | hb_filter (*unicodes_set, hb_first), 4u, base, plan, &format4objidx);
1665 if (c->in_error () && c->only_overflow ())
1666 {
1667 // cmap4 overflowed, reset and retry serialization without format 4 subtables.
1668 c->revert (snap);
1669 return serialize (c, it,
1670 encodingrec_iter,
1671 base,
1672 plan,
1673 true);
1674 }
1675 }
1676
1677 else if (format == 12)
1678 {
1679 if (_can_drop (_,
1680 *unicodes_set,
1681 base,
1682 *unicodes_cache,
1683 local_unicodes_cache,
1684 + it | hb_map (hb_first), encodingrec_iter))
1685 continue;
1686 c->copy (_, + it | hb_filter (*unicodes_set, hb_first), 12u, base, plan, &format12objidx);
1687 }
1688 else if (format == 14) c->copy (_, it, 14u, base, plan, &format14objidx);
1689 }
1690 c->check_assign(this->encodingRecord.len,
1691 (c->length () - cmap::min_size)/EncodingRecord::static_size,
1692 HB_SERIALIZE_ERROR_INT_OVERFLOW);
1693
1694 // Fail if format 4 was dropped and there is no cmap12.
1695 return !drop_format_4 || format12objidx;
1696 }
1697
1698 template<typename Iterator, typename EncodingRecordIterator,
1699 hb_requires (hb_is_iterator (Iterator)),
1700 hb_requires (hb_is_iterator (EncodingRecordIterator))>
_can_dropOT::cmap1701 bool _can_drop (const EncodingRecord& cmap12,
1702 const hb_set_t& cmap12_unicodes,
1703 const void* base,
1704 const SubtableUnicodesCache& unicodes_cache,
1705 SubtableUnicodesCache& local_unicodes_cache,
1706 Iterator subset_unicodes,
1707 EncodingRecordIterator encoding_records)
1708 {
1709 for (auto cp : + subset_unicodes | hb_filter (cmap12_unicodes))
1710 {
1711 if (cp >= 0x10000) return false;
1712 }
1713
1714 unsigned target_platform;
1715 unsigned target_encoding;
1716 unsigned target_language = (base+cmap12.subtable).get_language ();
1717
1718 if (cmap12.platformID == 0 && cmap12.encodingID == 4)
1719 {
1720 target_platform = 0;
1721 target_encoding = 3;
1722 } else if (cmap12.platformID == 3 && cmap12.encodingID == 10) {
1723 target_platform = 3;
1724 target_encoding = 1;
1725 } else {
1726 return false;
1727 }
1728
1729 for (const auto& _ : encoding_records)
1730 {
1731 if (_.platformID != target_platform
1732 || _.encodingID != target_encoding
1733 || (base+_.subtable).get_language() != target_language)
1734 continue;
1735
1736 const hb_set_t* sibling_unicodes = unicodes_cache.set_for (&_, local_unicodes_cache);
1737
1738 auto cmap12 = + subset_unicodes | hb_filter (cmap12_unicodes);
1739 auto sibling = + subset_unicodes | hb_filter (*sibling_unicodes);
1740 for (; cmap12 && sibling; cmap12++, sibling++)
1741 {
1742 unsigned a = *cmap12;
1743 unsigned b = *sibling;
1744 if (a != b) return false;
1745 }
1746
1747 return !cmap12 && !sibling;
1748 }
1749
1750 return false;
1751 }
1752
closure_glyphsOT::cmap1753 void closure_glyphs (const hb_set_t *unicodes,
1754 hb_set_t *glyphset) const
1755 {
1756 + hb_iter (encodingRecord)
1757 | hb_map (&EncodingRecord::subtable)
1758 | hb_map (hb_add (this))
1759 | hb_filter ([&] (const CmapSubtable& _) { return _.u.format == 14; })
1760 | hb_apply ([=] (const CmapSubtable& _) { _.u.format14.closure_glyphs (unicodes, glyphset); })
1761 ;
1762 }
1763
subsetOT::cmap1764 bool subset (hb_subset_context_t *c) const
1765 {
1766 TRACE_SUBSET (this);
1767
1768 cmap *cmap_prime = c->serializer->start_embed<cmap> ();
1769 if (unlikely (!c->serializer->check_success (cmap_prime))) return_trace (false);
1770
1771 auto encodingrec_iter =
1772 + hb_iter (encodingRecord)
1773 | hb_filter ([&](const EncodingRecord& _) {
1774 return cmap::filter_encoding_records_for_subset (this, _);
1775 })
1776 ;
1777
1778 if (unlikely (!encodingrec_iter.len ())) return_trace (false);
1779
1780 const EncodingRecord *unicode_bmp= nullptr, *unicode_ucs4 = nullptr, *ms_bmp = nullptr, *ms_ucs4 = nullptr;
1781 bool has_format12 = false;
1782
1783 for (const EncodingRecord& _ : encodingrec_iter)
1784 {
1785 unsigned format = (this + _.subtable).u.format;
1786 if (format == 12) has_format12 = true;
1787
1788 const EncodingRecord *table = std::addressof (_);
1789 if (_.platformID == 0 && _.encodingID == 3) unicode_bmp = table;
1790 else if (_.platformID == 0 && _.encodingID == 4) unicode_ucs4 = table;
1791 else if (_.platformID == 3 && _.encodingID == 1) ms_bmp = table;
1792 else if (_.platformID == 3 && _.encodingID == 10) ms_ucs4 = table;
1793 }
1794
1795 if (unlikely (!has_format12 && !unicode_bmp && !ms_bmp)) return_trace (false);
1796 if (unlikely (has_format12 && (!unicode_ucs4 && !ms_ucs4))) return_trace (false);
1797
1798 auto it =
1799 + c->plan->unicode_to_new_gid_list.iter ()
1800 | hb_filter ([&] (const hb_pair_t<hb_codepoint_t, hb_codepoint_t> _)
1801 { return (_.second != HB_MAP_VALUE_INVALID); })
1802 ;
1803
1804 return_trace (cmap_prime->serialize (c->serializer,
1805 it,
1806 encodingrec_iter,
1807 this,
1808 c->plan));
1809 }
1810
find_best_subtableOT::cmap1811 const CmapSubtable *find_best_subtable (bool *symbol = nullptr) const
1812 {
1813 if (symbol) *symbol = false;
1814
1815 const CmapSubtable *subtable;
1816
1817 /* Symbol subtable.
1818 * Prefer symbol if available.
1819 * https://github.com/harfbuzz/harfbuzz/issues/1918 */
1820 if ((subtable = this->find_subtable (3, 0)))
1821 {
1822 if (symbol) *symbol = true;
1823 return subtable;
1824 }
1825
1826 /* 32-bit subtables. */
1827 if ((subtable = this->find_subtable (3, 10))) return subtable;
1828 if ((subtable = this->find_subtable (0, 6))) return subtable;
1829 if ((subtable = this->find_subtable (0, 4))) return subtable;
1830
1831 /* 16-bit subtables. */
1832 if ((subtable = this->find_subtable (3, 1))) return subtable;
1833 if ((subtable = this->find_subtable (0, 3))) return subtable;
1834 if ((subtable = this->find_subtable (0, 2))) return subtable;
1835 if ((subtable = this->find_subtable (0, 1))) return subtable;
1836 if ((subtable = this->find_subtable (0, 0))) return subtable;
1837
1838 /* Meh. */
1839 return &Null (CmapSubtable);
1840 }
1841
1842 struct accelerator_t
1843 {
accelerator_tOT::cmap::accelerator_t1844 accelerator_t (hb_face_t *face)
1845 {
1846 this->table = hb_sanitize_context_t ().reference_table<cmap> (face);
1847 bool symbol;
1848 this->subtable = table->find_best_subtable (&symbol);
1849 this->subtable_uvs = &Null (CmapSubtableFormat14);
1850 {
1851 const CmapSubtable *st = table->find_subtable (0, 5);
1852 if (st && st->u.format == 14)
1853 subtable_uvs = &st->u.format14;
1854 }
1855
1856 this->get_glyph_data = subtable;
1857 if (unlikely (symbol))
1858 {
1859 switch ((unsigned) face->table.OS2->get_font_page ()) {
1860 case OS2::font_page_t::FONT_PAGE_NONE:
1861 this->get_glyph_funcZ = get_glyph_from_symbol<CmapSubtable, _hb_symbol_pua_map>;
1862 break;
1863 #ifndef HB_NO_OT_SHAPER_ARABIC_FALLBACK
1864 case OS2::font_page_t::FONT_PAGE_SIMP_ARABIC:
1865 this->get_glyph_funcZ = get_glyph_from_symbol<CmapSubtable, _hb_arabic_pua_simp_map>;
1866 break;
1867 case OS2::font_page_t::FONT_PAGE_TRAD_ARABIC:
1868 this->get_glyph_funcZ = get_glyph_from_symbol<CmapSubtable, _hb_arabic_pua_trad_map>;
1869 break;
1870 #endif
1871 default:
1872 this->get_glyph_funcZ = get_glyph_from<CmapSubtable>;
1873 break;
1874 }
1875 }
1876 else
1877 {
1878 switch (subtable->u.format) {
1879 /* Accelerate format 4 and format 12. */
1880 default:
1881 this->get_glyph_funcZ = get_glyph_from<CmapSubtable>;
1882 break;
1883 case 12:
1884 this->get_glyph_funcZ = get_glyph_from<CmapSubtableFormat12>;
1885 break;
1886 case 4:
1887 {
1888 this->format4_accel.init (&subtable->u.format4);
1889 this->get_glyph_data = &this->format4_accel;
1890 this->get_glyph_funcZ = this->format4_accel.get_glyph_func;
1891 break;
1892 }
1893 }
1894 }
1895 }
~accelerator_tOT::cmap::accelerator_t1896 ~accelerator_t () { this->table.destroy (); }
1897
get_nominal_glyphOT::cmap::accelerator_t1898 bool get_nominal_glyph (hb_codepoint_t unicode,
1899 hb_codepoint_t *glyph) const
1900 {
1901 if (unlikely (!this->get_glyph_funcZ)) return false;
1902 return this->get_glyph_funcZ (this->get_glyph_data, unicode, glyph);
1903 }
get_nominal_glyphsOT::cmap::accelerator_t1904 unsigned int get_nominal_glyphs (unsigned int count,
1905 const hb_codepoint_t *first_unicode,
1906 unsigned int unicode_stride,
1907 hb_codepoint_t *first_glyph,
1908 unsigned int glyph_stride) const
1909 {
1910 if (unlikely (!this->get_glyph_funcZ)) return 0;
1911
1912 hb_cmap_get_glyph_func_t get_glyph_funcZ = this->get_glyph_funcZ;
1913 const void *get_glyph_data = this->get_glyph_data;
1914
1915 unsigned int done;
1916 for (done = 0;
1917 done < count && get_glyph_funcZ (get_glyph_data, *first_unicode, first_glyph);
1918 done++)
1919 {
1920 first_unicode = &StructAtOffsetUnaligned<hb_codepoint_t> (first_unicode, unicode_stride);
1921 first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
1922 }
1923 return done;
1924 }
1925
get_variation_glyphOT::cmap::accelerator_t1926 bool get_variation_glyph (hb_codepoint_t unicode,
1927 hb_codepoint_t variation_selector,
1928 hb_codepoint_t *glyph) const
1929 {
1930 switch (this->subtable_uvs->get_glyph_variant (unicode,
1931 variation_selector,
1932 glyph))
1933 {
1934 case GLYPH_VARIANT_NOT_FOUND: return false;
1935 case GLYPH_VARIANT_FOUND: return true;
1936 case GLYPH_VARIANT_USE_DEFAULT: break;
1937 }
1938
1939 return get_nominal_glyph (unicode, glyph);
1940 }
1941
collect_unicodesOT::cmap::accelerator_t1942 void collect_unicodes (hb_set_t *out, unsigned int num_glyphs) const
1943 { subtable->collect_unicodes (out, num_glyphs); }
collect_mappingOT::cmap::accelerator_t1944 void collect_mapping (hb_set_t *unicodes, hb_map_t *mapping,
1945 unsigned num_glyphs = UINT_MAX) const
1946 { subtable->collect_mapping (unicodes, mapping, num_glyphs); }
collect_variation_selectorsOT::cmap::accelerator_t1947 void collect_variation_selectors (hb_set_t *out) const
1948 { subtable_uvs->collect_variation_selectors (out); }
collect_variation_unicodesOT::cmap::accelerator_t1949 void collect_variation_unicodes (hb_codepoint_t variation_selector,
1950 hb_set_t *out) const
1951 { subtable_uvs->collect_variation_unicodes (variation_selector, out); }
1952
1953 protected:
1954 typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj,
1955 hb_codepoint_t codepoint,
1956 hb_codepoint_t *glyph);
1957 typedef uint_fast16_t (*hb_pua_remap_func_t) (unsigned);
1958
1959 template <typename Type>
get_glyph_fromOT::cmap::accelerator_t1960 HB_INTERNAL static bool get_glyph_from (const void *obj,
1961 hb_codepoint_t codepoint,
1962 hb_codepoint_t *glyph)
1963 {
1964 const Type *typed_obj = (const Type *) obj;
1965 return typed_obj->get_glyph (codepoint, glyph);
1966 }
1967
1968 template <typename Type, hb_pua_remap_func_t remap>
get_glyph_from_symbolOT::cmap::accelerator_t1969 HB_INTERNAL static bool get_glyph_from_symbol (const void *obj,
1970 hb_codepoint_t codepoint,
1971 hb_codepoint_t *glyph)
1972 {
1973 const Type *typed_obj = (const Type *) obj;
1974 if (likely (typed_obj->get_glyph (codepoint, glyph)))
1975 return true;
1976
1977 if (hb_codepoint_t c = remap (codepoint))
1978 return typed_obj->get_glyph (c, glyph);
1979
1980 return false;
1981 }
1982
1983 private:
1984 hb_nonnull_ptr_t<const CmapSubtable> subtable;
1985 hb_nonnull_ptr_t<const CmapSubtableFormat14> subtable_uvs;
1986
1987 hb_cmap_get_glyph_func_t get_glyph_funcZ;
1988 const void *get_glyph_data;
1989
1990 CmapSubtableFormat4::accelerator_t format4_accel;
1991
1992 public:
1993 hb_blob_ptr_t<cmap> table;
1994 };
1995
1996 protected:
1997
find_subtableOT::cmap1998 const CmapSubtable *find_subtable (unsigned int platform_id,
1999 unsigned int encoding_id) const
2000 {
2001 EncodingRecord key;
2002 key.platformID = platform_id;
2003 key.encodingID = encoding_id;
2004
2005 const EncodingRecord &result = encodingRecord.bsearch (key);
2006 if (!result.subtable)
2007 return nullptr;
2008
2009 return &(this+result.subtable);
2010 }
2011
find_encodingrecOT::cmap2012 const EncodingRecord *find_encodingrec (unsigned int platform_id,
2013 unsigned int encoding_id) const
2014 {
2015 EncodingRecord key;
2016 key.platformID = platform_id;
2017 key.encodingID = encoding_id;
2018
2019 return encodingRecord.as_array ().bsearch (key);
2020 }
2021
find_subtableOT::cmap2022 bool find_subtable (unsigned format) const
2023 {
2024 auto it =
2025 + hb_iter (encodingRecord)
2026 | hb_map (&EncodingRecord::subtable)
2027 | hb_map (hb_add (this))
2028 | hb_filter ([&] (const CmapSubtable& _) { return _.u.format == format; })
2029 ;
2030
2031 return it.len ();
2032 }
2033
2034 public:
2035
sanitizeOT::cmap2036 bool sanitize (hb_sanitize_context_t *c) const
2037 {
2038 TRACE_SANITIZE (this);
2039 return_trace (c->check_struct (this) &&
2040 likely (version == 0) &&
2041 encodingRecord.sanitize (c, this));
2042 }
2043
2044 private:
2045
filter_encoding_records_for_subsetOT::cmap2046 static bool filter_encoding_records_for_subset(const cmap* cmap,
2047 const EncodingRecord& _)
2048 {
2049 return
2050 (_.platformID == 0 && _.encodingID == 3) ||
2051 (_.platformID == 0 && _.encodingID == 4) ||
2052 (_.platformID == 3 && _.encodingID == 1) ||
2053 (_.platformID == 3 && _.encodingID == 10) ||
2054 (cmap + _.subtable).u.format == 14;
2055 }
2056
2057 protected:
2058 HBUINT16 version; /* Table version number (0). */
2059 SortedArray16Of<EncodingRecord>
2060 encodingRecord; /* Encoding tables. */
2061 public:
2062 DEFINE_SIZE_ARRAY (4, encodingRecord);
2063 };
2064
2065 struct cmap_accelerator_t : cmap::accelerator_t {
cmap_accelerator_tOT::cmap_accelerator_t2066 cmap_accelerator_t (hb_face_t *face) : cmap::accelerator_t (face) {}
2067 };
2068
2069 } /* namespace OT */
2070
2071
2072 #endif /* HB_OT_CMAP_TABLE_HH */
2073