blob: 8d94ad312a06da91fbaa7643501216f906243a94 [file] [log] [blame]
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -04001/*
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
Behdad Esfahbodc77ae402018-08-25 22:36:36 -070030#include "hb-open-type.hh"
31#include "hb-set.hh"
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -040032
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -040033/*
Ebrahim Byagowif24b0b92018-04-12 13:40:45 +043034 * cmap -- Character to Glyph Index Mapping
35 * https://docs.microsoft.com/en-us/typography/opentype/spec/cmap
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -040036 */
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -040037#define HB_OT_TAG_cmap HB_TAG('c','m','a','p')
38
Ebrahim Byagowif24b0b92018-04-12 13:40:45 +043039namespace OT {
40
41
Behdad Esfahbodb7878cd2014-05-13 21:47:51 -040042struct CmapSubtableFormat0
43{
Behdad Esfahbodb7878cd2014-05-13 21:47:51 -040044 inline 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;
Behdad Esfahbod2ccc3222018-08-29 16:38:04 -070050 return true;
Behdad Esfahbodb7878cd2014-05-13 21:47:51 -040051 }
Behdad Esfahbod7d382fa2018-08-25 09:35:45 -070052 inline void collect_unicodes (hb_set_t *out) const
53 {
54 for (unsigned int i = 0; i < 256; i++)
55 if (glyphIdArray[i])
56 out->add (i);
57 }
Behdad Esfahbodb7878cd2014-05-13 21:47:51 -040058
Behdad Esfahbodde2118e2015-02-17 17:27:44 +030059 inline bool sanitize (hb_sanitize_context_t *c) const
60 {
Behdad Esfahbodb7878cd2014-05-13 21:47:51 -040061 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +010062 return_trace (c->check_struct (this));
Behdad Esfahbodb7878cd2014-05-13 21:47:51 -040063 }
64
65 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +010066 HBUINT16 format; /* Format number is set to 0. */
Behdad Esfahbod5b93f692018-05-02 14:59:14 -040067 HBUINT16 length; /* Byte length of this subtable. */
68 HBUINT16 language; /* Ignore. */
Behdad Esfahbod9aa2eb62018-02-11 19:00:42 -060069 HBUINT8 glyphIdArray[256];/* An array that maps character
Behdad Esfahbodb7878cd2014-05-13 21:47:51 -040070 * code to glyph index values. */
71 public:
72 DEFINE_SIZE_STATIC (6 + 256);
73};
74
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -040075struct CmapSubtableFormat4
76{
Garret Rieger295d67e2018-05-02 16:12:04 -070077 struct segment_plan
78 {
79 HBUINT16 start_code;
80 HBUINT16 end_code;
81 bool use_delta;
82 };
83
84 bool serialize (hb_serialize_context_t *c,
85 const hb_subset_plan_t *plan,
86 const hb_vector_t<segment_plan> &segments)
87 {
Garret Rieger4195a522018-05-02 17:11:18 -070088 TRACE_SERIALIZE (this);
89
90 if (unlikely (!c->extend_min (*this))) return_trace (false);
91
92 this->format.set (4);
93 this->length.set (get_sub_table_size (segments));
94
Garret Rieger4195a522018-05-02 17:11:18 -070095 this->segCountX2.set (segments.len * 2);
Behdad Esfahbodbddeb2b2018-07-10 14:12:37 +020096 this->entrySelector.set (MAX (1u, hb_bit_storage (segments.len)) - 1);
Garret Rieger3be050f2018-05-04 11:23:32 -070097 this->searchRange.set (2 * (1u << this->entrySelector));
98 this->rangeShift.set (segments.len * 2 > this->searchRange
99 ? 2 * segments.len - this->searchRange
100 : 0);
Garret Rieger4195a522018-05-02 17:11:18 -0700101
102 HBUINT16 *end_count = c->allocate_size<HBUINT16> (HBUINT16::static_size * segments.len);
103 c->allocate_size<HBUINT16> (HBUINT16::static_size); // 2 bytes of padding.
104 HBUINT16 *start_count = c->allocate_size<HBUINT16> (HBUINT16::static_size * segments.len);
105 HBINT16 *id_delta = c->allocate_size<HBINT16> (HBUINT16::static_size * segments.len);
106 HBUINT16 *id_range_offset = c->allocate_size<HBUINT16> (HBUINT16::static_size * segments.len);
107
Garret Rieger9ef55a42018-05-02 18:50:56 -0700108 if (id_range_offset == nullptr)
109 return_trace (false);
110
Garret Rieger4195a522018-05-02 17:11:18 -0700111 for (unsigned int i = 0; i < segments.len; i++)
112 {
113 end_count[i].set (segments[i].end_code);
114 start_count[i].set (segments[i].start_code);
115 if (segments[i].use_delta)
116 {
Garret Rieger9ef55a42018-05-02 18:50:56 -0700117 hb_codepoint_t cp = segments[i].start_code;
118 hb_codepoint_t start_gid = 0;
Garret Rieger251cc972018-05-30 12:23:51 -0700119 if (unlikely (!plan->new_gid_for_codepoint (cp, &start_gid) && cp != 0xFFFF))
Garret Rieger9ef55a42018-05-02 18:50:56 -0700120 return_trace (false);
Garret Rieger4195a522018-05-02 17:11:18 -0700121 id_delta[i].set (start_gid - segments[i].start_code);
122 } else {
Garret Rieger81ea75f2018-05-02 17:46:30 -0700123 id_delta[i].set (0);
124 unsigned int num_codepoints = segments[i].end_code - segments[i].start_code + 1;
125 HBUINT16 *glyph_id_array = c->allocate_size<HBUINT16> (HBUINT16::static_size * num_codepoints);
Garret Rieger9ef55a42018-05-02 18:50:56 -0700126 if (glyph_id_array == nullptr)
127 return_trace (false);
Garret Rieger81ea75f2018-05-02 17:46:30 -0700128 // From the cmap spec:
129 //
130 // id_range_offset[i]/2
131 // + (cp - segments[i].start_code)
132 // + (id_range_offset + i)
133 // =
134 // glyph_id_array + (cp - segments[i].start_code)
135 //
136 // So, solve for id_range_offset[i]:
137 //
138 // id_range_offset[i]
139 // =
140 // 2 * (glyph_id_array - id_range_offset - i)
141 id_range_offset[i].set (2 * (
142 glyph_id_array - id_range_offset - i));
143 for (unsigned int j = 0; j < num_codepoints; j++)
144 {
145 hb_codepoint_t cp = segments[i].start_code + j;
Garret Rieger9ef55a42018-05-02 18:50:56 -0700146 hb_codepoint_t new_gid;
Garret Rieger251cc972018-05-30 12:23:51 -0700147 if (unlikely (!plan->new_gid_for_codepoint (cp, &new_gid)))
Garret Rieger9ef55a42018-05-02 18:50:56 -0700148 return_trace (false);
Garret Rieger81ea75f2018-05-02 17:46:30 -0700149 glyph_id_array[j].set (new_gid);
150 }
Garret Rieger4195a522018-05-02 17:11:18 -0700151 }
152 }
153
Garret Rieger9ef55a42018-05-02 18:50:56 -0700154 return_trace (true);
Garret Rieger295d67e2018-05-02 16:12:04 -0700155 }
156
157 static inline size_t get_sub_table_size (const hb_vector_t<segment_plan> &segments)
158 {
159 size_t segment_size = 0;
160 for (unsigned int i = 0; i < segments.len; i++)
161 {
162 // Parallel array entries
163 segment_size +=
164 2 // end count
165 + 2 // start count
166 + 2 // delta
167 + 2; // range offset
168
169 if (!segments[i].use_delta)
170 // Add bytes for the glyph index array entries for this segment.
171 segment_size += (segments[i].end_code - segments[i].start_code + 1) * 2;
172 }
173
174 return min_size
175 + 2 // Padding
176 + segment_size;
177 }
178
179 static inline bool create_sub_table_plan (const hb_subset_plan_t *plan,
180 hb_vector_t<segment_plan> *segments)
181 {
Garret Riegercfa592d2018-05-02 16:37:38 -0700182 segment_plan *segment = nullptr;
183 hb_codepoint_t last_gid = 0;
Garret Rieger251cc972018-05-30 12:23:51 -0700184
185 hb_codepoint_t cp = HB_SET_VALUE_INVALID;
186 while (plan->unicodes->next (&cp)) {
Garret Riegercfa592d2018-05-02 16:37:38 -0700187 hb_codepoint_t new_gid;
Garret Rieger251cc972018-05-30 12:23:51 -0700188 if (unlikely (!plan->new_gid_for_codepoint (cp, &new_gid)))
Garret Riegercfa592d2018-05-02 16:37:38 -0700189 {
190 DEBUG_MSG(SUBSET, nullptr, "Unable to find new gid for %04x", cp);
191 return false;
192 }
193
194 if (cp > 0xFFFF) {
195 // We are now outside of unicode BMP, stop adding to this cmap.
196 break;
197 }
198
199 if (!segment
Behdad Esfahbode99d75e2018-05-09 15:28:30 -0700200 || cp != segment->end_code + 1u)
Garret Riegercfa592d2018-05-02 16:37:38 -0700201 {
202 segment = segments->push ();
203 segment->start_code.set (cp);
204 segment->end_code.set (cp);
205 segment->use_delta = true;
206 } else {
207 segment->end_code.set (cp);
Behdad Esfahbode99d75e2018-05-09 15:28:30 -0700208 if (last_gid + 1u != new_gid)
Garret Riegercfa592d2018-05-02 16:37:38 -0700209 // gid's are not consecutive in this segment so delta
210 // cannot be used.
211 segment->use_delta = false;
212 }
213
Garret Riegercfa592d2018-05-02 16:37:38 -0700214 last_gid = new_gid;
215 }
Garret Rieger9ef55a42018-05-02 18:50:56 -0700216
217 // There must be a final entry with end_code == 0xFFFF. Check if we need to add one.
Behdad Esfahbodf7515762018-06-01 17:48:37 -0700218 if (segment == nullptr || segment->end_code != 0xFFFF)
219 {
Garret Rieger9ef55a42018-05-02 18:50:56 -0700220 segment = segments->push ();
221 segment->start_code.set (0xFFFF);
222 segment->end_code.set (0xFFFF);
223 segment->use_delta = true;
224 }
225
Garret Riegercfa592d2018-05-02 16:37:38 -0700226 return true;
Garret Rieger295d67e2018-05-02 16:12:04 -0700227 }
228
Behdad Esfahbod23335de2016-02-24 20:27:13 +0900229 struct accelerator_t
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400230 {
Behdad Esfahbod56e0fd32018-10-29 22:35:44 -0700231 inline accelerator_t (void) {}
232 inline accelerator_t (const CmapSubtableFormat4 *subtable) { init (subtable); }
233 inline ~accelerator_t (void) { fini (); }
234
Behdad Esfahbod23335de2016-02-24 20:27:13 +0900235 inline void init (const CmapSubtableFormat4 *subtable)
236 {
237 segCount = subtable->segCountX2 / 2;
Behdad Esfahboddff2c452018-09-10 23:29:26 +0200238 endCount = subtable->values.arrayZ;
Behdad Esfahbod23335de2016-02-24 20:27:13 +0900239 startCount = endCount + segCount + 1;
240 idDelta = startCount + segCount;
241 idRangeOffset = idDelta + segCount;
242 glyphIdArray = idRangeOffset + segCount;
243 glyphIdArrayLength = (subtable->length - 16 - 8 * segCount) / 2;
244 }
Behdad Esfahbodddea4d12018-08-25 21:08:15 -0700245 inline void fini (void) {}
Behdad Esfahbod23335de2016-02-24 20:27:13 +0900246
Behdad Esfahbodb41c43b2018-08-25 15:25:03 -0700247 inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
Behdad Esfahbod23335de2016-02-24 20:27:13 +0900248 {
Behdad Esfahbod23335de2016-02-24 20:27:13 +0900249 /* Custom two-array bsearch. */
Behdad Esfahbodb41c43b2018-08-25 15:25:03 -0700250 int min = 0, max = (int) this->segCount - 1;
251 const HBUINT16 *startCount = this->startCount;
252 const HBUINT16 *endCount = this->endCount;
Behdad Esfahbod23335de2016-02-24 20:27:13 +0900253 unsigned int i;
254 while (min <= max)
255 {
Behdad Esfahbod21ede862018-10-25 13:19:34 -0700256 int mid = ((unsigned int) min + (unsigned int) max) / 2;
Behdad Esfahbod23335de2016-02-24 20:27:13 +0900257 if (codepoint < startCount[mid])
258 max = mid - 1;
259 else if (codepoint > endCount[mid])
260 min = mid + 1;
261 else
262 {
263 i = mid;
264 goto found;
265 }
266 }
267 return false;
268
269 found:
270 hb_codepoint_t gid;
Behdad Esfahbodb41c43b2018-08-25 15:25:03 -0700271 unsigned int rangeOffset = this->idRangeOffset[i];
Behdad Esfahbod23335de2016-02-24 20:27:13 +0900272 if (rangeOffset == 0)
Behdad Esfahbodb41c43b2018-08-25 15:25:03 -0700273 gid = codepoint + this->idDelta[i];
Behdad Esfahbod23335de2016-02-24 20:27:13 +0900274 else
275 {
276 /* Somebody has been smoking... */
Behdad Esfahbodb41c43b2018-08-25 15:25:03 -0700277 unsigned int index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount;
278 if (unlikely (index >= this->glyphIdArrayLength))
Behdad Esfahbod23335de2016-02-24 20:27:13 +0900279 return false;
Behdad Esfahbodb41c43b2018-08-25 15:25:03 -0700280 gid = this->glyphIdArray[index];
Behdad Esfahbod23335de2016-02-24 20:27:13 +0900281 if (unlikely (!gid))
282 return false;
Behdad Esfahbodb41c43b2018-08-25 15:25:03 -0700283 gid += this->idDelta[i];
Behdad Esfahbod23335de2016-02-24 20:27:13 +0900284 }
Behdad Esfahbod2ccc3222018-08-29 16:38:04 -0700285 gid &= 0xFFFFu;
286 if (!gid)
287 return false;
288 *glyph = gid;
289 return true;
Behdad Esfahbod23335de2016-02-24 20:27:13 +0900290 }
Behdad Esfahbodb41c43b2018-08-25 15:25:03 -0700291 static inline bool get_glyph_func (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph)
292 {
293 return ((const accelerator_t *) obj)->get_glyph (codepoint, glyph);
294 }
295 inline void collect_unicodes (hb_set_t *out) const
296 {
Behdad Esfahbodc8cfb702018-08-25 16:14:32 -0700297 unsigned int count = this->segCount;
298 if (count && this->startCount[count - 1] == 0xFFFFu)
299 count--; /* Skip sentinel segment. */
300 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbodb41c43b2018-08-25 15:25:03 -0700301 {
Behdad Esfahbod28634db2018-08-25 21:23:43 -0700302 unsigned int rangeOffset = this->idRangeOffset[i];
303 if (rangeOffset == 0)
304 out->add_range (this->startCount[i], this->endCount[i]);
305 else
306 {
307 for (hb_codepoint_t codepoint = this->startCount[i];
308 codepoint <= this->endCount[i];
309 codepoint++)
310 {
311 unsigned int index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount;
312 if (unlikely (index >= this->glyphIdArrayLength))
313 break;
314 hb_codepoint_t gid = this->glyphIdArray[index];
315 if (unlikely (!gid))
316 continue;
317 out->add (codepoint);
318 }
319 }
Behdad Esfahbodb41c43b2018-08-25 15:25:03 -0700320 }
321 }
Behdad Esfahbod23335de2016-02-24 20:27:13 +0900322
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100323 const HBUINT16 *endCount;
324 const HBUINT16 *startCount;
325 const HBUINT16 *idDelta;
326 const HBUINT16 *idRangeOffset;
327 const HBUINT16 *glyphIdArray;
Behdad Esfahbod23335de2016-02-24 20:27:13 +0900328 unsigned int segCount;
Behdad Esfahbodc8a47452014-05-09 19:55:51 -0400329 unsigned int glyphIdArrayLength;
Behdad Esfahbod23335de2016-02-24 20:27:13 +0900330 };
Behdad Esfahbodc8a47452014-05-09 19:55:51 -0400331
Behdad Esfahbod23335de2016-02-24 20:27:13 +0900332 inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
333 {
Behdad Esfahbod56e0fd32018-10-29 22:35:44 -0700334 accelerator_t accel (this);
Behdad Esfahbod23335de2016-02-24 20:27:13 +0900335 return accel.get_glyph_func (&accel, codepoint, glyph);
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400336 }
Behdad Esfahbodbd0e5422018-08-25 09:33:30 -0700337 inline void collect_unicodes (hb_set_t *out) const
338 {
Behdad Esfahbod56e0fd32018-10-29 22:35:44 -0700339 accelerator_t accel (this);
Behdad Esfahbodb41c43b2018-08-25 15:25:03 -0700340 accel.collect_unicodes (out);
Behdad Esfahbodbd0e5422018-08-25 09:33:30 -0700341 }
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400342
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300343 inline bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbod257d1ad2014-06-04 18:47:55 -0400344 {
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400345 TRACE_SANITIZE (this);
Behdad Esfahbod257d1ad2014-06-04 18:47:55 -0400346 if (unlikely (!c->check_struct (this)))
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100347 return_trace (false);
Behdad Esfahbod257d1ad2014-06-04 18:47:55 -0400348
349 if (unlikely (!c->check_range (this, length)))
350 {
351 /* Some broken fonts have too long of a "length" value.
352 * If that is the case, just change the value to truncate
353 * the subtable at the end of the blob. */
354 uint16_t new_length = (uint16_t) MIN ((uintptr_t) 65535,
355 (uintptr_t) (c->end -
356 (char *) this));
357 if (!c->try_set (&length, new_length))
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100358 return_trace (false);
Behdad Esfahbod257d1ad2014-06-04 18:47:55 -0400359 }
360
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100361 return_trace (16 + 4 * (unsigned int) segCountX2 <= length);
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400362 }
363
Garret Rieger295d67e2018-05-02 16:12:04 -0700364
365
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400366 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100367 HBUINT16 format; /* Format number is set to 4. */
368 HBUINT16 length; /* This is the length in bytes of the
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400369 * subtable. */
Behdad Esfahbod5b93f692018-05-02 14:59:14 -0400370 HBUINT16 language; /* Ignore. */
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100371 HBUINT16 segCountX2; /* 2 x segCount. */
Behdad Esfahbod5b93f692018-05-02 14:59:14 -0400372 HBUINT16 searchRange; /* 2 * (2**floor(log2(segCount))) */
373 HBUINT16 entrySelector; /* log2(searchRange/2) */
374 HBUINT16 rangeShift; /* 2 x segCount - searchRange */
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400375
Behdad Esfahboddff2c452018-09-10 23:29:26 +0200376 UnsizedArrayOf<HBUINT16>
377 values;
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400378#if 0
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100379 HBUINT16 endCount[segCount]; /* End characterCode for each segment,
Behdad Esfahbod76271002014-07-11 14:54:42 -0400380 * last=0xFFFFu. */
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100381 HBUINT16 reservedPad; /* Set to 0. */
382 HBUINT16 startCount[segCount]; /* Start character code for each segment. */
383 HBINT16 idDelta[segCount]; /* Delta for all character codes in segment. */
384 HBUINT16 idRangeOffset[segCount];/* Offsets into glyphIdArray or 0 */
Behdad Esfahboddff2c452018-09-10 23:29:26 +0200385 UnsizedArrayOf<HBUINT16>
386 glyphIdArray; /* Glyph index array (arbitrary length) */
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400387#endif
388
389 public:
390 DEFINE_SIZE_ARRAY (14, values);
391};
392
Behdad Esfahbodd294a2c2014-05-12 17:58:31 -0400393struct CmapSubtableLongGroup
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400394{
395 friend struct CmapSubtableFormat12;
Behdad Esfahbodd294a2c2014-05-12 17:58:31 -0400396 friend struct CmapSubtableFormat13;
Garret Rieger5dadbb02018-04-17 07:00:23 -0600397 template<typename U>
398 friend struct CmapSubtableLongSegmented;
Rod Sheeter1cd98d02018-02-08 19:39:57 -0800399 friend struct cmap;
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400400
401 int cmp (hb_codepoint_t codepoint) const
402 {
403 if (codepoint < startCharCode) return -1;
404 if (codepoint > endCharCode) return +1;
405 return 0;
406 }
407
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300408 inline bool sanitize (hb_sanitize_context_t *c) const
409 {
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400410 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100411 return_trace (c->check_struct (this));
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400412 }
413
414 private:
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100415 HBUINT32 startCharCode; /* First character code in this group. */
416 HBUINT32 endCharCode; /* Last character code in this group. */
417 HBUINT32 glyphID; /* Glyph index; interpretation depends on
Behdad Esfahbod7d382fa2018-08-25 09:35:45 -0700418 * subtable format. */
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400419 public:
420 DEFINE_SIZE_STATIC (12);
421};
422
Behdad Esfahbod94759e82014-05-13 21:17:28 -0400423template <typename UINT>
424struct CmapSubtableTrimmed
Behdad Esfahbod91bbfca2014-05-12 18:19:29 -0400425{
Behdad Esfahbod91bbfca2014-05-12 18:19:29 -0400426 inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
427 {
428 /* Rely on our implicit array bound-checking. */
429 hb_codepoint_t gid = glyphIdArray[codepoint - startCharCode];
430 if (!gid)
431 return false;
432 *glyph = gid;
Behdad Esfahbod2ccc3222018-08-29 16:38:04 -0700433 return true;
Behdad Esfahbod91bbfca2014-05-12 18:19:29 -0400434 }
Behdad Esfahbod7d382fa2018-08-25 09:35:45 -0700435 inline void collect_unicodes (hb_set_t *out) const
436 {
437 hb_codepoint_t start = startCharCode;
438 unsigned int count = glyphIdArray.len;
439 for (unsigned int i = 0; i < count; i++)
440 if (glyphIdArray[i])
441 out->add (start + i);
442 }
Behdad Esfahbod91bbfca2014-05-12 18:19:29 -0400443
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300444 inline bool sanitize (hb_sanitize_context_t *c) const
445 {
Behdad Esfahbod91bbfca2014-05-12 18:19:29 -0400446 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100447 return_trace (c->check_struct (this) && glyphIdArray.sanitize (c));
Behdad Esfahbod91bbfca2014-05-12 18:19:29 -0400448 }
449
450 protected:
Behdad Esfahbod94759e82014-05-13 21:17:28 -0400451 UINT formatReserved; /* Subtable format and (maybe) padding. */
Behdad Esfahbod5b93f692018-05-02 14:59:14 -0400452 UINT length; /* Byte length of this subtable. */
453 UINT language; /* Ignore. */
Behdad Esfahbod94759e82014-05-13 21:17:28 -0400454 UINT startCharCode; /* First character code covered. */
Behdad Esfahbod9da552d2014-06-27 15:09:42 -0400455 ArrayOf<GlyphID, UINT>
Behdad Esfahbod91bbfca2014-05-12 18:19:29 -0400456 glyphIdArray; /* Array of glyph index values for character
457 * codes in the range. */
458 public:
Behdad Esfahbod94759e82014-05-13 21:17:28 -0400459 DEFINE_SIZE_ARRAY (5 * sizeof (UINT), glyphIdArray);
Behdad Esfahbod91bbfca2014-05-12 18:19:29 -0400460};
461
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100462struct CmapSubtableFormat6 : CmapSubtableTrimmed<HBUINT16> {};
463struct CmapSubtableFormat10 : CmapSubtableTrimmed<HBUINT32 > {};
Behdad Esfahbod91bbfca2014-05-12 18:19:29 -0400464
Behdad Esfahbodca7b7742014-05-13 21:26:34 -0400465template <typename T>
466struct CmapSubtableLongSegmented
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400467{
Rod Sheeter9275bd02018-02-09 17:33:34 -0800468 friend struct cmap;
469
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400470 inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
471 {
Behdad Esfahboddf554af2014-06-19 15:39:18 -0400472 int i = groups.bsearch (codepoint);
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400473 if (i == -1)
474 return false;
Behdad Esfahbod2ccc3222018-08-29 16:38:04 -0700475 hb_codepoint_t gid = T::group_get_glyph (groups[i], codepoint);
476 if (!gid)
477 return false;
478 *glyph = gid;
479 return true;
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400480 }
481
Behdad Esfahbodd60c4652018-08-25 08:47:06 -0700482 inline void collect_unicodes (hb_set_t *out) const
Garret Rieger5dadbb02018-04-17 07:00:23 -0600483 {
484 for (unsigned int i = 0; i < this->groups.len; i++) {
Behdad Esfahbod1dcf5fb2018-08-25 16:11:26 -0700485 out->add_range (this->groups[i].startCharCode,
486 MIN ((hb_codepoint_t) this->groups[i].endCharCode,
Behdad Esfahbod82b12bc2018-08-25 22:07:17 -0700487 (hb_codepoint_t) HB_UNICODE_MAX));
Garret Rieger5dadbb02018-04-17 07:00:23 -0600488 }
489 }
490
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300491 inline bool sanitize (hb_sanitize_context_t *c) const
492 {
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400493 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100494 return_trace (c->check_struct (this) && groups.sanitize (c));
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400495 }
496
Behdad Esfahbod6fa690c2018-02-18 16:27:59 -0800497 inline bool serialize (hb_serialize_context_t *c,
Garret Rieger0053d132018-05-02 15:42:43 -0700498 const hb_vector_t<CmapSubtableLongGroup> &group_data)
Rod Sheeter9275bd02018-02-09 17:33:34 -0800499 {
500 TRACE_SERIALIZE (this);
Behdad Esfahbod6fa690c2018-02-18 16:27:59 -0800501 if (unlikely (!c->extend_min (*this))) return_trace (false);
Behdad Esfahbod955aa562018-10-25 16:50:38 -0700502 Supplier<CmapSubtableLongGroup> supplier (group_data, group_data.len);
Behdad Esfahbod6fa690c2018-02-18 16:27:59 -0800503 if (unlikely (!groups.serialize (c, supplier, group_data.len))) return_trace (false);
Rod Sheeter9275bd02018-02-09 17:33:34 -0800504 return true;
505 }
506
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400507 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100508 HBUINT16 format; /* Subtable format; set to 12. */
Behdad Esfahbod5b93f692018-05-02 14:59:14 -0400509 HBUINT16 reserved; /* Reserved; set to 0. */
510 HBUINT32 length; /* Byte length of this subtable. */
511 HBUINT32 language; /* Ignore. */
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100512 SortedArrayOf<CmapSubtableLongGroup, HBUINT32>
Behdad Esfahbodd294a2c2014-05-12 17:58:31 -0400513 groups; /* Groupings. */
514 public:
515 DEFINE_SIZE_ARRAY (16, groups);
516};
517
Behdad Esfahbodca7b7742014-05-13 21:26:34 -0400518struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
Behdad Esfahbodd294a2c2014-05-12 17:58:31 -0400519{
Behdad Esfahbodca7b7742014-05-13 21:26:34 -0400520 static inline hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
521 hb_codepoint_t u)
522 { return group.glyphID + (u - group.startCharCode); }
Garret Rieger0053d132018-05-02 15:42:43 -0700523
524
525 bool serialize (hb_serialize_context_t *c,
526 const hb_vector_t<CmapSubtableLongGroup> &groups)
527 {
528 if (unlikely (!c->extend_min (*this))) return false;
529
530 this->format.set (12);
Garret Rieger3be050f2018-05-04 11:23:32 -0700531 this->reserved.set (0);
532 this->length.set (get_sub_table_size (groups));
Garret Rieger0053d132018-05-02 15:42:43 -0700533
Garret Rieger7c22f982018-05-03 13:14:28 -0700534 return CmapSubtableLongSegmented<CmapSubtableFormat12>::serialize (c, groups);
Garret Rieger0053d132018-05-02 15:42:43 -0700535 }
536
537 static inline size_t get_sub_table_size (const hb_vector_t<CmapSubtableLongGroup> &groups)
538 {
539 return 16 + 12 * groups.len;
540 }
541
542 static inline bool create_sub_table_plan (const hb_subset_plan_t *plan,
543 hb_vector_t<CmapSubtableLongGroup> *groups)
544 {
545 CmapSubtableLongGroup *group = nullptr;
Garret Rieger0053d132018-05-02 15:42:43 -0700546
Garret Rieger251cc972018-05-30 12:23:51 -0700547 hb_codepoint_t cp = HB_SET_VALUE_INVALID;
548 while (plan->unicodes->next (&cp)) {
Garret Rieger0053d132018-05-02 15:42:43 -0700549 hb_codepoint_t new_gid;
Garret Rieger251cc972018-05-30 12:23:51 -0700550 if (unlikely (!plan->new_gid_for_codepoint (cp, &new_gid)))
Garret Rieger0053d132018-05-02 15:42:43 -0700551 {
552 DEBUG_MSG(SUBSET, nullptr, "Unable to find new gid for %04x", cp);
553 return false;
554 }
555
556 if (!group || !_is_gid_consecutive (group, cp, new_gid))
557 {
558 group = groups->push ();
559 group->startCharCode.set (cp);
560 group->endCharCode.set (cp);
561 group->glyphID.set (new_gid);
562 } else
563 {
564 group->endCharCode.set (cp);
565 }
566 }
567
568 DEBUG_MSG(SUBSET, nullptr, "cmap");
569 for (unsigned int i = 0; i < groups->len; i++) {
570 CmapSubtableLongGroup& group = (*groups)[i];
571 DEBUG_MSG(SUBSET, nullptr, " %d: U+%04X-U+%04X, gid %d-%d", i, (uint32_t) group.startCharCode, (uint32_t) group.endCharCode, (uint32_t) group.glyphID, (uint32_t) group.glyphID + ((uint32_t) group.endCharCode - (uint32_t) group.startCharCode));
572 }
573
574 return true;
575 }
576
577 private:
578 static inline bool _is_gid_consecutive (CmapSubtableLongGroup *group,
579 hb_codepoint_t cp,
580 hb_codepoint_t new_gid)
581 {
582 return (cp - 1 == group->endCharCode) &&
583 new_gid == group->glyphID + (cp - group->startCharCode);
584 }
585
Behdad Esfahbodca7b7742014-05-13 21:26:34 -0400586};
Behdad Esfahbodd294a2c2014-05-12 17:58:31 -0400587
Behdad Esfahbodca7b7742014-05-13 21:26:34 -0400588struct CmapSubtableFormat13 : CmapSubtableLongSegmented<CmapSubtableFormat13>
589{
590 static inline hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
591 hb_codepoint_t u HB_UNUSED)
592 { return group.glyphID; }
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400593};
594
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400595typedef enum
596{
597 GLYPH_VARIANT_NOT_FOUND = 0,
598 GLYPH_VARIANT_FOUND = 1,
599 GLYPH_VARIANT_USE_DEFAULT = 2
600} glyph_variant_t;
601
602struct UnicodeValueRange
603{
604 inline int cmp (const hb_codepoint_t &codepoint) const
605 {
606 if (codepoint < startUnicodeValue) return -1;
607 if (codepoint > startUnicodeValue + additionalCount) return +1;
608 return 0;
609 }
610
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300611 inline bool sanitize (hb_sanitize_context_t *c) const
612 {
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400613 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100614 return_trace (c->check_struct (this));
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400615 }
616
Ebrahim Byagowi435b1872018-04-15 21:18:48 +0430617 HBUINT24 startUnicodeValue; /* First value in this range. */
Behdad Esfahbod4806b382018-08-25 15:56:07 -0700618 HBUINT8 additionalCount; /* Number of additional values in this
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400619 * range. */
620 public:
621 DEFINE_SIZE_STATIC (4);
622};
623
Behdad Esfahbod1dcf5fb2018-08-25 16:11:26 -0700624struct DefaultUVS : SortedArrayOf<UnicodeValueRange, HBUINT32>
625{
626 inline void collect_unicodes (hb_set_t *out) const
627 {
628 unsigned int count = len;
629 for (unsigned int i = 0; i < count; i++)
630 {
631 hb_codepoint_t first = arrayZ[i].startUnicodeValue;
632 hb_codepoint_t last = MIN ((hb_codepoint_t) (first + arrayZ[i].additionalCount),
Behdad Esfahbod82b12bc2018-08-25 22:07:17 -0700633 (hb_codepoint_t) HB_UNICODE_MAX);
Behdad Esfahbod1dcf5fb2018-08-25 16:11:26 -0700634 out->add_range (first, last);
635 }
636 }
637
638 public:
Behdad Esfahbod1d66cdc2018-11-10 19:54:08 -0500639 DEFINE_SIZE_ARRAY (4, *this);
Behdad Esfahbod1dcf5fb2018-08-25 16:11:26 -0700640};
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400641
642struct UVSMapping
643{
644 inline int cmp (const hb_codepoint_t &codepoint) const
645 {
646 return unicodeValue.cmp (codepoint);
647 }
648
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300649 inline bool sanitize (hb_sanitize_context_t *c) const
650 {
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400651 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100652 return_trace (c->check_struct (this));
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400653 }
654
Ebrahim Byagowi435b1872018-04-15 21:18:48 +0430655 HBUINT24 unicodeValue; /* Base Unicode value of the UVS */
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400656 GlyphID glyphID; /* Glyph ID of the UVS */
657 public:
658 DEFINE_SIZE_STATIC (5);
659};
660
Behdad Esfahbod1dcf5fb2018-08-25 16:11:26 -0700661struct NonDefaultUVS : SortedArrayOf<UVSMapping, HBUINT32>
662{
663 inline void collect_unicodes (hb_set_t *out) const
664 {
665 unsigned int count = len;
666 for (unsigned int i = 0; i < count; i++)
667 out->add (arrayZ[i].glyphID);
668 }
669
670 public:
Behdad Esfahbod1d66cdc2018-11-10 19:54:08 -0500671 DEFINE_SIZE_ARRAY (4, *this);
Behdad Esfahbod1dcf5fb2018-08-25 16:11:26 -0700672};
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400673
674struct VariationSelectorRecord
675{
676 inline glyph_variant_t get_glyph (hb_codepoint_t codepoint,
677 hb_codepoint_t *glyph,
678 const void *base) const
679 {
680 int i;
681 const DefaultUVS &defaults = base+defaultUVS;
682 i = defaults.bsearch (codepoint);
683 if (i != -1)
684 return GLYPH_VARIANT_USE_DEFAULT;
685 const NonDefaultUVS &nonDefaults = base+nonDefaultUVS;
686 i = nonDefaults.bsearch (codepoint);
Behdad Esfahbod2ccc3222018-08-29 16:38:04 -0700687 if (i != -1 && nonDefaults[i].glyphID)
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400688 {
689 *glyph = nonDefaults[i].glyphID;
690 return GLYPH_VARIANT_FOUND;
691 }
692 return GLYPH_VARIANT_NOT_FOUND;
693 }
694
Behdad Esfahbod1dcf5fb2018-08-25 16:11:26 -0700695 inline void collect_unicodes (hb_set_t *out, const void *base) const
696 {
697 (base+defaultUVS).collect_unicodes (out);
698 (base+nonDefaultUVS).collect_unicodes (out);
699 }
700
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400701 inline int cmp (const hb_codepoint_t &variation_selector) const
702 {
703 return varSelector.cmp (variation_selector);
704 }
705
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300706 inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
707 {
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400708 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100709 return_trace (c->check_struct (this) &&
710 defaultUVS.sanitize (c, base) &&
711 nonDefaultUVS.sanitize (c, base));
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400712 }
713
Ebrahim Byagowi435b1872018-04-15 21:18:48 +0430714 HBUINT24 varSelector; /* Variation selector. */
Behdad Esfahbod5e156fa2017-01-22 20:28:56 -0800715 LOffsetTo<DefaultUVS>
Ebrahim Byagowi63109432018-10-13 14:00:05 +0330716 defaultUVS; /* Offset to Default UVS Table. May be 0. */
Behdad Esfahbod5e156fa2017-01-22 20:28:56 -0800717 LOffsetTo<NonDefaultUVS>
Ebrahim Byagowi63109432018-10-13 14:00:05 +0330718 nonDefaultUVS; /* Offset to Non-Default UVS Table. May be 0. */
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400719 public:
720 DEFINE_SIZE_STATIC (11);
721};
722
723struct CmapSubtableFormat14
724{
725 inline glyph_variant_t get_glyph_variant (hb_codepoint_t codepoint,
726 hb_codepoint_t variation_selector,
727 hb_codepoint_t *glyph) const
728 {
Behdad Esfahbod1dcf5fb2018-08-25 16:11:26 -0700729 return record[record.bsearch (variation_selector)].get_glyph (codepoint, glyph, this);
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400730 }
731
Behdad Esfahbod4806b382018-08-25 15:56:07 -0700732 inline void collect_variation_selectors (hb_set_t *out) const
733 {
734 unsigned int count = record.len;
735 for (unsigned int i = 0; i < count; i++)
736 out->add (record.arrayZ[i].varSelector);
737 }
Behdad Esfahbod1dcf5fb2018-08-25 16:11:26 -0700738 inline void collect_variation_unicodes (hb_codepoint_t variation_selector,
739 hb_set_t *out) const
740 {
741 record[record.bsearch (variation_selector)].collect_unicodes (out, this);
742 }
Behdad Esfahbod4806b382018-08-25 15:56:07 -0700743
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300744 inline bool sanitize (hb_sanitize_context_t *c) const
745 {
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400746 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100747 return_trace (c->check_struct (this) &&
748 record.sanitize (c, this));
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400749 }
750
751 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100752 HBUINT16 format; /* Format number is set to 14. */
Behdad Esfahbod5b93f692018-05-02 14:59:14 -0400753 HBUINT32 length; /* Byte length of this subtable. */
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100754 SortedArrayOf<VariationSelectorRecord, HBUINT32>
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400755 record; /* Variation selector records; sorted
756 * in increasing order of `varSelector'. */
757 public:
758 DEFINE_SIZE_ARRAY (10, record);
759};
760
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400761struct CmapSubtable
762{
Behdad Esfahbodc9558762014-05-14 00:42:18 -0400763 /* Note: We intentionally do NOT implement subtable formats 2 and 8. */
764
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400765 inline bool get_glyph (hb_codepoint_t codepoint,
766 hb_codepoint_t *glyph) const
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400767 {
768 switch (u.format) {
Rod Sheeter1725c352018-02-14 19:36:33 -0800769 case 0: return u.format0 .get_glyph (codepoint, glyph);
770 case 4: return u.format4 .get_glyph (codepoint, glyph);
771 case 6: return u.format6 .get_glyph (codepoint, glyph);
772 case 10: return u.format10.get_glyph (codepoint, glyph);
773 case 12: return u.format12.get_glyph (codepoint, glyph);
774 case 13: return u.format13.get_glyph (codepoint, glyph);
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400775 case 14:
776 default: return false;
777 }
778 }
Behdad Esfahbodbd0e5422018-08-25 09:33:30 -0700779 inline void collect_unicodes (hb_set_t *out) const
780 {
781 switch (u.format) {
Behdad Esfahbod7d382fa2018-08-25 09:35:45 -0700782 case 0: u.format0 .collect_unicodes (out); return;
Behdad Esfahbodbd0e5422018-08-25 09:33:30 -0700783 case 4: u.format4 .collect_unicodes (out); return;
Behdad Esfahbod7d382fa2018-08-25 09:35:45 -0700784 case 6: u.format6 .collect_unicodes (out); return;
785 case 10: u.format10.collect_unicodes (out); return;
Behdad Esfahbodbd0e5422018-08-25 09:33:30 -0700786 case 12: u.format12.collect_unicodes (out); return;
787 case 13: u.format13.collect_unicodes (out); return;
788 case 14:
789 default: return;
790 }
791 }
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400792
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300793 inline bool sanitize (hb_sanitize_context_t *c) const
794 {
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400795 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100796 if (!u.format.sanitize (c)) return_trace (false);
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400797 switch (u.format) {
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100798 case 0: return_trace (u.format0 .sanitize (c));
799 case 4: return_trace (u.format4 .sanitize (c));
800 case 6: return_trace (u.format6 .sanitize (c));
801 case 10: return_trace (u.format10.sanitize (c));
802 case 12: return_trace (u.format12.sanitize (c));
803 case 13: return_trace (u.format13.sanitize (c));
804 case 14: return_trace (u.format14.sanitize (c));
805 default:return_trace (true);
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400806 }
807 }
808
Behdad Esfahbod5473ebf2016-02-24 19:32:43 +0900809 public:
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400810 union {
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100811 HBUINT16 format; /* Format identifier */
Behdad Esfahbodb7878cd2014-05-13 21:47:51 -0400812 CmapSubtableFormat0 format0;
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400813 CmapSubtableFormat4 format4;
Behdad Esfahbod91bbfca2014-05-12 18:19:29 -0400814 CmapSubtableFormat6 format6;
815 CmapSubtableFormat10 format10;
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400816 CmapSubtableFormat12 format12;
Behdad Esfahbodd294a2c2014-05-12 17:58:31 -0400817 CmapSubtableFormat13 format13;
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400818 CmapSubtableFormat14 format14;
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400819 } u;
820 public:
821 DEFINE_SIZE_UNION (2, format);
822};
823
824
825struct EncodingRecord
826{
Behdad Esfahbodf1a72fe2014-06-04 19:00:29 -0400827 inline int cmp (const EncodingRecord &other) const
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400828 {
829 int ret;
Behdad Esfahbodf1a72fe2014-06-04 19:00:29 -0400830 ret = platformID.cmp (other.platformID);
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400831 if (ret) return ret;
Behdad Esfahbodf1a72fe2014-06-04 19:00:29 -0400832 ret = encodingID.cmp (other.encodingID);
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400833 if (ret) return ret;
834 return 0;
835 }
836
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300837 inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
838 {
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400839 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100840 return_trace (c->check_struct (this) &&
841 subtable.sanitize (c, base));
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400842 }
843
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100844 HBUINT16 platformID; /* Platform ID. */
845 HBUINT16 encodingID; /* Platform-specific encoding ID. */
Behdad Esfahbod5e156fa2017-01-22 20:28:56 -0800846 LOffsetTo<CmapSubtable>
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400847 subtable; /* Byte offset from beginning of table to the subtable for this encoding. */
848 public:
849 DEFINE_SIZE_STATIC (8);
850};
851
852struct cmap
853{
854 static const hb_tag_t tableTag = HB_OT_TAG_cmap;
855
Behdad Esfahbode6cb9382018-08-26 00:21:29 -0700856 struct subset_plan
857 {
Garret Rieger0053d132018-05-02 15:42:43 -0700858 inline size_t final_size() const
859 {
Garret Rieger9ef55a42018-05-02 18:50:56 -0700860 return 4 // header
Garret Riegerc8179922018-05-03 10:53:20 -0700861 + 8 * 3 // 3 EncodingRecord
Garret Rieger9ef55a42018-05-02 18:50:56 -0700862 + CmapSubtableFormat4::get_sub_table_size (this->format4_segments)
863 + CmapSubtableFormat12::get_sub_table_size (this->format12_groups);
Garret Rieger0053d132018-05-02 15:42:43 -0700864 }
865
Behdad Esfahbod3a4e5dd2018-10-29 18:05:25 -0700866 hb_vector_t<CmapSubtableFormat4::segment_plan> format4_segments;
867 hb_vector_t<CmapSubtableLongGroup> format12_groups;
Garret Rieger0053d132018-05-02 15:42:43 -0700868 };
869
Behdad Esfahbod977ddff2017-11-14 20:06:19 -0800870 inline bool sanitize (hb_sanitize_context_t *c) const
871 {
872 TRACE_SANITIZE (this);
873 return_trace (c->check_struct (this) &&
874 likely (version == 0) &&
875 encodingRecord.sanitize (c, this));
876 }
877
Garret Rieger0053d132018-05-02 15:42:43 -0700878 inline bool _create_plan (const hb_subset_plan_t *plan,
879 subset_plan *cmap_plan) const
Garret Rieger5e318e02018-04-18 17:13:37 -0700880 {
Garret Rieger295d67e2018-05-02 16:12:04 -0700881 if (unlikely( !CmapSubtableFormat4::create_sub_table_plan (plan, &cmap_plan->format4_segments)))
882 return false;
883
884 return CmapSubtableFormat12::create_sub_table_plan (plan, &cmap_plan->format12_groups);
Garret Rieger5e318e02018-04-18 17:13:37 -0700885 }
886
Garret Rieger295d67e2018-05-02 16:12:04 -0700887 inline bool _subset (const hb_subset_plan_t *plan,
888 const subset_plan &cmap_subset_plan,
Behdad Esfahbodb1bd0b52018-02-14 18:50:19 -0800889 size_t dest_sz,
890 void *dest) const
Rod Sheeter9275bd02018-02-09 17:33:34 -0800891 {
Behdad Esfahbod6fa690c2018-02-18 16:27:59 -0800892 hb_serialize_context_t c (dest, dest_sz);
Rod Sheeter9275bd02018-02-09 17:33:34 -0800893
Behdad Esfahbode57a6382018-07-23 12:00:02 -0700894 cmap *table = c.start_serialize<cmap> ();
895 if (unlikely (!c.extend_min (*table)))
Rod Sheeter9275bd02018-02-09 17:33:34 -0800896 {
897 return false;
898 }
899
Behdad Esfahbode57a6382018-07-23 12:00:02 -0700900 table->version.set (0);
Rod Sheeter9275bd02018-02-09 17:33:34 -0800901
Behdad Esfahbode57a6382018-07-23 12:00:02 -0700902 if (unlikely (!table->encodingRecord.serialize (&c, /* numTables */ 3)))
Garret Rieger9ef55a42018-05-02 18:50:56 -0700903 return false;
Rod Sheeter9275bd02018-02-09 17:33:34 -0800904
Garret Rieger295d67e2018-05-02 16:12:04 -0700905 // TODO(grieger): Convert the below to a for loop
Rod Sheeter9275bd02018-02-09 17:33:34 -0800906
Garret Riegerc8179922018-05-03 10:53:20 -0700907 // Format 4, Plat 0 Encoding Record
Behdad Esfahbode57a6382018-07-23 12:00:02 -0700908 EncodingRecord &format4_plat0_rec = table->encodingRecord[0];
Garret Riegerc8179922018-05-03 10:53:20 -0700909 format4_plat0_rec.platformID.set (0); // Unicode
910 format4_plat0_rec.encodingID.set (3);
Rod Sheeter0301e5b2018-02-12 10:12:11 -0800911
Garret Riegerc8179922018-05-03 10:53:20 -0700912 // Format 4, Plat 3 Encoding Record
Behdad Esfahbode57a6382018-07-23 12:00:02 -0700913 EncodingRecord &format4_plat3_rec = table->encodingRecord[1];
Garret Riegerc8179922018-05-03 10:53:20 -0700914 format4_plat3_rec.platformID.set (3); // Windows
915 format4_plat3_rec.encodingID.set (1); // Unicode BMP
Rod Sheeter9275bd02018-02-09 17:33:34 -0800916
Garret Rieger295d67e2018-05-02 16:12:04 -0700917 // Format 12 Encoding Record
Behdad Esfahbode57a6382018-07-23 12:00:02 -0700918 EncodingRecord &format12_rec = table->encodingRecord[2];
Garret Rieger295d67e2018-05-02 16:12:04 -0700919 format12_rec.platformID.set (3); // Windows
920 format12_rec.encodingID.set (10); // Unicode UCS-4
Rod Sheeter0301e5b2018-02-12 10:12:11 -0800921
Garret Riegerc8179922018-05-03 10:53:20 -0700922 // Write out format 4 sub table
Garret Rieger295d67e2018-05-02 16:12:04 -0700923 {
Behdad Esfahbode57a6382018-07-23 12:00:02 -0700924 CmapSubtable &subtable = format4_plat0_rec.subtable.serialize (&c, table);
Garret Riegerc8179922018-05-03 10:53:20 -0700925 format4_plat3_rec.subtable.set (format4_plat0_rec.subtable);
Garret Rieger295d67e2018-05-02 16:12:04 -0700926 subtable.u.format.set (4);
Rod Sheeter9275bd02018-02-09 17:33:34 -0800927
Garret Rieger295d67e2018-05-02 16:12:04 -0700928 CmapSubtableFormat4 &format4 = subtable.u.format4;
Garret Rieger9ef55a42018-05-02 18:50:56 -0700929 if (unlikely (!format4.serialize (&c, plan, cmap_subset_plan.format4_segments)))
930 return false;
Garret Rieger295d67e2018-05-02 16:12:04 -0700931 }
Rod Sheeter9275bd02018-02-09 17:33:34 -0800932
Garret Rieger0053d132018-05-02 15:42:43 -0700933 // Write out format 12 sub table.
Garret Rieger295d67e2018-05-02 16:12:04 -0700934 {
Behdad Esfahbode57a6382018-07-23 12:00:02 -0700935 CmapSubtable &subtable = format12_rec.subtable.serialize (&c, table);
Garret Rieger295d67e2018-05-02 16:12:04 -0700936 subtable.u.format.set (12);
Rod Sheeter9275bd02018-02-09 17:33:34 -0800937
Garret Rieger295d67e2018-05-02 16:12:04 -0700938 CmapSubtableFormat12 &format12 = subtable.u.format12;
Garret Rieger9ef55a42018-05-02 18:50:56 -0700939 if (unlikely (!format12.serialize (&c, cmap_subset_plan.format12_groups)))
940 return false;
Garret Rieger295d67e2018-05-02 16:12:04 -0700941 }
Rod Sheeter9275bd02018-02-09 17:33:34 -0800942
Behdad Esfahbod6fa690c2018-02-18 16:27:59 -0800943 c.end_serialize ();
Rod Sheeter0301e5b2018-02-12 10:12:11 -0800944
Rod Sheeter0859a002018-02-07 15:59:36 -0800945 return true;
946 }
947
Rod Sheeter3ed70e52018-02-14 15:24:49 -0800948 inline bool subset (hb_subset_plan_t *plan) const
Rod Sheeter9275bd02018-02-09 17:33:34 -0800949 {
Garret Rieger0053d132018-05-02 15:42:43 -0700950 subset_plan cmap_subset_plan;
Rod Sheeter9275bd02018-02-09 17:33:34 -0800951
Garret Rieger0053d132018-05-02 15:42:43 -0700952 if (unlikely (!_create_plan (plan, &cmap_subset_plan)))
953 {
954 DEBUG_MSG(SUBSET, nullptr, "Failed to generate a cmap subsetting plan.");
955 return false;
956 }
Rod Sheeter9275bd02018-02-09 17:33:34 -0800957
958 // We now know how big our blob needs to be
Garret Rieger0053d132018-05-02 15:42:43 -0700959 size_t dest_sz = cmap_subset_plan.final_size();
Garret Rieger0fb8a5c2018-02-23 15:37:43 -0800960 void *dest = malloc (dest_sz);
Rod Sheeter1725c352018-02-14 19:36:33 -0800961 if (unlikely (!dest)) {
Behdad Esfahbodd1f16fc2018-02-20 10:32:09 -0800962 DEBUG_MSG(SUBSET, nullptr, "Unable to alloc %lu for cmap subset output", (unsigned long) dest_sz);
Rod Sheeterfa877702018-02-14 14:16:25 -0800963 return false;
Rod Sheeter9275bd02018-02-09 17:33:34 -0800964 }
965
Garret Rieger295d67e2018-05-02 16:12:04 -0700966 if (unlikely (!_subset (plan, cmap_subset_plan, dest_sz, dest)))
Rod Sheeter9275bd02018-02-09 17:33:34 -0800967 {
Garret Rieger0053d132018-05-02 15:42:43 -0700968 DEBUG_MSG(SUBSET, nullptr, "Failed to perform subsetting of cmap.");
Rod Sheeter1725c352018-02-14 19:36:33 -0800969 free (dest);
Rod Sheeterfa877702018-02-14 14:16:25 -0800970 return false;
Rod Sheeter9275bd02018-02-09 17:33:34 -0800971 }
972
973 // all done, write the blob into dest
Rod Sheeterfa877702018-02-14 14:16:25 -0800974 hb_blob_t *cmap_prime = hb_blob_create ((const char *)dest,
975 dest_sz,
976 HB_MEMORY_MODE_READONLY,
Garret Rieger0fb8a5c2018-02-23 15:37:43 -0800977 dest,
Rod Sheeterfa877702018-02-14 14:16:25 -0800978 free);
Garret Rieger251cc972018-05-30 12:23:51 -0700979 bool result = plan->add_table (HB_OT_TAG_cmap, cmap_prime);
Garret Rieger0fb8a5c2018-02-23 15:37:43 -0800980 hb_blob_destroy (cmap_prime);
981 return result;
Rod Sheeter9275bd02018-02-09 17:33:34 -0800982 }
983
Behdad Esfahbod02fe03e2018-08-25 15:33:05 -0700984 const CmapSubtable *find_best_subtable (bool *symbol = nullptr) const
985 {
986 if (symbol) *symbol = false;
987
988 const CmapSubtable *subtable;
989
990 /* 32-bit subtables. */
991 if ((subtable = this->find_subtable (3, 10))) return subtable;
992 if ((subtable = this->find_subtable (0, 6))) return subtable;
993 if ((subtable = this->find_subtable (0, 4))) return subtable;
994
995 /* 16-bit subtables. */
996 if ((subtable = this->find_subtable (3, 1))) return subtable;
997 if ((subtable = this->find_subtable (0, 3))) return subtable;
998 if ((subtable = this->find_subtable (0, 2))) return subtable;
999 if ((subtable = this->find_subtable (0, 1))) return subtable;
1000 if ((subtable = this->find_subtable (0, 0))) return subtable;
1001
1002 /* Symbol subtable. */
1003 if ((subtable = this->find_subtable (3, 0)))
1004 {
1005 if (symbol) *symbol = true;
1006 return subtable;
1007 }
1008
1009 /* Meh. */
1010 return &Null(CmapSubtable);
1011 }
1012
Behdad Esfahbod977ddff2017-11-14 20:06:19 -08001013 struct accelerator_t
1014 {
1015 inline void init (hb_face_t *face)
1016 {
Behdad Esfahbod0e2680a2018-11-11 00:28:47 -05001017 this->table = hb_sanitize_context_t().reference_table<cmap> (face);
Behdad Esfahbod02fe03e2018-08-25 15:33:05 -07001018 bool symbol;
Behdad Esfahbod36d85dc2018-11-05 19:46:29 -05001019 this->subtable = table->find_best_subtable (&symbol);
1020 this->subtable_uvs = &Null(CmapSubtableFormat14);
Behdad Esfahbod977ddff2017-11-14 20:06:19 -08001021 {
Behdad Esfahbode57a6382018-07-23 12:00:02 -07001022 const CmapSubtable *st = table->find_subtable (0, 5);
Behdad Esfahbod977ddff2017-11-14 20:06:19 -08001023 if (st && st->u.format == 14)
Behdad Esfahbod36d85dc2018-11-05 19:46:29 -05001024 subtable_uvs = &st->u.format14;
Behdad Esfahbod977ddff2017-11-14 20:06:19 -08001025 }
Behdad Esfahbod977ddff2017-11-14 20:06:19 -08001026
Behdad Esfahbod36d85dc2018-11-05 19:46:29 -05001027 this->get_glyph_data = subtable;
Behdad Esfahbod977ddff2017-11-14 20:06:19 -08001028 if (unlikely (symbol))
Garret Rieger21a181a2018-04-10 15:40:24 -07001029 {
Behdad Esfahbodbb380ec2018-11-05 13:45:12 -05001030 this->get_glyph_funcZ = get_glyph_from_symbol<CmapSubtable>;
Garret Rieger21a181a2018-04-10 15:40:24 -07001031 } else {
Behdad Esfahbod36d85dc2018-11-05 19:46:29 -05001032 switch (subtable->u.format) {
Behdad Esfahbod977ddff2017-11-14 20:06:19 -08001033 /* Accelerate format 4 and format 12. */
Garret Rieger21a181a2018-04-10 15:40:24 -07001034 default:
Behdad Esfahbodbb380ec2018-11-05 13:45:12 -05001035 this->get_glyph_funcZ = get_glyph_from<CmapSubtable>;
Garret Rieger21a181a2018-04-10 15:40:24 -07001036 break;
1037 case 12:
Behdad Esfahbodbb380ec2018-11-05 13:45:12 -05001038 this->get_glyph_funcZ = get_glyph_from<CmapSubtableFormat12>;
Garret Rieger21a181a2018-04-10 15:40:24 -07001039 break;
Behdad Esfahbod977ddff2017-11-14 20:06:19 -08001040 case 4:
1041 {
Behdad Esfahbod36d85dc2018-11-05 19:46:29 -05001042 this->format4_accel.init (&subtable->u.format4);
Behdad Esfahbod977ddff2017-11-14 20:06:19 -08001043 this->get_glyph_data = &this->format4_accel;
Behdad Esfahbodbb380ec2018-11-05 13:45:12 -05001044 this->get_glyph_funcZ = this->format4_accel.get_glyph_func;
Behdad Esfahbod977ddff2017-11-14 20:06:19 -08001045 }
1046 break;
1047 }
Garret Rieger21a181a2018-04-10 15:40:24 -07001048 }
Behdad Esfahbod977ddff2017-11-14 20:06:19 -08001049 }
1050
1051 inline void fini (void)
1052 {
Behdad Esfahbod0e2680a2018-11-11 00:28:47 -05001053 hb_blob_destroy (this->table.get_blob ());
Behdad Esfahbod977ddff2017-11-14 20:06:19 -08001054 }
1055
1056 inline bool get_nominal_glyph (hb_codepoint_t unicode,
1057 hb_codepoint_t *glyph) const
1058 {
Behdad Esfahbodbb380ec2018-11-05 13:45:12 -05001059 if (unlikely (!this->get_glyph_funcZ)) return false;
1060 return this->get_glyph_funcZ (this->get_glyph_data, unicode, glyph);
Behdad Esfahbod977ddff2017-11-14 20:06:19 -08001061 }
Behdad Esfahbod56ba9982018-11-05 19:49:54 -05001062 inline unsigned int get_nominal_glyphs (unsigned int count,
1063 const hb_codepoint_t *first_unicode,
1064 unsigned int unicode_stride,
1065 hb_codepoint_t *first_glyph,
1066 unsigned int glyph_stride) const
1067 {
1068 if (unlikely (!this->get_glyph_funcZ)) return 0;
1069
1070 hb_cmap_get_glyph_func_t get_glyph_funcZ = this->get_glyph_funcZ;
1071 const void *get_glyph_data = this->get_glyph_data;
1072
1073 unsigned int done;
1074 for (done = 0;
1075 done < count && get_glyph_funcZ (get_glyph_data, *first_unicode, first_glyph);
1076 done++)
1077 {
1078 first_unicode = &StructAtOffset<hb_codepoint_t> (first_unicode, unicode_stride);
1079 first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
1080 }
1081 return done;
1082 }
Behdad Esfahbod977ddff2017-11-14 20:06:19 -08001083
1084 inline bool get_variation_glyph (hb_codepoint_t unicode,
1085 hb_codepoint_t variation_selector,
1086 hb_codepoint_t *glyph) const
1087 {
Behdad Esfahbod36d85dc2018-11-05 19:46:29 -05001088 switch (this->subtable_uvs->get_glyph_variant (unicode,
1089 variation_selector,
1090 glyph))
Behdad Esfahbod977ddff2017-11-14 20:06:19 -08001091 {
Behdad Esfahbod36ed1632018-07-23 11:57:45 -07001092 case GLYPH_VARIANT_NOT_FOUND: return false;
1093 case GLYPH_VARIANT_FOUND: return true;
1094 case GLYPH_VARIANT_USE_DEFAULT: break;
Behdad Esfahbod977ddff2017-11-14 20:06:19 -08001095 }
1096
1097 return get_nominal_glyph (unicode, glyph);
1098 }
1099
Behdad Esfahbodd60c4652018-08-25 08:47:06 -07001100 inline void collect_unicodes (hb_set_t *out) const
Garret Rieger21a181a2018-04-10 15:40:24 -07001101 {
Behdad Esfahbod36d85dc2018-11-05 19:46:29 -05001102 subtable->collect_unicodes (out);
Garret Rieger21a181a2018-04-10 15:40:24 -07001103 }
Behdad Esfahbod4806b382018-08-25 15:56:07 -07001104 inline void collect_variation_selectors (hb_set_t *out) const
1105 {
Behdad Esfahbod36d85dc2018-11-05 19:46:29 -05001106 subtable_uvs->collect_variation_selectors (out);
Behdad Esfahbod4806b382018-08-25 15:56:07 -07001107 }
Behdad Esfahbod1dcf5fb2018-08-25 16:11:26 -07001108 inline void collect_variation_unicodes (hb_codepoint_t variation_selector,
1109 hb_set_t *out) const
1110 {
Behdad Esfahbod36d85dc2018-11-05 19:46:29 -05001111 subtable_uvs->collect_variation_unicodes (variation_selector, out);
Behdad Esfahbod1dcf5fb2018-08-25 16:11:26 -07001112 }
Garret Rieger21a181a2018-04-10 15:40:24 -07001113
Behdad Esfahbod977ddff2017-11-14 20:06:19 -08001114 protected:
1115 typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj,
1116 hb_codepoint_t codepoint,
1117 hb_codepoint_t *glyph);
Garret Rieger21a181a2018-04-10 15:40:24 -07001118
Behdad Esfahbod977ddff2017-11-14 20:06:19 -08001119 template <typename Type>
1120 static inline bool get_glyph_from (const void *obj,
1121 hb_codepoint_t codepoint,
1122 hb_codepoint_t *glyph)
1123 {
1124 const Type *typed_obj = (const Type *) obj;
1125 return typed_obj->get_glyph (codepoint, glyph);
1126 }
1127
1128 template <typename Type>
1129 static inline bool get_glyph_from_symbol (const void *obj,
1130 hb_codepoint_t codepoint,
1131 hb_codepoint_t *glyph)
1132 {
1133 const Type *typed_obj = (const Type *) obj;
1134 if (likely (typed_obj->get_glyph (codepoint, glyph)))
1135 return true;
1136
1137 if (codepoint <= 0x00FFu)
1138 {
1139 /* For symbol-encoded OpenType fonts, we duplicate the
1140 * U+F000..F0FF range at U+0000..U+00FF. That's what
1141 * Windows seems to do, and that's hinted about at:
Ebrahim Byagowif24b0b92018-04-12 13:40:45 +04301142 * https://docs.microsoft.com/en-us/typography/opentype/spec/recom
Behdad Esfahbod977ddff2017-11-14 20:06:19 -08001143 * under "Non-Standard (Symbol) Fonts". */
1144 return typed_obj->get_glyph (0xF000u + codepoint, glyph);
1145 }
1146
1147 return false;
1148 }
1149
1150 private:
Behdad Esfahbod36d85dc2018-11-05 19:46:29 -05001151 hb_nonnull_ptr_t<const CmapSubtable> subtable;
1152 hb_nonnull_ptr_t<const CmapSubtableFormat14> subtable_uvs;
Behdad Esfahbod4806b382018-08-25 15:56:07 -07001153
Behdad Esfahbodbb380ec2018-11-05 13:45:12 -05001154 hb_cmap_get_glyph_func_t get_glyph_funcZ;
Behdad Esfahbod977ddff2017-11-14 20:06:19 -08001155 const void *get_glyph_data;
Garret Rieger21a181a2018-04-10 15:40:24 -07001156
Behdad Esfahbod36ed1632018-07-23 11:57:45 -07001157 CmapSubtableFormat4::accelerator_t format4_accel;
Behdad Esfahbod977ddff2017-11-14 20:06:19 -08001158
Behdad Esfahbod0e2680a2018-11-11 00:28:47 -05001159 hb_blob_ptr_t<cmap> table;
Behdad Esfahbod977ddff2017-11-14 20:06:19 -08001160 };
1161
1162 protected:
1163
Behdad Esfahbod3608a682014-05-12 13:46:29 -04001164 inline const CmapSubtable *find_subtable (unsigned int platform_id,
1165 unsigned int encoding_id) const
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -04001166 {
1167 EncodingRecord key;
1168 key.platformID.set (platform_id);
1169 key.encodingID.set (encoding_id);
1170
Behdad Esfahbod1becabe2018-08-25 15:37:56 -07001171 int result = encodingRecord.bsearch (key);
Behdad Esfahbod500737e2014-06-04 18:17:29 -04001172 if (result == -1 || !encodingRecord[result].subtable)
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001173 return nullptr;
Behdad Esfahbod3608a682014-05-12 13:46:29 -04001174
1175 return &(this+encodingRecord[result].subtable);
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -04001176 }
1177
Behdad Esfahbod977ddff2017-11-14 20:06:19 -08001178 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001179 HBUINT16 version; /* Table version number (0). */
Behdad Esfahboddf554af2014-06-19 15:39:18 -04001180 SortedArrayOf<EncodingRecord>
Behdad Esfahbodf1a72fe2014-06-04 19:00:29 -04001181 encodingRecord; /* Encoding tables. */
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -04001182 public:
1183 DEFINE_SIZE_ARRAY (4, encodingRecord);
1184};
1185
Behdad Esfahbod3a0b3a22018-08-26 15:11:24 -07001186struct cmap_accelerator_t : cmap::accelerator_t {};
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -04001187
1188} /* namespace OT */
1189
1190
1191#endif /* HB_OT_CMAP_TABLE_HH */