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