• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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