QtBase  v6.3.1
hb-ot-cmap-table.hh
Go to the documentation of this file.
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-open-type.hh"
31 #include "hb-set.hh"
32 
33 /*
34  * cmap -- Character to Glyph Index Mapping
35  * https://docs.microsoft.com/en-us/typography/opentype/spec/cmap
36  */
37 #define HB_OT_TAG_cmap HB_TAG('c','m','a','p')
38 
39 namespace OT {
40 
41 
43 {
44  bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
45  {
46  hb_codepoint_t gid = codepoint < 256 ? glyphIdArray[codepoint] : 0;
47  if (!gid)
48  return false;
49  *glyph = gid;
50  return true;
51  }
52 
53  unsigned get_language () const
54  {
55  return language;
56  }
57 
59  {
60  for (unsigned int i = 0; i < 256; i++)
61  if (glyphIdArray[i])
62  out->add (i);
63  }
64 
65  void collect_mapping (hb_set_t *unicodes, /* OUT */
66  hb_map_t *mapping /* OUT */) const
67  {
68  for (unsigned i = 0; i < 256; i++)
69  if (glyphIdArray[i])
70  {
71  hb_codepoint_t glyph = glyphIdArray[i];
72  unicodes->add (i);
73  mapping->set (i, glyph);
74  }
75  }
76 
78  {
79  TRACE_SANITIZE (this);
80  return_trace (c->check_struct (this));
81  }
82 
83  protected:
84  HBUINT16 format; /* Format number is set to 0. */
85  HBUINT16 length; /* Byte length of this subtable. */
86  HBUINT16 language; /* Ignore. */
87  HBUINT8 glyphIdArray[256];/* An array that maps character
88  * code to glyph index values. */
89  public:
90  DEFINE_SIZE_STATIC (6 + 256);
91 };
92 
94 {
95 
96 
97  template<typename Iterator,
98  typename Writer,
99  hb_requires (hb_is_iterator (Iterator))>
100  void to_ranges (Iterator it, Writer& range_writer)
101  {
102  hb_codepoint_t start_cp = 0, prev_run_start_cp = 0, run_start_cp = 0, end_cp = 0, last_gid = 0;
103  int run_length = 0 , delta = 0, prev_delta = 0;
104 
105  enum {
106  FIRST_SUB_RANGE,
107  FOLLOWING_SUB_RANGE,
108  } mode;
109 
110  while (it) {
111  // Start a new range
112  start_cp = (*it).first;
113  prev_run_start_cp = (*it).first;
114  run_start_cp = (*it).first;
115  end_cp = (*it).first;
116  last_gid = (*it).second;
117  run_length = 1;
118  prev_delta = 0;
119 
120  delta = (*it).second - (*it).first;
121  mode = FIRST_SUB_RANGE;
122  it++;
123 
124  while (it) {
125  // Process range
126  hb_codepoint_t next_cp = (*it).first;
127  hb_codepoint_t next_gid = (*it).second;
128  if (next_cp != end_cp + 1) {
129  // Current range is over, stop processing.
130  break;
131  }
132 
133  if (next_gid == last_gid + 1) {
134  // The current run continues.
135  end_cp = next_cp;
136  run_length++;
137  last_gid = next_gid;
138  it++;
139  continue;
140  }
141 
142  // A new run is starting, decide if we want to commit the current run.
143  int split_cost = (mode == FIRST_SUB_RANGE) ? 8 : 16;
144  int run_cost = run_length * 2;
145  if (run_cost >= split_cost) {
146  commit_current_range(start_cp,
147  prev_run_start_cp,
148  run_start_cp,
149  end_cp,
150  delta,
151  prev_delta,
152  split_cost,
153  range_writer);
154  start_cp = next_cp;
155  }
156 
157  // Start the new run
158  mode = FOLLOWING_SUB_RANGE;
159  prev_run_start_cp = run_start_cp;
160  run_start_cp = next_cp;
161  end_cp = next_cp;
162  prev_delta = delta;
163  delta = next_gid - run_start_cp;
164  run_length = 1;
165  last_gid = next_gid;
166  it++;
167  }
168 
169  // Finalize range
170  commit_current_range (start_cp,
171  prev_run_start_cp,
172  run_start_cp,
173  end_cp,
174  delta,
175  prev_delta,
176  8,
177  range_writer);
178  }
179 
180  if (likely (end_cp != 0xFFFF)) {
181  range_writer (0xFFFF, 0xFFFF, 1);
182  }
183  }
184 
185  /*
186  * Writes the current range as either one or two ranges depending on what is most efficient.
187  */
188  template<typename Writer>
190  hb_codepoint_t prev_run_start,
191  hb_codepoint_t run_start,
193  int run_delta,
194  int previous_run_delta,
195  int split_cost,
196  Writer& range_writer) {
197  bool should_split = false;
198  if (start < run_start && run_start < end) {
199  int run_cost = (end - run_start + 1) * 2;
200  if (run_cost >= split_cost) {
201  should_split = true;
202  }
203  }
204 
205  // TODO(grieger): handle case where delta is legitimately 0, mark range offset array instead?
206  if (should_split) {
207  if (start == prev_run_start)
208  range_writer (start, run_start - 1, previous_run_delta);
209  else
210  range_writer (start, run_start - 1, 0);
211  range_writer (run_start, end, run_delta);
212  return;
213  }
214 
215 
216  if (start == run_start) {
217  // Range is only a run
218  range_writer (start, end, run_delta);
219  return;
220  }
221 
222  // Write only a single non-run range.
223  range_writer (start, end, 0);
224  }
225 
226  template<typename Iterator,
227  hb_requires (hb_is_iterator (Iterator))>
228  unsigned serialize_find_segcount (Iterator it) {
229  struct Counter {
230  unsigned segcount = 0;
231 
234  int delta) {
235  segcount++;
236  }
237  } counter;
238 
239  to_ranges (+it, counter);
240  return counter.segcount;
241  }
242 
243 
244  template<typename Iterator,
245  hb_requires (hb_is_iterator (Iterator))>
247  Iterator it,
248  int segcount)
249  {
250  struct Writer {
251  hb_serialize_context_t *serializer_;
252  HBUINT16* end_code_;
253  HBUINT16* start_code_;
254  HBINT16* id_delta_;
255  int index_;
256 
257  Writer(hb_serialize_context_t *serializer)
258  : serializer_(serializer),
259  end_code_(nullptr),
260  start_code_(nullptr),
261  id_delta_(nullptr),
262  index_ (0) {}
265  int delta) {
266  start_code_[index_] = start;
267  end_code_[index_] = end;
268  id_delta_[index_] = delta;
269  index_++;
270  }
271  } writer(c);
272 
273  writer.end_code_ = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount);
274  c->allocate_size<HBUINT16> (2); // padding
275  writer.start_code_ = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount);
276  writer.id_delta_ = c->allocate_size<HBINT16> (HBINT16::static_size * segcount);
277 
278  if (unlikely (!writer.end_code_ || !writer.start_code_ || !writer.id_delta_)) return false;
279 
280  to_ranges (+it, writer);
281  return true;
282  }
283 
284  template<typename Iterator,
285  hb_requires (hb_is_iterator (Iterator))>
287  Iterator it,
288  HBUINT16 *endCode,
289  HBUINT16 *startCode,
290  HBINT16 *idDelta,
291  unsigned segcount)
292  {
294  + it | hb_sink (cp_to_gid);
295 
296  HBUINT16 *idRangeOffset = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount);
297  if (unlikely (!c->check_success (idRangeOffset))) return nullptr;
298  if (unlikely ((char *)idRangeOffset - (char *)idDelta != (int) segcount * (int) HBINT16::static_size)) return nullptr;
299 
300  for (unsigned i : + hb_range (segcount)
301  | hb_filter ([&] (const unsigned _) { return idDelta[_] == 0; }))
302  {
303  idRangeOffset[i] = 2 * (c->start_embed<HBUINT16> () - idRangeOffset - i);
304  for (hb_codepoint_t cp = startCode[i]; cp <= endCode[i]; cp++)
305  {
306  HBUINT16 gid;
307  gid = cp_to_gid[cp];
308  c->copy<HBUINT16> (gid);
309  }
310  }
311 
312  return idRangeOffset;
313  }
314 
315  template<typename Iterator,
316  hb_requires (hb_is_iterator (Iterator))>
318  Iterator it)
319  {
320  auto format4_iter =
321  + it
322  | hb_filter ([&] (const hb_pair_t<hb_codepoint_t, hb_codepoint_t> _)
323  { return _.first <= 0xFFFF; })
324  ;
325 
326  if (format4_iter.len () == 0) return;
327 
328  unsigned table_initpos = c->length ();
329  if (unlikely (!c->extend_min (this))) return;
330  this->format = 4;
331 
332  //serialize endCode[], startCode[], idDelta[]
333  HBUINT16* endCode = c->start_embed<HBUINT16> ();
334  unsigned segcount = serialize_find_segcount (format4_iter);
335  if (unlikely (!serialize_start_end_delta_arrays (c, format4_iter, segcount)))
336  return;
337 
338  HBUINT16 *startCode = endCode + segcount + 1;
339  HBINT16 *idDelta = ((HBINT16*)startCode) + segcount;
340 
341  HBUINT16 *idRangeOffset = serialize_rangeoffset_glyid (c, format4_iter, endCode, startCode, idDelta, segcount);
342  if (unlikely (!c->check_success (idRangeOffset))) return;
343 
344  this->length = c->length () - table_initpos;
345  if ((long long) this->length != (long long) c->length () - table_initpos)
346  {
347  // Length overflowed. Discard the current object before setting the error condition, otherwise
348  // discard is a noop which prevents the higher level code from reverting the serializer to the
349  // pre-error state in cmap4 overflow handling code.
350  c->pop_discard ();
352  return;
353  }
354 
355  this->segCountX2 = segcount * 2;
356  this->entrySelector = hb_max (1u, hb_bit_storage (segcount)) - 1;
357  this->searchRange = 2 * (1u << this->entrySelector);
358  this->rangeShift = segcount * 2 > this->searchRange
359  ? 2 * segcount - this->searchRange
360  : 0;
361  }
362 
363  unsigned get_language () const
364  {
365  return language;
366  }
367 
369  {
371  accelerator_t (const CmapSubtableFormat4 *subtable) { init (subtable); }
372 
373  void init (const CmapSubtableFormat4 *subtable)
374  {
375  segCount = subtable->segCountX2 / 2;
376  endCount = subtable->values.arrayZ;
377  startCount = endCount + segCount + 1;
381  glyphIdArrayLength = (subtable->length - 16 - 8 * segCount) / 2;
382  }
383 
384  bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
385  {
386  struct CustomRange
387  {
388  int cmp (hb_codepoint_t k,
389  unsigned distance) const
390  {
391  if (k > last) return +1;
392  if (k < (&last)[distance]) return -1;
393  return 0;
394  }
395  HBUINT16 last;
396  };
397 
398  const HBUINT16 *found = hb_bsearch (codepoint,
399  this->endCount,
400  this->segCount,
401  2,
402  _hb_cmp_method<hb_codepoint_t, CustomRange, unsigned>,
403  this->segCount + 1);
404  if (!found)
405  return false;
406  unsigned int i = found - endCount;
407 
408  hb_codepoint_t gid;
409  unsigned int rangeOffset = this->idRangeOffset[i];
410  if (rangeOffset == 0)
411  gid = codepoint + this->idDelta[i];
412  else
413  {
414  /* Somebody has been smoking... */
415  unsigned int index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount;
416  if (unlikely (index >= this->glyphIdArrayLength))
417  return false;
418  gid = this->glyphIdArray[index];
419  if (unlikely (!gid))
420  return false;
421  gid += this->idDelta[i];
422  }
423  gid &= 0xFFFFu;
424  if (!gid)
425  return false;
426  *glyph = gid;
427  return true;
428  }
429 
430  HB_INTERNAL static bool get_glyph_func (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph)
431  { return ((const accelerator_t *) obj)->get_glyph (codepoint, glyph); }
432 
434  {
435  unsigned int count = this->segCount;
436  if (count && this->startCount[count - 1] == 0xFFFFu)
437  count--; /* Skip sentinel segment. */
438  for (unsigned int i = 0; i < count; i++)
439  {
440  hb_codepoint_t start = this->startCount[i];
441  hb_codepoint_t end = this->endCount[i];
442  unsigned int rangeOffset = this->idRangeOffset[i];
443  if (rangeOffset == 0)
444  {
445  for (hb_codepoint_t codepoint = start; codepoint <= end; codepoint++)
446  {
447  hb_codepoint_t gid = (codepoint + this->idDelta[i]) & 0xFFFFu;
448  if (unlikely (!gid))
449  continue;
450  out->add (codepoint);
451  }
452  }
453  else
454  {
455  for (hb_codepoint_t codepoint = start; codepoint <= end; codepoint++)
456  {
457  unsigned int index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount;
458  if (unlikely (index >= this->glyphIdArrayLength))
459  break;
460  hb_codepoint_t gid = this->glyphIdArray[index];
461  if (unlikely (!gid))
462  continue;
463  out->add (codepoint);
464  }
465  }
466  }
467  }
468 
469  void collect_mapping (hb_set_t *unicodes, /* OUT */
470  hb_map_t *mapping /* OUT */) const
471  {
472  unsigned count = this->segCount;
473  if (count && this->startCount[count - 1] == 0xFFFFu)
474  count--; /* Skip sentinel segment. */
475  for (unsigned i = 0; i < count; i++)
476  {
477  hb_codepoint_t start = this->startCount[i];
478  hb_codepoint_t end = this->endCount[i];
479  unsigned rangeOffset = this->idRangeOffset[i];
480  if (rangeOffset == 0)
481  {
482  for (hb_codepoint_t codepoint = start; codepoint <= end; codepoint++)
483  {
484  hb_codepoint_t gid = (codepoint + this->idDelta[i]) & 0xFFFFu;
485  if (unlikely (!gid))
486  continue;
487  unicodes->add (codepoint);
488  mapping->set (codepoint, gid);
489  }
490  }
491  else
492  {
493  for (hb_codepoint_t codepoint = start; codepoint <= end; codepoint++)
494  {
495  unsigned index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount;
496  if (unlikely (index >= this->glyphIdArrayLength))
497  break;
498  hb_codepoint_t gid = this->glyphIdArray[index];
499  if (unlikely (!gid))
500  continue;
501  unicodes->add (codepoint);
502  mapping->set (codepoint, gid);
503  }
504  }
505  }
506  }
507 
513  unsigned int segCount;
514  unsigned int glyphIdArrayLength;
515  };
516 
517  bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
518  {
519  accelerator_t accel (this);
520  return accel.get_glyph_func (&accel, codepoint, glyph);
521  }
523  {
524  accelerator_t accel (this);
525  accel.collect_unicodes (out);
526  }
527 
528  void collect_mapping (hb_set_t *unicodes, /* OUT */
529  hb_map_t *mapping /* OUT */) const
530  {
531  accelerator_t accel (this);
532  accel.collect_mapping (unicodes, mapping);
533  }
534 
536  {
537  TRACE_SANITIZE (this);
538  if (unlikely (!c->check_struct (this)))
539  return_trace (false);
540 
541  if (unlikely (!c->check_range (this, length)))
542  {
543  /* Some broken fonts have too long of a "length" value.
544  * If that is the case, just change the value to truncate
545  * the subtable at the end of the blob. */
546  uint16_t new_length = (uint16_t) hb_min ((uintptr_t) 65535,
547  (uintptr_t) (c->end -
548  (char *) this));
549  if (!c->try_set (&length, new_length))
550  return_trace (false);
551  }
552 
553  return_trace (16 + 4 * (unsigned int) segCountX2 <= length);
554  }
555 
556 
557 
558  protected:
559  HBUINT16 format; /* Format number is set to 4. */
560  HBUINT16 length; /* This is the length in bytes of the
561  * subtable. */
562  HBUINT16 language; /* Ignore. */
563  HBUINT16 segCountX2; /* 2 x segCount. */
564  HBUINT16 searchRange; /* 2 * (2**floor(log2(segCount))) */
565  HBUINT16 entrySelector; /* log2(searchRange/2) */
566  HBUINT16 rangeShift; /* 2 x segCount - searchRange */
567 
570 #if 0
571  HBUINT16 endCount[segCount]; /* End characterCode for each segment,
572  * last=0xFFFFu. */
573  HBUINT16 reservedPad; /* Set to 0. */
574  HBUINT16 startCount[segCount]; /* Start character code for each segment. */
575  HBINT16 idDelta[segCount]; /* Delta for all character codes in segment. */
576  HBUINT16 idRangeOffset[segCount];/* Offsets into glyphIdArray or 0 */
578  glyphIdArray; /* Glyph index array (arbitrary length) */
579 #endif
580 
581  public:
583 };
584 
586 {
587  friend struct CmapSubtableFormat12;
588  friend struct CmapSubtableFormat13;
589  template<typename U>
591  friend struct cmap;
592 
593  int cmp (hb_codepoint_t codepoint) const
594  {
595  if (codepoint < startCharCode) return -1;
596  if (codepoint > endCharCode) return +1;
597  return 0;
598  }
599 
601  {
602  TRACE_SANITIZE (this);
603  return_trace (c->check_struct (this));
604  }
605 
606  private:
607  HBUINT32 startCharCode; /* First character code in this group. */
608  HBUINT32 endCharCode; /* Last character code in this group. */
609  HBUINT32 glyphID; /* Glyph index; interpretation depends on
610  * subtable format. */
611  public:
613 };
615 
616 template <typename UINT>
618 {
619  bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
620  {
621  /* Rely on our implicit array bound-checking. */
622  hb_codepoint_t gid = glyphIdArray[codepoint - startCharCode];
623  if (!gid)
624  return false;
625  *glyph = gid;
626  return true;
627  }
628 
629  unsigned get_language () const
630  {
631  return language;
632  }
633 
635  {
637  unsigned int count = glyphIdArray.len;
638  for (unsigned int i = 0; i < count; i++)
639  if (glyphIdArray[i])
640  out->add (start + i);
641  }
642 
643  void collect_mapping (hb_set_t *unicodes, /* OUT */
644  hb_map_t *mapping /* OUT */) const
645  {
646  hb_codepoint_t start_cp = startCharCode;
647  unsigned count = glyphIdArray.len;
648  for (unsigned i = 0; i < count; i++)
649  if (glyphIdArray[i])
650  {
651  hb_codepoint_t unicode = start_cp + i;
652  hb_codepoint_t glyphid = glyphIdArray[i];
653  unicodes->add (unicode);
654  mapping->set (unicode, glyphid);
655  }
656  }
657 
659  {
660  TRACE_SANITIZE (this);
661  return_trace (c->check_struct (this) && glyphIdArray.sanitize (c));
662  }
663 
664  protected:
665  UINT formatReserved; /* Subtable format and (maybe) padding. */
666  UINT length; /* Byte length of this subtable. */
667  UINT language; /* Ignore. */
668  UINT startCharCode; /* First character code covered. */
670  glyphIdArray; /* Array of glyph index values for character
671  * codes in the range. */
672  public:
673  DEFINE_SIZE_ARRAY (5 * sizeof (UINT), glyphIdArray);
674 };
675 
678 
679 template <typename T>
681 {
682  friend struct cmap;
683 
684  bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
685  {
686  hb_codepoint_t gid = T::group_get_glyph (groups.bsearch (codepoint), codepoint);
687  if (!gid)
688  return false;
689  *glyph = gid;
690  return true;
691  }
692 
693  unsigned get_language () const
694  {
695  return language;
696  }
697 
698  void collect_unicodes (hb_set_t *out, unsigned int num_glyphs) const
699  {
700  for (unsigned int i = 0; i < this->groups.len; i++)
701  {
702  hb_codepoint_t start = this->groups[i].startCharCode;
703  hb_codepoint_t end = hb_min ((hb_codepoint_t) this->groups[i].endCharCode,
705  hb_codepoint_t gid = this->groups[i].glyphID;
706  if (!gid)
707  {
708  /* Intention is: if (hb_is_same (T, CmapSubtableFormat13)) continue; */
709  if (! T::group_get_glyph (this->groups[i], end)) continue;
710  start++;
711  gid++;
712  }
713  if (unlikely ((unsigned int) gid >= num_glyphs)) continue;
714  if (unlikely ((unsigned int) (gid + end - start) >= num_glyphs))
715  end = start + (hb_codepoint_t) num_glyphs - gid;
716 
717  out->add_range (start, hb_min (end, 0x10FFFFu));
718  }
719  }
720 
721  void collect_mapping (hb_set_t *unicodes, /* OUT */
722  hb_map_t *mapping, /* OUT */
723  unsigned num_glyphs) const
724  {
725  for (unsigned i = 0; i < this->groups.len; i++)
726  {
727  hb_codepoint_t start = this->groups[i].startCharCode;
728  hb_codepoint_t end = hb_min ((hb_codepoint_t) this->groups[i].endCharCode,
730  hb_codepoint_t gid = this->groups[i].glyphID;
731  if (!gid)
732  {
733  /* Intention is: if (hb_is_same (T, CmapSubtableFormat13)) continue; */
734  if (! T::group_get_glyph (this->groups[i], end)) continue;
735  start++;
736  gid++;
737  }
738  if (unlikely ((unsigned int) gid >= num_glyphs)) continue;
739  if (unlikely ((unsigned int) (gid + end - start) >= num_glyphs))
740  end = start + (hb_codepoint_t) num_glyphs - gid;
741 
742  for (unsigned cp = start; cp <= end; cp++)
743  {
744  unicodes->add (cp);
745  mapping->set (cp, gid);
746  gid++;
747  }
748  }
749  }
750 
752  {
753  TRACE_SANITIZE (this);
754  return_trace (c->check_struct (this) && groups.sanitize (c));
755  }
756 
757  protected:
758  HBUINT16 format; /* Subtable format; set to 12. */
759  HBUINT16 reserved; /* Reserved; set to 0. */
760  HBUINT32 length; /* Byte length of this subtable. */
761  HBUINT32 language; /* Ignore. */
763  groups; /* Groupings. */
764  public:
766 };
767 
768 struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
769 {
772  { return likely (group.startCharCode <= group.endCharCode) ?
773  group.glyphID + (u - group.startCharCode) : 0; }
774 
775 
776  template<typename Iterator,
777  hb_requires (hb_is_iterator (Iterator))>
779  Iterator it)
780  {
781  if (it.len () == 0) return;
782  unsigned table_initpos = c->length ();
783  if (unlikely (!c->extend_min (this))) return;
784 
785  hb_codepoint_t startCharCode = 0xFFFF, endCharCode = 0xFFFF;
786  hb_codepoint_t glyphID = 0;
787 
788  for (const auto& _ : +it)
789  {
790  if (startCharCode == 0xFFFF)
791  {
792  startCharCode = _.first;
793  endCharCode = _.first;
794  glyphID = _.second;
795  }
796  else if (!_is_gid_consecutive (endCharCode, startCharCode, glyphID, _.first, _.second))
797  {
798  CmapSubtableLongGroup grouprecord;
799  grouprecord.startCharCode = startCharCode;
800  grouprecord.endCharCode = endCharCode;
801  grouprecord.glyphID = glyphID;
802  c->copy<CmapSubtableLongGroup> (grouprecord);
803 
804  startCharCode = _.first;
805  endCharCode = _.first;
806  glyphID = _.second;
807  }
808  else
809  endCharCode = _.first;
810  }
811 
813  record.startCharCode = startCharCode;
814  record.endCharCode = endCharCode;
815  record.glyphID = glyphID;
816  c->copy<CmapSubtableLongGroup> (record);
817 
818  this->format = 12;
819  this->reserved = 0;
820  this->length = c->length () - table_initpos;
821  this->groups.len = (this->length - min_size)/CmapSubtableLongGroup::static_size;
822  }
823 
825  { return 16 + 12 * groups_data.length; }
826 
827  private:
828  static bool _is_gid_consecutive (hb_codepoint_t endCharCode,
829  hb_codepoint_t startCharCode,
830  hb_codepoint_t glyphID,
831  hb_codepoint_t cp,
832  hb_codepoint_t new_gid)
833  {
834  return (cp - 1 == endCharCode) &&
835  new_gid == glyphID + (cp - startCharCode);
836  }
837 
838 };
839 
840 struct CmapSubtableFormat13 : CmapSubtableLongSegmented<CmapSubtableFormat13>
841 {
844  { return group.glyphID; }
845 };
846 
847 typedef enum
848 {
853 
855 {
856  int cmp (const hb_codepoint_t &codepoint) const
857  {
858  if (codepoint < startUnicodeValue) return -1;
859  if (codepoint > startUnicodeValue + additionalCount) return +1;
860  return 0;
861  }
862 
864  {
865  TRACE_SANITIZE (this);
866  return_trace (c->check_struct (this));
867  }
868 
869  HBUINT24 startUnicodeValue; /* First value in this range. */
870  HBUINT8 additionalCount; /* Number of additional values in this
871  * range. */
872  public:
874 };
875 
876 struct DefaultUVS : SortedArray32Of<UnicodeValueRange>
877 {
879  {
880  unsigned int count = len;
881  for (unsigned int i = 0; i < count; i++)
882  {
883  hb_codepoint_t first = arrayZ[i].startUnicodeValue;
884  hb_codepoint_t last = hb_min ((hb_codepoint_t) (first + arrayZ[i].additionalCount),
886  out->add_range (first, hb_min (last, 0x10FFFFu));
887  }
888  }
889 
891  const hb_set_t *unicodes) const
892  {
893  DefaultUVS *out = c->start_embed<DefaultUVS> ();
894  if (unlikely (!out)) return nullptr;
895  auto snap = c->snapshot ();
896 
897  HBUINT32 len;
898  len = 0;
899  if (unlikely (!c->copy<HBUINT32> (len))) return nullptr;
900  unsigned init_len = c->length ();
901 
903  int count = -1;
904 
905  for (const UnicodeValueRange& _ : as_array ())
906  {
907  for (const unsigned addcnt : hb_range ((unsigned) _.additionalCount + 1))
908  {
909  unsigned curEntry = (unsigned) _.startUnicodeValue + addcnt;
910  if (!unicodes->has (curEntry)) continue;
911  count += 1;
912  if (lastCode == HB_MAP_VALUE_INVALID)
913  lastCode = curEntry;
914  else if (lastCode + count != curEntry)
915  {
916  UnicodeValueRange rec;
917  rec.startUnicodeValue = lastCode;
918  rec.additionalCount = count - 1;
919  c->copy<UnicodeValueRange> (rec);
920 
921  lastCode = curEntry;
922  count = 0;
923  }
924  }
925  }
926 
927  if (lastCode != HB_MAP_VALUE_INVALID)
928  {
929  UnicodeValueRange rec;
930  rec.startUnicodeValue = lastCode;
931  rec.additionalCount = count;
932  c->copy<UnicodeValueRange> (rec);
933  }
934 
935  if (c->length () - init_len == 0)
936  {
937  c->revert (snap);
938  return nullptr;
939  }
940  else
941  {
942  if (unlikely (!c->check_assign (out->len,
943  (c->length () - init_len) / UnicodeValueRange::static_size,
944  HB_SERIALIZE_ERROR_INT_OVERFLOW))) return nullptr;
945  return out;
946  }
947  }
948 
949  public:
950  DEFINE_SIZE_ARRAY (4, *this);
951 };
952 
954 {
955  int cmp (const hb_codepoint_t &codepoint) const
956  { return unicodeValue.cmp (codepoint); }
957 
959  {
960  TRACE_SANITIZE (this);
961  return_trace (c->check_struct (this));
962  }
963 
964  HBUINT24 unicodeValue; /* Base Unicode value of the UVS */
965  HBGlyphID16 glyphID; /* Glyph ID of the UVS */
966  public:
968 };
969 
970 struct NonDefaultUVS : SortedArray32Of<UVSMapping>
971 {
973  {
974  for (const auto& a : as_array ())
975  out->add (a.unicodeValue);
976  }
977 
978  void collect_mapping (hb_set_t *unicodes, /* OUT */
979  hb_map_t *mapping /* OUT */) const
980  {
981  for (const auto& a : as_array ())
982  {
983  hb_codepoint_t unicode = a.unicodeValue;
984  hb_codepoint_t glyphid = a.glyphID;
985  unicodes->add (unicode);
986  mapping->set (unicode, glyphid);
987  }
988  }
989 
990  void closure_glyphs (const hb_set_t *unicodes,
991  hb_set_t *glyphset) const
992  {
993  + as_array ()
994  | hb_filter (unicodes, &UVSMapping::unicodeValue)
996  | hb_sink (glyphset)
997  ;
998  }
999 
1001  const hb_set_t *unicodes,
1002  const hb_set_t *glyphs_requested,
1003  const hb_map_t *glyph_map) const
1004  {
1005  NonDefaultUVS *out = c->start_embed<NonDefaultUVS> ();
1006  if (unlikely (!out)) return nullptr;
1007 
1008  auto it =
1009  + as_array ()
1010  | hb_filter ([&] (const UVSMapping& _)
1011  {
1012  return unicodes->has (_.unicodeValue) || glyphs_requested->has (_.glyphID);
1013  })
1014  ;
1015 
1016  if (!it) return nullptr;
1017 
1018  HBUINT32 len;
1019  len = it.len ();
1020  if (unlikely (!c->copy<HBUINT32> (len))) return nullptr;
1021 
1022  for (const UVSMapping& _ : it)
1023  {
1025  mapping.unicodeValue = _.unicodeValue;
1026  mapping.glyphID = glyph_map->get (_.glyphID);
1027  c->copy<UVSMapping> (mapping);
1028  }
1029 
1030  return out;
1031  }
1032 
1033  public:
1034  DEFINE_SIZE_ARRAY (4, *this);
1035 };
1036 
1038 {
1040  hb_codepoint_t *glyph,
1041  const void *base) const
1042  {
1043  if ((base+defaultUVS).bfind (codepoint))
1045  const UVSMapping &nonDefault = (base+nonDefaultUVS).bsearch (codepoint);
1046  if (nonDefault.glyphID)
1047  {
1048  *glyph = nonDefault.glyphID;
1049  return GLYPH_VARIANT_FOUND;
1050  }
1051  return GLYPH_VARIANT_NOT_FOUND;
1052  }
1053 
1055  {
1056  *this = other;
1057  }
1058 
1060  {
1061  varSelector = other.varSelector;
1062  HBUINT32 offset = other.defaultUVS;
1063  defaultUVS = offset;
1064  offset = other.nonDefaultUVS;
1066  }
1067 
1068  void collect_unicodes (hb_set_t *out, const void *base) const
1069  {
1072  }
1073 
1074  void collect_mapping (const void *base,
1075  hb_set_t *unicodes, /* OUT */
1076  hb_map_t *mapping /* OUT */) const
1077  {
1078  (base+defaultUVS).collect_unicodes (unicodes);
1079  (base+nonDefaultUVS).collect_mapping (unicodes, mapping);
1080  }
1081 
1082  int cmp (const hb_codepoint_t &variation_selector) const
1083  { return varSelector.cmp (variation_selector); }
1084 
1085  bool sanitize (hb_sanitize_context_t *c, const void *base) const
1086  {
1087  TRACE_SANITIZE (this);
1088  return_trace (c->check_struct (this) &&
1089  defaultUVS.sanitize (c, base) &&
1090  nonDefaultUVS.sanitize (c, base));
1091  }
1092 
1095  const hb_set_t *unicodes,
1096  const hb_set_t *glyphs_requested,
1097  const hb_map_t *glyph_map,
1098  const void *base) const
1099  {
1100  auto snap = c->snapshot ();
1101  auto *out = c->embed<VariationSelectorRecord> (*this);
1102  if (unlikely (!out)) return hb_pair (0, 0);
1103 
1104  out->defaultUVS = 0;
1105  out->nonDefaultUVS = 0;
1106 
1107  unsigned non_default_uvs_objidx = 0;
1108  if (nonDefaultUVS != 0)
1109  {
1110  c->push ();
1111  if (c->copy (base+nonDefaultUVS, unicodes, glyphs_requested, glyph_map))
1112  non_default_uvs_objidx = c->pop_pack ();
1113  else c->pop_discard ();
1114  }
1115 
1116  unsigned default_uvs_objidx = 0;
1117  if (defaultUVS != 0)
1118  {
1119  c->push ();
1120  if (c->copy (base+defaultUVS, unicodes))
1121  default_uvs_objidx = c->pop_pack ();
1122  else c->pop_discard ();
1123  }
1124 
1125 
1126  if (!default_uvs_objidx && !non_default_uvs_objidx)
1127  c->revert (snap);
1128 
1129  return hb_pair (default_uvs_objidx, non_default_uvs_objidx);
1130  }
1131 
1132  HBUINT24 varSelector; /* Variation selector. */
1134  defaultUVS; /* Offset to Default UVS Table. May be 0. */
1136  nonDefaultUVS; /* Offset to Non-Default UVS Table. May be 0. */
1137  public:
1139 };
1140 
1142 {
1144  hb_codepoint_t variation_selector,
1145  hb_codepoint_t *glyph) const
1146  { return record.bsearch (variation_selector).get_glyph (codepoint, glyph, this); }
1147 
1149  {
1150  for (const auto& a : record.as_array ())
1151  out->add (a.varSelector);
1152  }
1153  void collect_variation_unicodes (hb_codepoint_t variation_selector,
1154  hb_set_t *out) const
1155  { record.bsearch (variation_selector).collect_unicodes (out, this); }
1156 
1158  const hb_set_t *unicodes,
1159  const hb_set_t *glyphs_requested,
1160  const hb_map_t *glyph_map,
1161  const void *base)
1162  {
1163  auto snap = c->snapshot ();
1164  unsigned table_initpos = c->length ();
1165  const char* init_tail = c->tail;
1166 
1167  if (unlikely (!c->extend_min (this))) return;
1168  this->format = 14;
1169 
1170  auto src_tbl = reinterpret_cast<const CmapSubtableFormat14*> (base);
1171 
1172  /*
1173  * Some versions of OTS require that offsets are in order. Due to the use
1174  * of push()/pop_pack() serializing the variation records in order results
1175  * in the offsets being in reverse order (first record has the largest
1176  * offset). While this is perfectly valid, it will cause some versions of
1177  * OTS to consider this table bad.
1178  *
1179  * So to prevent this issue we serialize the variation records in reverse
1180  * order, so that the offsets are ordered from small to large. Since
1181  * variation records are supposed to be in increasing order of varSelector
1182  * we then have to reverse the order of the written variation selector
1183  * records after everything is finalized.
1184  */
1186  for (int i = src_tbl->record.len - 1; i >= 0; i--)
1187  {
1188  hb_pair_t<unsigned, unsigned> result = src_tbl->record[i].copy (c, unicodes, glyphs_requested, glyph_map, base);
1189  if (result.first || result.second)
1190  obj_indices.push (result);
1191  }
1192 
1193  if (c->length () - table_initpos == CmapSubtableFormat14::min_size)
1194  {
1195  c->revert (snap);
1196  return;
1197  }
1198 
1199  if (unlikely (!c->check_success (!obj_indices.in_error ())))
1200  return;
1201 
1202  int tail_len = init_tail - c->tail;
1203  c->check_assign (this->length, c->length () - table_initpos + tail_len,
1205  c->check_assign (this->record.len,
1206  (c->length () - table_initpos - CmapSubtableFormat14::min_size) /
1207  VariationSelectorRecord::static_size,
1209 
1210  /* Correct the incorrect write order by reversing the order of the variation
1211  records array. */
1213 
1214  /* Now that records are in the right order, we can set up the offsets. */
1215  _add_links_to_variation_records (c, obj_indices);
1216  }
1217 
1219  {
1220  record.as_array ().reverse ();
1221  }
1222 
1224  const hb_vector_t<hb_pair_t<unsigned, unsigned>>& obj_indices)
1225  {
1226  for (unsigned i = 0; i < obj_indices.length; i++)
1227  {
1228  /*
1229  * Since the record array has been reversed (see comments in copy())
1230  * but obj_indices has not been, the indices at obj_indices[i]
1231  * are for the variation record at record[j].
1232  */
1233  int j = obj_indices.length - 1 - i;
1234  c->add_link (record[j].defaultUVS, obj_indices[i].first);
1235  c->add_link (record[j].nonDefaultUVS, obj_indices[i].second);
1236  }
1237  }
1238 
1239  void closure_glyphs (const hb_set_t *unicodes,
1240  hb_set_t *glyphset) const
1241  {
1242  + hb_iter (record)
1243  | hb_filter (hb_bool, &VariationSelectorRecord::nonDefaultUVS)
1245  | hb_map (hb_add (this))
1246  | hb_apply ([=] (const NonDefaultUVS& _) { _.closure_glyphs (unicodes, glyphset); })
1247  ;
1248  }
1249 
1251  {
1252  for (const VariationSelectorRecord& _ : record)
1253  _.collect_unicodes (out, this);
1254  }
1255 
1256  void collect_mapping (hb_set_t *unicodes, /* OUT */
1257  hb_map_t *mapping /* OUT */) const
1258  {
1259  for (const VariationSelectorRecord& _ : record)
1260  _.collect_mapping (this, unicodes, mapping);
1261  }
1262 
1264  {
1265  TRACE_SANITIZE (this);
1266  return_trace (c->check_struct (this) &&
1267  record.sanitize (c, this));
1268  }
1269 
1270  protected:
1271  HBUINT16 format; /* Format number is set to 14. */
1272  HBUINT32 length; /* Byte length of this subtable. */
1274  record; /* Variation selector records; sorted
1275  * in increasing order of `varSelector'. */
1276  public:
1278 };
1279 
1281 {
1282  /* Note: We intentionally do NOT implement subtable formats 2 and 8. */
1283 
1284  bool get_glyph (hb_codepoint_t codepoint,
1285  hb_codepoint_t *glyph) const
1286  {
1287  switch (u.format) {
1288  case 0: return u.format0 .get_glyph (codepoint, glyph);
1289  case 4: return u.format4 .get_glyph (codepoint, glyph);
1290  case 6: return u.format6 .get_glyph (codepoint, glyph);
1291  case 10: return u.format10.get_glyph (codepoint, glyph);
1292  case 12: return u.format12.get_glyph (codepoint, glyph);
1293  case 13: return u.format13.get_glyph (codepoint, glyph);
1294  case 14:
1295  default: return false;
1296  }
1297  }
1298  void collect_unicodes (hb_set_t *out, unsigned int num_glyphs = UINT_MAX) const
1299  {
1300  switch (u.format) {
1301  case 0: u.format0 .collect_unicodes (out); return;
1302  case 4: u.format4 .collect_unicodes (out); return;
1303  case 6: u.format6 .collect_unicodes (out); return;
1304  case 10: u.format10.collect_unicodes (out); return;
1305  case 12: u.format12.collect_unicodes (out, num_glyphs); return;
1306  case 13: u.format13.collect_unicodes (out, num_glyphs); return;
1307  case 14:
1308  default: return;
1309  }
1310  }
1311 
1312  void collect_mapping (hb_set_t *unicodes, /* OUT */
1313  hb_map_t *mapping, /* OUT */
1314  unsigned num_glyphs = UINT_MAX) const
1315  {
1316  switch (u.format) {
1317  case 0: u.format0 .collect_mapping (unicodes, mapping); return;
1318  case 4: u.format4 .collect_mapping (unicodes, mapping); return;
1319  case 6: u.format6 .collect_mapping (unicodes, mapping); return;
1320  case 10: u.format10.collect_mapping (unicodes, mapping); return;
1321  case 12: u.format12.collect_mapping (unicodes, mapping, num_glyphs); return;
1322  case 13: u.format13.collect_mapping (unicodes, mapping, num_glyphs); return;
1323  case 14:
1324  default: return;
1325  }
1326  }
1327 
1328  unsigned get_language () const
1329  {
1330  switch (u.format) {
1331  case 0: return u.format0 .get_language ();
1332  case 4: return u.format4 .get_language ();
1333  case 6: return u.format6 .get_language ();
1334  case 10: return u.format10.get_language ();
1335  case 12: return u.format12.get_language ();
1336  case 13: return u.format13.get_language ();
1337  case 14:
1338  default: return 0;
1339  }
1340  }
1341 
1342  template<typename Iterator,
1343  hb_requires (hb_is_iterator (Iterator))>
1345  Iterator it,
1346  unsigned format,
1347  const hb_subset_plan_t *plan,
1348  const void *base)
1349  {
1350  switch (format) {
1351  case 4: return u.format4.serialize (c, it);
1352  case 12: return u.format12.serialize (c, it);
1353  case 14: return u.format14.serialize (c, plan->unicodes, plan->glyphs_requested, plan->glyph_map, base);
1354  default: return;
1355  }
1356  }
1357 
1359  {
1360  TRACE_SANITIZE (this);
1361  if (!u.format.sanitize (c)) return_trace (false);
1362  switch (u.format) {
1363  case 0: return_trace (u.format0 .sanitize (c));
1364  case 4: return_trace (u.format4 .sanitize (c));
1365  case 6: return_trace (u.format6 .sanitize (c));
1366  case 10: return_trace (u.format10.sanitize (c));
1367  case 12: return_trace (u.format12.sanitize (c));
1368  case 13: return_trace (u.format13.sanitize (c));
1369  case 14: return_trace (u.format14.sanitize (c));
1370  default:return_trace (true);
1371  }
1372  }
1373 
1374  public:
1375  union {
1376  HBUINT16 format; /* Format identifier */
1384  } u;
1385  public:
1387 };
1388 
1389 
1391 {
1392  int cmp (const EncodingRecord &other) const
1393  {
1394  int ret;
1395  ret = platformID.cmp (other.platformID);
1396  if (ret) return ret;
1397  ret = encodingID.cmp (other.encodingID);
1398  if (ret) return ret;
1399  return 0;
1400  }
1401 
1402  bool sanitize (hb_sanitize_context_t *c, const void *base) const
1403  {
1404  TRACE_SANITIZE (this);
1405  return_trace (c->check_struct (this) &&
1406  subtable.sanitize (c, base));
1407  }
1408 
1409  template<typename Iterator,
1410  hb_requires (hb_is_iterator (Iterator))>
1412  Iterator it,
1413  unsigned format,
1414  const void *base,
1415  const hb_subset_plan_t *plan,
1416  /* INOUT */ unsigned *objidx) const
1417  {
1418  TRACE_SERIALIZE (this);
1419  auto snap = c->snapshot ();
1420  auto *out = c->embed (this);
1421  if (unlikely (!out)) return_trace (nullptr);
1422  out->subtable = 0;
1423 
1424  if (*objidx == 0)
1425  {
1426  CmapSubtable *cmapsubtable = c->push<CmapSubtable> ();
1427  unsigned origin_length = c->length ();
1428  cmapsubtable->serialize (c, it, format, plan, &(base+subtable));
1429  if (c->length () - origin_length > 0) *objidx = c->pop_pack ();
1430  else c->pop_discard ();
1431  }
1432 
1433  if (*objidx == 0)
1434  {
1435  c->revert (snap);
1436  return_trace (nullptr);
1437  }
1438 
1439  c->add_link (out->subtable, *objidx);
1440  return_trace (out);
1441  }
1442 
1443  HBUINT16 platformID; /* Platform ID. */
1444  HBUINT16 encodingID; /* Platform-specific encoding ID. */
1446  subtable; /* Byte offset from beginning of table to the subtable for this encoding. */
1447  public:
1449 };
1450 
1451 struct cmap
1452 {
1453  static constexpr hb_tag_t tableTag = HB_OT_TAG_cmap;
1454 
1455  template<typename Iterator, typename EncodingRecIter,
1456  hb_requires (hb_is_iterator (EncodingRecIter))>
1458  Iterator it,
1459  EncodingRecIter encodingrec_iter,
1460  const void *base,
1461  const hb_subset_plan_t *plan,
1462  bool drop_format_4 = false)
1463  {
1464  if (unlikely (!c->extend_min ((*this)))) return false;
1465  this->version = 0;
1466 
1467  unsigned format4objidx = 0, format12objidx = 0, format14objidx = 0;
1468  auto snap = c->snapshot ();
1469 
1470  for (const EncodingRecord& _ : encodingrec_iter)
1471  {
1472  if (c->in_error ())
1473  return false;
1474 
1475  unsigned format = (base+_.subtable).u.format;
1476  if (format != 4 && format != 12 && format != 14) continue;
1477 
1478  hb_set_t unicodes_set;
1479  (base+_.subtable).collect_unicodes (&unicodes_set);
1480 
1481  if (!drop_format_4 && format == 4)
1482  {
1483  c->copy (_, + it | hb_filter (unicodes_set, hb_first), 4u, base, plan, &format4objidx);
1484  if (c->in_error () && c->only_overflow ())
1485  {
1486  // cmap4 overflowed, reset and retry serialization without format 4 subtables.
1487  c->revert (snap);
1488  return serialize (c, it,
1489  encodingrec_iter,
1490  base,
1491  plan,
1492  true);
1493  }
1494  }
1495 
1496  else if (format == 12)
1497  {
1498  if (_can_drop (_, unicodes_set, base, + it | hb_map (hb_first), encodingrec_iter)) continue;
1499  c->copy (_, + it | hb_filter (unicodes_set, hb_first), 12u, base, plan, &format12objidx);
1500  }
1501  else if (format == 14) c->copy (_, it, 14u, base, plan, &format14objidx);
1502  }
1503  c->check_assign(this->encodingRecord.len,
1504  (c->length () - cmap::min_size)/EncodingRecord::static_size,
1506 
1507  // Fail if format 4 was dropped and there is no cmap12.
1508  return !drop_format_4 || format12objidx;
1509  }
1510 
1511  template<typename Iterator, typename EncodingRecordIterator,
1512  hb_requires (hb_is_iterator (Iterator)),
1513  hb_requires (hb_is_iterator (EncodingRecordIterator))>
1514  bool _can_drop (const EncodingRecord& cmap12,
1515  const hb_set_t& cmap12_unicodes,
1516  const void* base,
1517  Iterator subset_unicodes,
1518  EncodingRecordIterator encoding_records)
1519  {
1520  for (auto cp : + subset_unicodes | hb_filter (cmap12_unicodes))
1521  {
1522  if (cp >= 0x10000) return false;
1523  }
1524 
1525  unsigned target_platform;
1526  unsigned target_encoding;
1527  unsigned target_language = (base+cmap12.subtable).get_language ();
1528 
1529  if (cmap12.platformID == 0 && cmap12.encodingID == 4)
1530  {
1531  target_platform = 0;
1532  target_encoding = 3;
1533  } else if (cmap12.platformID == 3 && cmap12.encodingID == 10) {
1534  target_platform = 3;
1535  target_encoding = 1;
1536  } else {
1537  return false;
1538  }
1539 
1540  for (const auto& _ : encoding_records)
1541  {
1542  if (_.platformID != target_platform
1543  || _.encodingID != target_encoding
1544  || (base+_.subtable).get_language() != target_language)
1545  continue;
1546 
1547  hb_set_t sibling_unicodes;
1548  (base+_.subtable).collect_unicodes (&sibling_unicodes);
1549 
1550  auto cmap12 = + subset_unicodes | hb_filter (cmap12_unicodes);
1551  auto sibling = + subset_unicodes | hb_filter (sibling_unicodes);
1552  for (; cmap12 && sibling; cmap12++, sibling++)
1553  {
1554  unsigned a = *cmap12;
1555  unsigned b = *sibling;
1556  if (a != b) return false;
1557  }
1558 
1559  return !cmap12 && !sibling;
1560  }
1561 
1562  return false;
1563  }
1564 
1565  void closure_glyphs (const hb_set_t *unicodes,
1566  hb_set_t *glyphset) const
1567  {
1568  + hb_iter (encodingRecord)
1570  | hb_map (hb_add (this))
1571  | hb_filter ([&] (const CmapSubtable& _) { return _.u.format == 14; })
1572  | hb_apply ([=] (const CmapSubtable& _) { _.u.format14.closure_glyphs (unicodes, glyphset); })
1573  ;
1574  }
1575 
1577  {
1578  TRACE_SUBSET (this);
1579 
1580  cmap *cmap_prime = c->serializer->start_embed<cmap> ();
1581  if (unlikely (!c->serializer->check_success (cmap_prime))) return_trace (false);
1582 
1583  auto encodingrec_iter =
1584  + hb_iter (encodingRecord)
1585  | hb_filter ([&] (const EncodingRecord& _)
1586  {
1587  if ((_.platformID == 0 && _.encodingID == 3) ||
1588  (_.platformID == 0 && _.encodingID == 4) ||
1589  (_.platformID == 3 && _.encodingID == 1) ||
1590  (_.platformID == 3 && _.encodingID == 10) ||
1591  (this + _.subtable).u.format == 14)
1592  return true;
1593 
1594  return false;
1595  })
1596  ;
1597 
1598  if (unlikely (!encodingrec_iter.len ())) return_trace (false);
1599 
1600  const EncodingRecord *unicode_bmp= nullptr, *unicode_ucs4 = nullptr, *ms_bmp = nullptr, *ms_ucs4 = nullptr;
1601  bool has_format12 = false;
1602 
1603  for (const EncodingRecord& _ : encodingrec_iter)
1604  {
1605  unsigned format = (this + _.subtable).u.format;
1606  if (format == 12) has_format12 = true;
1607 
1608  const EncodingRecord *table = std::addressof (_);
1609  if (_.platformID == 0 && _.encodingID == 3) unicode_bmp = table;
1610  else if (_.platformID == 0 && _.encodingID == 4) unicode_ucs4 = table;
1611  else if (_.platformID == 3 && _.encodingID == 1) ms_bmp = table;
1612  else if (_.platformID == 3 && _.encodingID == 10) ms_ucs4 = table;
1613  }
1614 
1615  if (unlikely (!has_format12 && !unicode_bmp && !ms_bmp)) return_trace (false);
1616  if (unlikely (has_format12 && (!unicode_ucs4 && !ms_ucs4))) return_trace (false);
1617 
1618  auto it =
1619  + hb_iter (c->plan->unicodes)
1620  | hb_map ([&] (hb_codepoint_t _)
1621  {
1623  c->plan->new_gid_for_codepoint (_, &new_gid);
1624  return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (_, new_gid);
1625  })
1626  | hb_filter ([&] (const hb_pair_t<hb_codepoint_t, hb_codepoint_t> _)
1627  { return (_.second != HB_MAP_VALUE_INVALID); })
1628  ;
1629 
1630  return_trace (cmap_prime->serialize (c->serializer, it, encodingrec_iter, this, c->plan));
1631  }
1632 
1633  const CmapSubtable *find_best_subtable (bool *symbol = nullptr) const
1634  {
1635  if (symbol) *symbol = false;
1636 
1637  const CmapSubtable *subtable;
1638 
1639  /* Symbol subtable.
1640  * Prefer symbol if available.
1641  * https://github.com/harfbuzz/harfbuzz/issues/1918 */
1642  if ((subtable = this->find_subtable (3, 0)))
1643  {
1644  if (symbol) *symbol = true;
1645  return subtable;
1646  }
1647 
1648  /* 32-bit subtables. */
1649  if ((subtable = this->find_subtable (3, 10))) return subtable;
1650  if ((subtable = this->find_subtable (0, 6))) return subtable;
1651  if ((subtable = this->find_subtable (0, 4))) return subtable;
1652 
1653  /* 16-bit subtables. */
1654  if ((subtable = this->find_subtable (3, 1))) return subtable;
1655  if ((subtable = this->find_subtable (0, 3))) return subtable;
1656  if ((subtable = this->find_subtable (0, 2))) return subtable;
1657  if ((subtable = this->find_subtable (0, 1))) return subtable;
1658  if ((subtable = this->find_subtable (0, 0))) return subtable;
1659 
1660  /* Meh. */
1661  return &Null (CmapSubtable);
1662  }
1663 
1665  {
1667  {
1668  this->table = hb_sanitize_context_t ().reference_table<cmap> (face);
1669  bool symbol;
1670  this->subtable = table->find_best_subtable (&symbol);
1671  this->subtable_uvs = &Null (CmapSubtableFormat14);
1672  {
1673  const CmapSubtable *st = table->find_subtable (0, 5);
1674  if (st && st->u.format == 14)
1675  subtable_uvs = &st->u.format14;
1676  }
1677 
1678  this->get_glyph_data = subtable;
1679  if (unlikely (symbol))
1680  this->get_glyph_funcZ = get_glyph_from_symbol<CmapSubtable>;
1681  else
1682  {
1683  switch (subtable->u.format) {
1684  /* Accelerate format 4 and format 12. */
1685  default:
1686  this->get_glyph_funcZ = get_glyph_from<CmapSubtable>;
1687  break;
1688  case 12:
1689  this->get_glyph_funcZ = get_glyph_from<CmapSubtableFormat12>;
1690  break;
1691  case 4:
1692  {
1693  this->format4_accel.init (&subtable->u.format4);
1694  this->get_glyph_data = &this->format4_accel;
1695  this->get_glyph_funcZ = this->format4_accel.get_glyph_func;
1696  break;
1697  }
1698  }
1699  }
1700  }
1701  ~accelerator_t () { this->table.destroy (); }
1702 
1704  hb_codepoint_t *glyph) const
1705  {
1706  if (unlikely (!this->get_glyph_funcZ)) return false;
1707  return this->get_glyph_funcZ (this->get_glyph_data, unicode, glyph);
1708  }
1709  unsigned int get_nominal_glyphs (unsigned int count,
1710  const hb_codepoint_t *first_unicode,
1711  unsigned int unicode_stride,
1712  hb_codepoint_t *first_glyph,
1713  unsigned int glyph_stride) const
1714  {
1715  if (unlikely (!this->get_glyph_funcZ)) return 0;
1716 
1717  hb_cmap_get_glyph_func_t get_glyph_funcZ = this->get_glyph_funcZ;
1718  const void *get_glyph_data = this->get_glyph_data;
1719 
1720  unsigned int done;
1721  for (done = 0;
1722  done < count && get_glyph_funcZ (get_glyph_data, *first_unicode, first_glyph);
1723  done++)
1724  {
1725  first_unicode = &StructAtOffsetUnaligned<hb_codepoint_t> (first_unicode, unicode_stride);
1726  first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
1727  }
1728  return done;
1729  }
1730 
1732  hb_codepoint_t variation_selector,
1733  hb_codepoint_t *glyph) const
1734  {
1735  switch (this->subtable_uvs->get_glyph_variant (unicode,
1736  variation_selector,
1737  glyph))
1738  {
1739  case GLYPH_VARIANT_NOT_FOUND: return false;
1740  case GLYPH_VARIANT_FOUND: return true;
1741  case GLYPH_VARIANT_USE_DEFAULT: break;
1742  }
1743 
1744  return get_nominal_glyph (unicode, glyph);
1745  }
1746 
1747  void collect_unicodes (hb_set_t *out, unsigned int num_glyphs) const
1748  { subtable->collect_unicodes (out, num_glyphs); }
1750  unsigned num_glyphs = UINT_MAX) const
1751  { subtable->collect_mapping (unicodes, mapping, num_glyphs); }
1753  { subtable_uvs->collect_variation_selectors (out); }
1754  void collect_variation_unicodes (hb_codepoint_t variation_selector,
1755  hb_set_t *out) const
1756  { subtable_uvs->collect_variation_unicodes (variation_selector, out); }
1757 
1758  protected:
1759  typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj,
1760  hb_codepoint_t codepoint,
1761  hb_codepoint_t *glyph);
1762 
1763  template <typename Type>
1764  HB_INTERNAL static bool get_glyph_from (const void *obj,
1765  hb_codepoint_t codepoint,
1766  hb_codepoint_t *glyph)
1767  {
1768  const Type *typed_obj = (const Type *) obj;
1769  return typed_obj->get_glyph (codepoint, glyph);
1770  }
1771 
1772  template <typename Type>
1773  HB_INTERNAL static bool get_glyph_from_symbol (const void *obj,
1774  hb_codepoint_t codepoint,
1775  hb_codepoint_t *glyph)
1776  {
1777  const Type *typed_obj = (const Type *) obj;
1778  if (likely (typed_obj->get_glyph (codepoint, glyph)))
1779  return true;
1780 
1781  if (codepoint <= 0x00FFu)
1782  {
1783  /* For symbol-encoded OpenType fonts, we duplicate the
1784  * U+F000..F0FF range at U+0000..U+00FF. That's what
1785  * Windows seems to do, and that's hinted about at:
1786  * https://docs.microsoft.com/en-us/typography/opentype/spec/recom
1787  * under "Non-Standard (Symbol) Fonts". */
1788  return typed_obj->get_glyph (0xF000u + codepoint, glyph);
1789  }
1790 
1791  return false;
1792  }
1793 
1794  private:
1797 
1798  hb_cmap_get_glyph_func_t get_glyph_funcZ;
1799  const void *get_glyph_data;
1800 
1801  CmapSubtableFormat4::accelerator_t format4_accel;
1802 
1803  public:
1805  };
1806 
1807  protected:
1808 
1809  const CmapSubtable *find_subtable (unsigned int platform_id,
1810  unsigned int encoding_id) const
1811  {
1813  key.platformID = platform_id;
1814  key.encodingID = encoding_id;
1815 
1816  const EncodingRecord &result = encodingRecord.bsearch (key);
1817  if (!result.subtable)
1818  return nullptr;
1819 
1820  return &(this+result.subtable);
1821  }
1822 
1823  const EncodingRecord *find_encodingrec (unsigned int platform_id,
1824  unsigned int encoding_id) const
1825  {
1827  key.platformID = platform_id;
1828  key.encodingID = encoding_id;
1829 
1830  return encodingRecord.as_array ().bsearch (key);
1831  }
1832 
1833  bool find_subtable (unsigned format) const
1834  {
1835  auto it =
1836  + hb_iter (encodingRecord)
1838  | hb_map (hb_add (this))
1839  | hb_filter ([&] (const CmapSubtable& _) { return _.u.format == format; })
1840  ;
1841 
1842  return it.len ();
1843  }
1844 
1845  public:
1846 
1848  {
1849  TRACE_SANITIZE (this);
1850  return_trace (c->check_struct (this) &&
1851  likely (version == 0) &&
1852  encodingRecord.sanitize (c, this));
1853  }
1854 
1855  protected:
1856  HBUINT16 version; /* Table version number (0). */
1858  encodingRecord; /* Encoding tables. */
1859  public:
1861 };
1862 
1865 };
1866 
1867 } /* namespace OT */
1868 
1869 
1870 #endif /* HB_OT_CMAP_TABLE_HH */
small capitals from c petite p scientific f u
Definition: afcover.h:88
small capitals from c petite p scientific i
[1]
Definition: afcover.h:80
Definition: base.h:37
constexpr T & operator()(T &v) const
Definition: hb-algs.hh:2
#define TRACE_SERIALIZE(this)
Definition: hb-debug.hh:426
#define TRACE_SANITIZE(this)
Definition: hb-debug.hh:414
#define return_trace(RET)
Definition: hb-debug.hh:349
#define TRACE_SUBSET(this)
Definition: hb-debug.hh:438
void const void *obj HB_UNUSED
Definition: hb-debug.hh:180
#define hb_is_iterator(Iter)
Definition: hb-iter.hh:265
auto it hb_map(hb_second)) template< typename Type > inline hb_array_t< Type > operator()(hb_array_t< Type > array
static auto hb_requires(hb_is_iterable(Iterable))> static inline auto end(Iterable &&iterable) HB_AUTO_RETURN(hb_iter(iterable).end()) namespace OT
Definition: hb-iter.hh:331
#define HB_MAP_VALUE_INVALID
Definition: hb-map.h:46
#define HB_OT_TAG_cmap
#define _(S, M)
@ HB_SERIALIZE_ERROR_INT_OVERFLOW
Definition: hb-serialize.hh:52
#define likely(expr)
Definition: hb.hh:250
#define unlikely(expr)
Definition: hb.hh:251
#define HB_INTERNAL
Definition: hb.hh:274
DECLARE_NULL_NAMESPACE_BYTES(OT, Index)
@ GLYPH_VARIANT_NOT_FOUND
@ GLYPH_VARIANT_USE_DEFAULT
@ GLYPH_VARIANT_FOUND
def startCount(c, text)
Definition: qlocalexml.py:65
set set set set set set set macro pixldst1 abits if abits op else op endif endm macro pixldst2 abits if abits op else op endif endm macro pixldst4 abits if abits op else op endif endm macro pixldst0 abits op endm macro pixldst3 mem_operand op endm macro pixldst30 mem_operand op endm macro pixldst abits if abits elseif abits elseif abits elseif abits elseif abits pixldst0 abits else pixldst0 abits pixldst0 abits pixldst0 abits pixldst0 abits endif elseif abits else pixldst0 abits pixldst0 abits endif elseif abits else error unsupported bpp *numpix else pixst endif endm macro vuzp8 reg2 vuzp d d &reg2 endm macro vzip8 reg2 vzip d d &reg2 endm macro pixdeinterleave basereg basereg basereg basereg basereg endif endm macro pixinterleave basereg basereg basereg basereg basereg endif endm macro PF boost_increment endif if endif PF tst PF addne PF subne PF cmp ORIG_W if endif if endif if endif PF subge ORIG_W PF subges if endif if endif if endif endif endm macro cache_preload_simple endif if dst_r_bpp pld[DST_R, #(PREFETCH_DISTANCE_SIMPLE *dst_r_bpp/8)] endif if mask_bpp pld if[MASK, #(PREFETCH_DISTANCE_SIMPLE *mask_bpp/8)] endif endif endm macro ensure_destination_ptr_alignment process_pixblock_tail_head if beq irp skip1(dst_w_bpp<=(lowbit *8)) &&((lowbit *8)<(pixblock_size *dst_w_bpp)) .if lowbit< 16 tst DST_R
[3]
QT_BEGIN_NAMESPACE bool done
GLenum GLuint GLenum GLsizei length
Definition: qopengl.h:270
GLenum GLsizei GLsizei GLint * values
[16]
GLboolean GLboolean GLboolean b
GLenum mode
GLsizei GLuint * groups
GLuint64 key
GLboolean GLboolean GLboolean GLboolean a
[7]
GLuint index
[2]
GLuint GLuint end
GLenum GLenum GLsizei count
GLenum face
GLsizei GLsizei GLfloat distance
GLboolean GLuint group
GLuint start
GLenum GLuint GLintptr offset
GLint first
GLint GLsizei GLsizei GLenum format
GLuint counter
GLhandleARB obj
[2]
Definition: qopenglext.h:4164
const GLubyte * c
Definition: qopenglext.h:12701
GLenum GLsizei len
Definition: qopenglext.h:3292
GLuint64EXT * result
[6]
Definition: qopenglext.h:10932
GLenum GLenum GLenum GLenum mapping
Definition: qopenglext.h:10816
GLenum GLenum GLsizei void * table
Definition: qopenglext.h:2745
uint32_t hb_codepoint_t
Definition: hb-common.h:106
uint32_t hb_tag_t
Definition: hb-common.h:157
#define HB_UNICODE_MAX
Definition: hb-unicode.h:50
QString base
QTextStream out(stdout)
[7]
MyRecord record(int row) const
[0]
QSharedPointer< T > other(t)
[5]
QStringList::Iterator it
Definition: hb-null.hh:93
Type arrayZ[HB_VAR_ARRAY]
bool get_glyph(hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
void collect_unicodes(hb_set_t *out) const
unsigned get_language() const
void collect_mapping(hb_set_t *unicodes, hb_map_t *mapping) const
bool sanitize(hb_sanitize_context_t *c) const
static hb_codepoint_t group_get_glyph(const CmapSubtableLongGroup &group, hb_codepoint_t u)
static size_t get_sub_table_size(const hb_sorted_vector_t< CmapSubtableLongGroup > &groups_data)
void serialize(hb_serialize_context_t *c, Iterator it)
static hb_codepoint_t group_get_glyph(const CmapSubtableLongGroup &group, hb_codepoint_t u HB_UNUSED)
DEFINE_SIZE_ARRAY(10, record)
bool sanitize(hb_sanitize_context_t *c) const
void _add_links_to_variation_records(hb_serialize_context_t *c, const hb_vector_t< hb_pair_t< unsigned, unsigned >> &obj_indices)
void collect_unicodes(hb_set_t *out) const
void closure_glyphs(const hb_set_t *unicodes, hb_set_t *glyphset) const
void collect_variation_selectors(hb_set_t *out) const
SortedArray32Of< VariationSelectorRecord > record
void collect_mapping(hb_set_t *unicodes, hb_map_t *mapping) const
void serialize(hb_serialize_context_t *c, const hb_set_t *unicodes, const hb_set_t *glyphs_requested, const hb_map_t *glyph_map, const void *base)
glyph_variant_t get_glyph_variant(hb_codepoint_t codepoint, hb_codepoint_t variation_selector, hb_codepoint_t *glyph) const
void collect_variation_unicodes(hb_codepoint_t variation_selector, hb_set_t *out) const
void init(const CmapSubtableFormat4 *subtable)
accelerator_t(const CmapSubtableFormat4 *subtable)
static HB_INTERNAL bool get_glyph_func(const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph)
void collect_unicodes(hb_set_t *out) const
void collect_mapping(hb_set_t *unicodes, hb_map_t *mapping) const
bool get_glyph(hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
void to_ranges(Iterator it, Writer &range_writer)
UnsizedArrayOf< HBUINT16 > values
unsigned get_language() const
HBUINT16 * serialize_rangeoffset_glyid(hb_serialize_context_t *c, Iterator it, HBUINT16 *endCode, HBUINT16 *startCode, HBINT16 *idDelta, unsigned segcount)
void serialize(hb_serialize_context_t *c, Iterator it)
bool sanitize(hb_sanitize_context_t *c) const
DEFINE_SIZE_ARRAY(14, values)
void commit_current_range(hb_codepoint_t start, hb_codepoint_t prev_run_start, hb_codepoint_t run_start, hb_codepoint_t end, int run_delta, int previous_run_delta, int split_cost, Writer &range_writer)
unsigned serialize_find_segcount(Iterator it)
void collect_mapping(hb_set_t *unicodes, hb_map_t *mapping) const
void collect_unicodes(hb_set_t *out) const
bool get_glyph(hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
bool serialize_start_end_delta_arrays(hb_serialize_context_t *c, Iterator it, int segcount)
CmapSubtableFormat10 format10
void collect_mapping(hb_set_t *unicodes, hb_map_t *mapping, unsigned num_glyphs=UINT_MAX) const
CmapSubtableFormat0 format0
unsigned get_language() const
bool sanitize(hb_sanitize_context_t *c) const
CmapSubtableFormat4 format4
bool get_glyph(hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
CmapSubtableFormat14 format14
DEFINE_SIZE_UNION(2, format)
void serialize(hb_serialize_context_t *c, Iterator it, unsigned format, const hb_subset_plan_t *plan, const void *base)
CmapSubtableFormat6 format6
union OT::CmapSubtable::@149 u
void collect_unicodes(hb_set_t *out, unsigned int num_glyphs=UINT_MAX) const
CmapSubtableFormat12 format12
CmapSubtableFormat13 format13
bool sanitize(hb_sanitize_context_t *c) const
int cmp(hb_codepoint_t codepoint) const
void collect_unicodes(hb_set_t *out, unsigned int num_glyphs) const
bool sanitize(hb_sanitize_context_t *c) const
void collect_mapping(hb_set_t *unicodes, hb_map_t *mapping, unsigned num_glyphs) const
bool get_glyph(hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
SortedArray32Of< CmapSubtableLongGroup > groups
bool get_glyph(hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
unsigned get_language() const
DEFINE_SIZE_ARRAY(5 *sizeof(UINT), glyphIdArray)
void collect_mapping(hb_set_t *unicodes, hb_map_t *mapping) const
bool sanitize(hb_sanitize_context_t *c) const
void collect_unicodes(hb_set_t *out) const
ArrayOf< HBGlyphID16, UINT > glyphIdArray
DefaultUVS * copy(hb_serialize_context_t *c, const hb_set_t *unicodes) const
DEFINE_SIZE_ARRAY(4, *this)
void collect_unicodes(hb_set_t *out) const
Offset32To< CmapSubtable > subtable
EncodingRecord * copy(hb_serialize_context_t *c, Iterator it, unsigned format, const void *base, const hb_subset_plan_t *plan, unsigned *objidx) const
int cmp(const EncodingRecord &other) const
bool sanitize(hb_sanitize_context_t *c, const void *base) const
static HB_INTERNAL int cmp(const IntType *a, const IntType *b)
Definition: hb-open-type.hh:79
void collect_unicodes(hb_set_t *out) const
void collect_mapping(hb_set_t *unicodes, hb_map_t *mapping) const
DEFINE_SIZE_ARRAY(4, *this)
NonDefaultUVS * copy(hb_serialize_context_t *c, const hb_set_t *unicodes, const hb_set_t *glyphs_requested, const hb_map_t *glyph_map) const
void closure_glyphs(const hb_set_t *unicodes, hb_set_t *glyphset) const
hb_sorted_array_t< Type > as_array()
HBGlyphID16 glyphID
bool sanitize(hb_sanitize_context_t *c) const
int cmp(const hb_codepoint_t &codepoint) const
bool sanitize(hb_sanitize_context_t *c) const
int cmp(const hb_codepoint_t &codepoint) const
hb_pair_t< unsigned, unsigned > copy(hb_serialize_context_t *c, const hb_set_t *unicodes, const hb_set_t *glyphs_requested, const hb_map_t *glyph_map, const void *base) const
glyph_variant_t get_glyph(hb_codepoint_t codepoint, hb_codepoint_t *glyph, const void *base) const
void operator=(const VariationSelectorRecord &other)
bool sanitize(hb_sanitize_context_t *c, const void *base) const
Offset32To< NonDefaultUVS > nonDefaultUVS
int cmp(const hb_codepoint_t &variation_selector) const
Offset32To< DefaultUVS > defaultUVS
VariationSelectorRecord(const VariationSelectorRecord &other)
void collect_mapping(const void *base, hb_set_t *unicodes, hb_map_t *mapping) const
void collect_unicodes(hb_set_t *out, const void *base) const
unsigned int get_nominal_glyphs(unsigned int count, const hb_codepoint_t *first_unicode, unsigned int unicode_stride, hb_codepoint_t *first_glyph, unsigned int glyph_stride) const
accelerator_t(hb_face_t *face)
bool(* hb_cmap_get_glyph_func_t)(const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph)
void collect_unicodes(hb_set_t *out, unsigned int num_glyphs) const
void collect_variation_selectors(hb_set_t *out) const
void collect_variation_unicodes(hb_codepoint_t variation_selector, hb_set_t *out) const
static HB_INTERNAL bool get_glyph_from_symbol(const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph)
static HB_INTERNAL bool get_glyph_from(const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph)
hb_blob_ptr_t< cmap > table
void collect_mapping(hb_set_t *unicodes, hb_map_t *mapping, unsigned num_glyphs=UINT_MAX) const
bool get_nominal_glyph(hb_codepoint_t unicode, hb_codepoint_t *glyph) const
bool get_variation_glyph(hb_codepoint_t unicode, hb_codepoint_t variation_selector, hb_codepoint_t *glyph) const
cmap_accelerator_t(hb_face_t *face)
const CmapSubtable * find_subtable(unsigned int platform_id, unsigned int encoding_id) const
SortedArray16Of< EncodingRecord > encodingRecord
const CmapSubtable * find_best_subtable(bool *symbol=nullptr) const
bool _can_drop(const EncodingRecord &cmap12, const hb_set_t &cmap12_unicodes, const void *base, Iterator subset_unicodes, EncodingRecordIterator encoding_records)
bool serialize(hb_serialize_context_t *c, Iterator it, EncodingRecIter encodingrec_iter, const void *base, const hb_subset_plan_t *plan, bool drop_format_4=false)
const EncodingRecord * find_encodingrec(unsigned int platform_id, unsigned int encoding_id) const
void closure_glyphs(const hb_set_t *unicodes, hb_set_t *glyphset) const
static constexpr hb_tag_t tableTag
bool find_subtable(unsigned format) const
bool sanitize(hb_sanitize_context_t *c) const
HBUINT16 version
DEFINE_SIZE_ARRAY(4, encodingRecord)
bool subset(hb_subset_context_t *c) const
Definition: moc.h:48
V get(K key) const
Definition: hb-map.hh:202
unsigned int length() const
bool has(hb_codepoint_t k) const
Definition: hb-set.hh:111
void add(hb_codepoint_t g)
Definition: hb-set.hh:85
hb_set_t * unicodes
hb_map_t * glyph_map
hb_set_t * glyphs_requested
Type * push()
Definition: hb-vector.hh:183
bool in_error() const
Definition: hb-vector.hh:203
unsigned int length
Definition: hb-vector.hh:76