blob: aca5de2e3bd224f428f0944094121f7b22bd4b8c [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"
Rod Sheeter0859a002018-02-07 15:59:36 -080032#include "hb-subset-plan.hh"
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -040033
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -040034/*
Ebrahim Byagowif24b0b92018-04-12 13:40:45 +043035 * cmap -- Character to Glyph Index Mapping
36 * https://docs.microsoft.com/en-us/typography/opentype/spec/cmap
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -040037 */
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -040038#define HB_OT_TAG_cmap HB_TAG('c','m','a','p')
39
Ebrahim Byagowif24b0b92018-04-12 13:40:45 +043040namespace OT {
41
42
Behdad Esfahbodb7878cd2014-05-13 21:47:51 -040043struct CmapSubtableFormat0
44{
Behdad Esfahbodb7878cd2014-05-13 21:47:51 -040045 inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
46 {
47 hb_codepoint_t gid = codepoint < 256 ? glyphIdArray[codepoint] : 0;
48 if (!gid)
49 return false;
50 *glyph = gid;
Behdad Esfahbod531051b2018-08-25 08:44:18 -070051 return *glyph != 0;
Behdad Esfahbodb7878cd2014-05-13 21:47:51 -040052 }
Behdad Esfahbod7d382fa2018-08-25 09:35:45 -070053 inline void collect_unicodes (hb_set_t *out) const
54 {
55 for (unsigned int i = 0; i < 256; i++)
56 if (glyphIdArray[i])
57 out->add (i);
58 }
Behdad Esfahbodb7878cd2014-05-13 21:47:51 -040059
Behdad Esfahbodde2118e2015-02-17 17:27:44 +030060 inline bool sanitize (hb_sanitize_context_t *c) const
61 {
Behdad Esfahbodb7878cd2014-05-13 21:47:51 -040062 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +010063 return_trace (c->check_struct (this));
Behdad Esfahbodb7878cd2014-05-13 21:47:51 -040064 }
65
66 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +010067 HBUINT16 format; /* Format number is set to 0. */
Behdad Esfahbod5b93f692018-05-02 14:59:14 -040068 HBUINT16 length; /* Byte length of this subtable. */
69 HBUINT16 language; /* Ignore. */
Behdad Esfahbod9aa2eb62018-02-11 19:00:42 -060070 HBUINT8 glyphIdArray[256];/* An array that maps character
Behdad Esfahbodb7878cd2014-05-13 21:47:51 -040071 * code to glyph index values. */
72 public:
73 DEFINE_SIZE_STATIC (6 + 256);
74};
75
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -040076struct CmapSubtableFormat4
77{
Garret Rieger295d67e2018-05-02 16:12:04 -070078 struct segment_plan
79 {
80 HBUINT16 start_code;
81 HBUINT16 end_code;
82 bool use_delta;
83 };
84
85 bool serialize (hb_serialize_context_t *c,
86 const hb_subset_plan_t *plan,
87 const hb_vector_t<segment_plan> &segments)
88 {
Garret Rieger4195a522018-05-02 17:11:18 -070089 TRACE_SERIALIZE (this);
90
91 if (unlikely (!c->extend_min (*this))) return_trace (false);
92
93 this->format.set (4);
94 this->length.set (get_sub_table_size (segments));
95
Garret Rieger4195a522018-05-02 17:11:18 -070096 this->segCountX2.set (segments.len * 2);
Behdad Esfahbodbddeb2b2018-07-10 14:12:37 +020097 this->entrySelector.set (MAX (1u, hb_bit_storage (segments.len)) - 1);
Garret Rieger3be050f2018-05-04 11:23:32 -070098 this->searchRange.set (2 * (1u << this->entrySelector));
99 this->rangeShift.set (segments.len * 2 > this->searchRange
100 ? 2 * segments.len - this->searchRange
101 : 0);
Garret Rieger4195a522018-05-02 17:11:18 -0700102
103 HBUINT16 *end_count = c->allocate_size<HBUINT16> (HBUINT16::static_size * segments.len);
104 c->allocate_size<HBUINT16> (HBUINT16::static_size); // 2 bytes of padding.
105 HBUINT16 *start_count = c->allocate_size<HBUINT16> (HBUINT16::static_size * segments.len);
106 HBINT16 *id_delta = c->allocate_size<HBINT16> (HBUINT16::static_size * segments.len);
107 HBUINT16 *id_range_offset = c->allocate_size<HBUINT16> (HBUINT16::static_size * segments.len);
108
Garret Rieger9ef55a42018-05-02 18:50:56 -0700109 if (id_range_offset == nullptr)
110 return_trace (false);
111
Garret Rieger4195a522018-05-02 17:11:18 -0700112 for (unsigned int i = 0; i < segments.len; i++)
113 {
114 end_count[i].set (segments[i].end_code);
115 start_count[i].set (segments[i].start_code);
116 if (segments[i].use_delta)
117 {
Garret Rieger9ef55a42018-05-02 18:50:56 -0700118 hb_codepoint_t cp = segments[i].start_code;
119 hb_codepoint_t start_gid = 0;
Garret Rieger251cc972018-05-30 12:23:51 -0700120 if (unlikely (!plan->new_gid_for_codepoint (cp, &start_gid) && cp != 0xFFFF))
Garret Rieger9ef55a42018-05-02 18:50:56 -0700121 return_trace (false);
Garret Rieger4195a522018-05-02 17:11:18 -0700122 id_delta[i].set (start_gid - segments[i].start_code);
123 } else {
Garret Rieger81ea75f2018-05-02 17:46:30 -0700124 id_delta[i].set (0);
125 unsigned int num_codepoints = segments[i].end_code - segments[i].start_code + 1;
126 HBUINT16 *glyph_id_array = c->allocate_size<HBUINT16> (HBUINT16::static_size * num_codepoints);
Garret Rieger9ef55a42018-05-02 18:50:56 -0700127 if (glyph_id_array == nullptr)
128 return_trace (false);
Garret Rieger81ea75f2018-05-02 17:46:30 -0700129 // From the cmap spec:
130 //
131 // id_range_offset[i]/2
132 // + (cp - segments[i].start_code)
133 // + (id_range_offset + i)
134 // =
135 // glyph_id_array + (cp - segments[i].start_code)
136 //
137 // So, solve for id_range_offset[i]:
138 //
139 // id_range_offset[i]
140 // =
141 // 2 * (glyph_id_array - id_range_offset - i)
142 id_range_offset[i].set (2 * (
143 glyph_id_array - id_range_offset - i));
144 for (unsigned int j = 0; j < num_codepoints; j++)
145 {
146 hb_codepoint_t cp = segments[i].start_code + j;
Garret Rieger9ef55a42018-05-02 18:50:56 -0700147 hb_codepoint_t new_gid;
Garret Rieger251cc972018-05-30 12:23:51 -0700148 if (unlikely (!plan->new_gid_for_codepoint (cp, &new_gid)))
Garret Rieger9ef55a42018-05-02 18:50:56 -0700149 return_trace (false);
Garret Rieger81ea75f2018-05-02 17:46:30 -0700150 glyph_id_array[j].set (new_gid);
151 }
Garret Rieger4195a522018-05-02 17:11:18 -0700152 }
153 }
154
Garret Rieger9ef55a42018-05-02 18:50:56 -0700155 return_trace (true);
Garret Rieger295d67e2018-05-02 16:12:04 -0700156 }
157
158 static inline size_t get_sub_table_size (const hb_vector_t<segment_plan> &segments)
159 {
160 size_t segment_size = 0;
161 for (unsigned int i = 0; i < segments.len; i++)
162 {
163 // Parallel array entries
164 segment_size +=
165 2 // end count
166 + 2 // start count
167 + 2 // delta
168 + 2; // range offset
169
170 if (!segments[i].use_delta)
171 // Add bytes for the glyph index array entries for this segment.
172 segment_size += (segments[i].end_code - segments[i].start_code + 1) * 2;
173 }
174
175 return min_size
176 + 2 // Padding
177 + segment_size;
178 }
179
180 static inline bool create_sub_table_plan (const hb_subset_plan_t *plan,
181 hb_vector_t<segment_plan> *segments)
182 {
Garret Riegercfa592d2018-05-02 16:37:38 -0700183 segment_plan *segment = nullptr;
184 hb_codepoint_t last_gid = 0;
Garret Rieger251cc972018-05-30 12:23:51 -0700185
186 hb_codepoint_t cp = HB_SET_VALUE_INVALID;
187 while (plan->unicodes->next (&cp)) {
Garret Riegercfa592d2018-05-02 16:37:38 -0700188 hb_codepoint_t new_gid;
Garret Rieger251cc972018-05-30 12:23:51 -0700189 if (unlikely (!plan->new_gid_for_codepoint (cp, &new_gid)))
Garret Riegercfa592d2018-05-02 16:37:38 -0700190 {
191 DEBUG_MSG(SUBSET, nullptr, "Unable to find new gid for %04x", cp);
192 return false;
193 }
194
195 if (cp > 0xFFFF) {
196 // We are now outside of unicode BMP, stop adding to this cmap.
197 break;
198 }
199
200 if (!segment
Behdad Esfahbode99d75e2018-05-09 15:28:30 -0700201 || cp != segment->end_code + 1u)
Garret Riegercfa592d2018-05-02 16:37:38 -0700202 {
203 segment = segments->push ();
204 segment->start_code.set (cp);
205 segment->end_code.set (cp);
206 segment->use_delta = true;
207 } else {
208 segment->end_code.set (cp);
Behdad Esfahbode99d75e2018-05-09 15:28:30 -0700209 if (last_gid + 1u != new_gid)
Garret Riegercfa592d2018-05-02 16:37:38 -0700210 // gid's are not consecutive in this segment so delta
211 // cannot be used.
212 segment->use_delta = false;
213 }
214
Garret Riegercfa592d2018-05-02 16:37:38 -0700215 last_gid = new_gid;
216 }
Garret Rieger9ef55a42018-05-02 18:50:56 -0700217
218 // There must be a final entry with end_code == 0xFFFF. Check if we need to add one.
Behdad Esfahbodf7515762018-06-01 17:48:37 -0700219 if (segment == nullptr || segment->end_code != 0xFFFF)
220 {
Garret Rieger9ef55a42018-05-02 18:50:56 -0700221 segment = segments->push ();
222 segment->start_code.set (0xFFFF);
223 segment->end_code.set (0xFFFF);
224 segment->use_delta = true;
225 }
226
Garret Riegercfa592d2018-05-02 16:37:38 -0700227 return true;
Garret Rieger295d67e2018-05-02 16:12:04 -0700228 }
229
Behdad Esfahbod23335de2016-02-24 20:27:13 +0900230 struct accelerator_t
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400231 {
Behdad Esfahbod23335de2016-02-24 20:27:13 +0900232 inline void init (const CmapSubtableFormat4 *subtable)
233 {
234 segCount = subtable->segCountX2 / 2;
235 endCount = subtable->values;
236 startCount = endCount + segCount + 1;
237 idDelta = startCount + segCount;
238 idRangeOffset = idDelta + segCount;
239 glyphIdArray = idRangeOffset + segCount;
240 glyphIdArrayLength = (subtable->length - 16 - 8 * segCount) / 2;
241 }
Behdad Esfahbodddea4d12018-08-25 21:08:15 -0700242 inline void fini (void) {}
Behdad Esfahbod23335de2016-02-24 20:27:13 +0900243
Behdad Esfahbodb41c43b2018-08-25 15:25:03 -0700244 inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
Behdad Esfahbod23335de2016-02-24 20:27:13 +0900245 {
Behdad Esfahbod23335de2016-02-24 20:27:13 +0900246 /* Custom two-array bsearch. */
Behdad Esfahbodb41c43b2018-08-25 15:25:03 -0700247 int min = 0, max = (int) this->segCount - 1;
248 const HBUINT16 *startCount = this->startCount;
249 const HBUINT16 *endCount = this->endCount;
Behdad Esfahbod23335de2016-02-24 20:27:13 +0900250 unsigned int i;
251 while (min <= max)
252 {
253 int mid = (min + max) / 2;
254 if (codepoint < startCount[mid])
255 max = mid - 1;
256 else if (codepoint > endCount[mid])
257 min = mid + 1;
258 else
259 {
260 i = mid;
261 goto found;
262 }
263 }
264 return false;
265
266 found:
267 hb_codepoint_t gid;
Behdad Esfahbodb41c43b2018-08-25 15:25:03 -0700268 unsigned int rangeOffset = this->idRangeOffset[i];
Behdad Esfahbod23335de2016-02-24 20:27:13 +0900269 if (rangeOffset == 0)
Behdad Esfahbodb41c43b2018-08-25 15:25:03 -0700270 gid = codepoint + this->idDelta[i];
Behdad Esfahbod23335de2016-02-24 20:27:13 +0900271 else
272 {
273 /* Somebody has been smoking... */
Behdad Esfahbodb41c43b2018-08-25 15:25:03 -0700274 unsigned int index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount;
275 if (unlikely (index >= this->glyphIdArrayLength))
Behdad Esfahbod23335de2016-02-24 20:27:13 +0900276 return false;
Behdad Esfahbodb41c43b2018-08-25 15:25:03 -0700277 gid = this->glyphIdArray[index];
Behdad Esfahbod23335de2016-02-24 20:27:13 +0900278 if (unlikely (!gid))
279 return false;
Behdad Esfahbodb41c43b2018-08-25 15:25:03 -0700280 gid += this->idDelta[i];
Behdad Esfahbod23335de2016-02-24 20:27:13 +0900281 }
282
283 *glyph = gid & 0xFFFFu;
Behdad Esfahbod531051b2018-08-25 08:44:18 -0700284 return *glyph != 0;
Behdad Esfahbod23335de2016-02-24 20:27:13 +0900285 }
Behdad Esfahbodb41c43b2018-08-25 15:25:03 -0700286 static inline bool get_glyph_func (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph)
287 {
288 return ((const accelerator_t *) obj)->get_glyph (codepoint, glyph);
289 }
290 inline void collect_unicodes (hb_set_t *out) const
291 {
Behdad Esfahbodc8cfb702018-08-25 16:14:32 -0700292 unsigned int count = this->segCount;
293 if (count && this->startCount[count - 1] == 0xFFFFu)
294 count--; /* Skip sentinel segment. */
295 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbodb41c43b2018-08-25 15:25:03 -0700296 {
Behdad Esfahbod28634db2018-08-25 21:23:43 -0700297 unsigned int rangeOffset = this->idRangeOffset[i];
298 if (rangeOffset == 0)
299 out->add_range (this->startCount[i], this->endCount[i]);
300 else
301 {
302 for (hb_codepoint_t codepoint = this->startCount[i];
303 codepoint <= this->endCount[i];
304 codepoint++)
305 {
306 unsigned int index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount;
307 if (unlikely (index >= this->glyphIdArrayLength))
308 break;
309 hb_codepoint_t gid = this->glyphIdArray[index];
310 if (unlikely (!gid))
311 continue;
312 out->add (codepoint);
313 }
314 }
Behdad Esfahbodb41c43b2018-08-25 15:25:03 -0700315 }
316 }
Behdad Esfahbod23335de2016-02-24 20:27:13 +0900317
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100318 const HBUINT16 *endCount;
319 const HBUINT16 *startCount;
320 const HBUINT16 *idDelta;
321 const HBUINT16 *idRangeOffset;
322 const HBUINT16 *glyphIdArray;
Behdad Esfahbod23335de2016-02-24 20:27:13 +0900323 unsigned int segCount;
Behdad Esfahbodc8a47452014-05-09 19:55:51 -0400324 unsigned int glyphIdArrayLength;
Behdad Esfahbod23335de2016-02-24 20:27:13 +0900325 };
Behdad Esfahbodc8a47452014-05-09 19:55:51 -0400326
Behdad Esfahbod23335de2016-02-24 20:27:13 +0900327 inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
328 {
Behdad Esfahbodddea4d12018-08-25 21:08:15 -0700329 hb_auto_t<accelerator_t> accel (this);
Behdad Esfahbod23335de2016-02-24 20:27:13 +0900330 return accel.get_glyph_func (&accel, codepoint, glyph);
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400331 }
Behdad Esfahbodbd0e5422018-08-25 09:33:30 -0700332 inline void collect_unicodes (hb_set_t *out) const
333 {
Behdad Esfahbodddea4d12018-08-25 21:08:15 -0700334 hb_auto_t<accelerator_t> accel (this);
Behdad Esfahbodb41c43b2018-08-25 15:25:03 -0700335 accel.collect_unicodes (out);
Behdad Esfahbodbd0e5422018-08-25 09:33:30 -0700336 }
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400337
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300338 inline bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbod257d1ad2014-06-04 18:47:55 -0400339 {
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400340 TRACE_SANITIZE (this);
Behdad Esfahbod257d1ad2014-06-04 18:47:55 -0400341 if (unlikely (!c->check_struct (this)))
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100342 return_trace (false);
Behdad Esfahbod257d1ad2014-06-04 18:47:55 -0400343
344 if (unlikely (!c->check_range (this, length)))
345 {
346 /* Some broken fonts have too long of a "length" value.
347 * If that is the case, just change the value to truncate
348 * the subtable at the end of the blob. */
349 uint16_t new_length = (uint16_t) MIN ((uintptr_t) 65535,
350 (uintptr_t) (c->end -
351 (char *) this));
352 if (!c->try_set (&length, new_length))
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100353 return_trace (false);
Behdad Esfahbod257d1ad2014-06-04 18:47:55 -0400354 }
355
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100356 return_trace (16 + 4 * (unsigned int) segCountX2 <= length);
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400357 }
358
Garret Rieger295d67e2018-05-02 16:12:04 -0700359
360
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400361 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100362 HBUINT16 format; /* Format number is set to 4. */
363 HBUINT16 length; /* This is the length in bytes of the
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400364 * subtable. */
Behdad Esfahbod5b93f692018-05-02 14:59:14 -0400365 HBUINT16 language; /* Ignore. */
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100366 HBUINT16 segCountX2; /* 2 x segCount. */
Behdad Esfahbod5b93f692018-05-02 14:59:14 -0400367 HBUINT16 searchRange; /* 2 * (2**floor(log2(segCount))) */
368 HBUINT16 entrySelector; /* log2(searchRange/2) */
369 HBUINT16 rangeShift; /* 2 x segCount - searchRange */
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400370
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100371 HBUINT16 values[VAR];
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400372#if 0
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100373 HBUINT16 endCount[segCount]; /* End characterCode for each segment,
Behdad Esfahbod76271002014-07-11 14:54:42 -0400374 * last=0xFFFFu. */
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100375 HBUINT16 reservedPad; /* Set to 0. */
376 HBUINT16 startCount[segCount]; /* Start character code for each segment. */
377 HBINT16 idDelta[segCount]; /* Delta for all character codes in segment. */
378 HBUINT16 idRangeOffset[segCount];/* Offsets into glyphIdArray or 0 */
379 HBUINT16 glyphIdArray[VAR]; /* Glyph index array (arbitrary length) */
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400380#endif
381
382 public:
383 DEFINE_SIZE_ARRAY (14, values);
384};
385
Behdad Esfahbodd294a2c2014-05-12 17:58:31 -0400386struct CmapSubtableLongGroup
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400387{
388 friend struct CmapSubtableFormat12;
Behdad Esfahbodd294a2c2014-05-12 17:58:31 -0400389 friend struct CmapSubtableFormat13;
Garret Rieger5dadbb02018-04-17 07:00:23 -0600390 template<typename U>
391 friend struct CmapSubtableLongSegmented;
Rod Sheeter1cd98d02018-02-08 19:39:57 -0800392 friend struct cmap;
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400393
394 int cmp (hb_codepoint_t codepoint) const
395 {
396 if (codepoint < startCharCode) return -1;
397 if (codepoint > endCharCode) return +1;
398 return 0;
399 }
400
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300401 inline bool sanitize (hb_sanitize_context_t *c) const
402 {
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400403 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100404 return_trace (c->check_struct (this));
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400405 }
406
407 private:
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100408 HBUINT32 startCharCode; /* First character code in this group. */
409 HBUINT32 endCharCode; /* Last character code in this group. */
410 HBUINT32 glyphID; /* Glyph index; interpretation depends on
Behdad Esfahbod7d382fa2018-08-25 09:35:45 -0700411 * subtable format. */
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400412 public:
413 DEFINE_SIZE_STATIC (12);
414};
415
Behdad Esfahbod94759e82014-05-13 21:17:28 -0400416template <typename UINT>
417struct CmapSubtableTrimmed
Behdad Esfahbod91bbfca2014-05-12 18:19:29 -0400418{
Behdad Esfahbod91bbfca2014-05-12 18:19:29 -0400419 inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
420 {
421 /* Rely on our implicit array bound-checking. */
422 hb_codepoint_t gid = glyphIdArray[codepoint - startCharCode];
423 if (!gid)
424 return false;
425 *glyph = gid;
Behdad Esfahbod531051b2018-08-25 08:44:18 -0700426 return *glyph != 0;
Behdad Esfahbod91bbfca2014-05-12 18:19:29 -0400427 }
Behdad Esfahbod7d382fa2018-08-25 09:35:45 -0700428 inline void collect_unicodes (hb_set_t *out) const
429 {
430 hb_codepoint_t start = startCharCode;
431 unsigned int count = glyphIdArray.len;
432 for (unsigned int i = 0; i < count; i++)
433 if (glyphIdArray[i])
434 out->add (start + i);
435 }
Behdad Esfahbod91bbfca2014-05-12 18:19:29 -0400436
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300437 inline bool sanitize (hb_sanitize_context_t *c) const
438 {
Behdad Esfahbod91bbfca2014-05-12 18:19:29 -0400439 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100440 return_trace (c->check_struct (this) && glyphIdArray.sanitize (c));
Behdad Esfahbod91bbfca2014-05-12 18:19:29 -0400441 }
442
443 protected:
Behdad Esfahbod94759e82014-05-13 21:17:28 -0400444 UINT formatReserved; /* Subtable format and (maybe) padding. */
Behdad Esfahbod5b93f692018-05-02 14:59:14 -0400445 UINT length; /* Byte length of this subtable. */
446 UINT language; /* Ignore. */
Behdad Esfahbod94759e82014-05-13 21:17:28 -0400447 UINT startCharCode; /* First character code covered. */
Behdad Esfahbod9da552d2014-06-27 15:09:42 -0400448 ArrayOf<GlyphID, UINT>
Behdad Esfahbod91bbfca2014-05-12 18:19:29 -0400449 glyphIdArray; /* Array of glyph index values for character
450 * codes in the range. */
451 public:
Behdad Esfahbod94759e82014-05-13 21:17:28 -0400452 DEFINE_SIZE_ARRAY (5 * sizeof (UINT), glyphIdArray);
Behdad Esfahbod91bbfca2014-05-12 18:19:29 -0400453};
454
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100455struct CmapSubtableFormat6 : CmapSubtableTrimmed<HBUINT16> {};
456struct CmapSubtableFormat10 : CmapSubtableTrimmed<HBUINT32 > {};
Behdad Esfahbod91bbfca2014-05-12 18:19:29 -0400457
Behdad Esfahbodca7b7742014-05-13 21:26:34 -0400458template <typename T>
459struct CmapSubtableLongSegmented
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400460{
Rod Sheeter9275bd02018-02-09 17:33:34 -0800461 friend struct cmap;
462
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400463 inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
464 {
Behdad Esfahboddf554af2014-06-19 15:39:18 -0400465 int i = groups.bsearch (codepoint);
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400466 if (i == -1)
467 return false;
Behdad Esfahbodca7b7742014-05-13 21:26:34 -0400468 *glyph = T::group_get_glyph (groups[i], codepoint);
Behdad Esfahbod531051b2018-08-25 08:44:18 -0700469 return *glyph != 0;
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400470 }
471
Behdad Esfahbodd60c4652018-08-25 08:47:06 -0700472 inline void collect_unicodes (hb_set_t *out) const
Garret Rieger5dadbb02018-04-17 07:00:23 -0600473 {
474 for (unsigned int i = 0; i < this->groups.len; i++) {
Behdad Esfahbod1dcf5fb2018-08-25 16:11:26 -0700475 out->add_range (this->groups[i].startCharCode,
476 MIN ((hb_codepoint_t) this->groups[i].endCharCode,
Behdad Esfahbod82b12bc2018-08-25 22:07:17 -0700477 (hb_codepoint_t) HB_UNICODE_MAX));
Garret Rieger5dadbb02018-04-17 07:00:23 -0600478 }
479 }
480
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300481 inline bool sanitize (hb_sanitize_context_t *c) const
482 {
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400483 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100484 return_trace (c->check_struct (this) && groups.sanitize (c));
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400485 }
486
Behdad Esfahbod6fa690c2018-02-18 16:27:59 -0800487 inline bool serialize (hb_serialize_context_t *c,
Garret Rieger0053d132018-05-02 15:42:43 -0700488 const hb_vector_t<CmapSubtableLongGroup> &group_data)
Rod Sheeter9275bd02018-02-09 17:33:34 -0800489 {
490 TRACE_SERIALIZE (this);
Behdad Esfahbod6fa690c2018-02-18 16:27:59 -0800491 if (unlikely (!c->extend_min (*this))) return_trace (false);
Behdad Esfahbod63f57f42018-05-08 16:56:11 -0700492 Supplier<CmapSubtableLongGroup> supplier (group_data.arrayZ, group_data.len);
Behdad Esfahbod6fa690c2018-02-18 16:27:59 -0800493 if (unlikely (!groups.serialize (c, supplier, group_data.len))) return_trace (false);
Rod Sheeter9275bd02018-02-09 17:33:34 -0800494 return true;
495 }
496
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400497 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100498 HBUINT16 format; /* Subtable format; set to 12. */
Behdad Esfahbod5b93f692018-05-02 14:59:14 -0400499 HBUINT16 reserved; /* Reserved; set to 0. */
500 HBUINT32 length; /* Byte length of this subtable. */
501 HBUINT32 language; /* Ignore. */
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100502 SortedArrayOf<CmapSubtableLongGroup, HBUINT32>
Behdad Esfahbodd294a2c2014-05-12 17:58:31 -0400503 groups; /* Groupings. */
504 public:
505 DEFINE_SIZE_ARRAY (16, groups);
506};
507
Behdad Esfahbodca7b7742014-05-13 21:26:34 -0400508struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
Behdad Esfahbodd294a2c2014-05-12 17:58:31 -0400509{
Behdad Esfahbodca7b7742014-05-13 21:26:34 -0400510 static inline hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
511 hb_codepoint_t u)
512 { return group.glyphID + (u - group.startCharCode); }
Garret Rieger0053d132018-05-02 15:42:43 -0700513
514
515 bool serialize (hb_serialize_context_t *c,
516 const hb_vector_t<CmapSubtableLongGroup> &groups)
517 {
518 if (unlikely (!c->extend_min (*this))) return false;
519
520 this->format.set (12);
Garret Rieger3be050f2018-05-04 11:23:32 -0700521 this->reserved.set (0);
522 this->length.set (get_sub_table_size (groups));
Garret Rieger0053d132018-05-02 15:42:43 -0700523
Garret Rieger7c22f982018-05-03 13:14:28 -0700524 return CmapSubtableLongSegmented<CmapSubtableFormat12>::serialize (c, groups);
Garret Rieger0053d132018-05-02 15:42:43 -0700525 }
526
527 static inline size_t get_sub_table_size (const hb_vector_t<CmapSubtableLongGroup> &groups)
528 {
529 return 16 + 12 * groups.len;
530 }
531
532 static inline bool create_sub_table_plan (const hb_subset_plan_t *plan,
533 hb_vector_t<CmapSubtableLongGroup> *groups)
534 {
535 CmapSubtableLongGroup *group = nullptr;
Garret Rieger0053d132018-05-02 15:42:43 -0700536
Garret Rieger251cc972018-05-30 12:23:51 -0700537 hb_codepoint_t cp = HB_SET_VALUE_INVALID;
538 while (plan->unicodes->next (&cp)) {
Garret Rieger0053d132018-05-02 15:42:43 -0700539 hb_codepoint_t new_gid;
Garret Rieger251cc972018-05-30 12:23:51 -0700540 if (unlikely (!plan->new_gid_for_codepoint (cp, &new_gid)))
Garret Rieger0053d132018-05-02 15:42:43 -0700541 {
542 DEBUG_MSG(SUBSET, nullptr, "Unable to find new gid for %04x", cp);
543 return false;
544 }
545
546 if (!group || !_is_gid_consecutive (group, cp, new_gid))
547 {
548 group = groups->push ();
549 group->startCharCode.set (cp);
550 group->endCharCode.set (cp);
551 group->glyphID.set (new_gid);
552 } else
553 {
554 group->endCharCode.set (cp);
555 }
556 }
557
558 DEBUG_MSG(SUBSET, nullptr, "cmap");
559 for (unsigned int i = 0; i < groups->len; i++) {
560 CmapSubtableLongGroup& group = (*groups)[i];
561 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));
562 }
563
564 return true;
565 }
566
567 private:
568 static inline bool _is_gid_consecutive (CmapSubtableLongGroup *group,
569 hb_codepoint_t cp,
570 hb_codepoint_t new_gid)
571 {
572 return (cp - 1 == group->endCharCode) &&
573 new_gid == group->glyphID + (cp - group->startCharCode);
574 }
575
Behdad Esfahbodca7b7742014-05-13 21:26:34 -0400576};
Behdad Esfahbodd294a2c2014-05-12 17:58:31 -0400577
Behdad Esfahbodca7b7742014-05-13 21:26:34 -0400578struct CmapSubtableFormat13 : CmapSubtableLongSegmented<CmapSubtableFormat13>
579{
580 static inline hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
581 hb_codepoint_t u HB_UNUSED)
582 { return group.glyphID; }
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400583};
584
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400585typedef enum
586{
587 GLYPH_VARIANT_NOT_FOUND = 0,
588 GLYPH_VARIANT_FOUND = 1,
589 GLYPH_VARIANT_USE_DEFAULT = 2
590} glyph_variant_t;
591
592struct UnicodeValueRange
593{
594 inline int cmp (const hb_codepoint_t &codepoint) const
595 {
596 if (codepoint < startUnicodeValue) return -1;
597 if (codepoint > startUnicodeValue + additionalCount) return +1;
598 return 0;
599 }
600
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300601 inline bool sanitize (hb_sanitize_context_t *c) const
602 {
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400603 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100604 return_trace (c->check_struct (this));
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400605 }
606
Ebrahim Byagowi435b1872018-04-15 21:18:48 +0430607 HBUINT24 startUnicodeValue; /* First value in this range. */
Behdad Esfahbod4806b382018-08-25 15:56:07 -0700608 HBUINT8 additionalCount; /* Number of additional values in this
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400609 * range. */
610 public:
611 DEFINE_SIZE_STATIC (4);
612};
613
Behdad Esfahbod1dcf5fb2018-08-25 16:11:26 -0700614struct DefaultUVS : SortedArrayOf<UnicodeValueRange, HBUINT32>
615{
616 inline void collect_unicodes (hb_set_t *out) const
617 {
618 unsigned int count = len;
619 for (unsigned int i = 0; i < count; i++)
620 {
621 hb_codepoint_t first = arrayZ[i].startUnicodeValue;
622 hb_codepoint_t last = MIN ((hb_codepoint_t) (first + arrayZ[i].additionalCount),
Behdad Esfahbod82b12bc2018-08-25 22:07:17 -0700623 (hb_codepoint_t) HB_UNICODE_MAX);
Behdad Esfahbod1dcf5fb2018-08-25 16:11:26 -0700624 out->add_range (first, last);
625 }
626 }
627
628 public:
629 DEFINE_SIZE_ARRAY (4, arrayZ);
630};
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400631
632struct UVSMapping
633{
634 inline int cmp (const hb_codepoint_t &codepoint) const
635 {
636 return unicodeValue.cmp (codepoint);
637 }
638
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300639 inline bool sanitize (hb_sanitize_context_t *c) const
640 {
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400641 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100642 return_trace (c->check_struct (this));
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400643 }
644
Ebrahim Byagowi435b1872018-04-15 21:18:48 +0430645 HBUINT24 unicodeValue; /* Base Unicode value of the UVS */
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400646 GlyphID glyphID; /* Glyph ID of the UVS */
647 public:
648 DEFINE_SIZE_STATIC (5);
649};
650
Behdad Esfahbod1dcf5fb2018-08-25 16:11:26 -0700651struct NonDefaultUVS : SortedArrayOf<UVSMapping, HBUINT32>
652{
653 inline void collect_unicodes (hb_set_t *out) const
654 {
655 unsigned int count = len;
656 for (unsigned int i = 0; i < count; i++)
657 out->add (arrayZ[i].glyphID);
658 }
659
660 public:
661 DEFINE_SIZE_ARRAY (4, arrayZ);
662};
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400663
664struct VariationSelectorRecord
665{
666 inline glyph_variant_t get_glyph (hb_codepoint_t codepoint,
667 hb_codepoint_t *glyph,
668 const void *base) const
669 {
670 int i;
671 const DefaultUVS &defaults = base+defaultUVS;
672 i = defaults.bsearch (codepoint);
673 if (i != -1)
674 return GLYPH_VARIANT_USE_DEFAULT;
675 const NonDefaultUVS &nonDefaults = base+nonDefaultUVS;
676 i = nonDefaults.bsearch (codepoint);
677 if (i != -1)
678 {
679 *glyph = nonDefaults[i].glyphID;
680 return GLYPH_VARIANT_FOUND;
681 }
682 return GLYPH_VARIANT_NOT_FOUND;
683 }
684
Behdad Esfahbod1dcf5fb2018-08-25 16:11:26 -0700685 inline void collect_unicodes (hb_set_t *out, const void *base) const
686 {
687 (base+defaultUVS).collect_unicodes (out);
688 (base+nonDefaultUVS).collect_unicodes (out);
689 }
690
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400691 inline int cmp (const hb_codepoint_t &variation_selector) const
692 {
693 return varSelector.cmp (variation_selector);
694 }
695
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300696 inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
697 {
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400698 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100699 return_trace (c->check_struct (this) &&
700 defaultUVS.sanitize (c, base) &&
701 nonDefaultUVS.sanitize (c, base));
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400702 }
703
Ebrahim Byagowi435b1872018-04-15 21:18:48 +0430704 HBUINT24 varSelector; /* Variation selector. */
Behdad Esfahbod5e156fa2017-01-22 20:28:56 -0800705 LOffsetTo<DefaultUVS>
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400706 defaultUVS; /* Offset to Default UVS Table. May be 0. */
Behdad Esfahbod5e156fa2017-01-22 20:28:56 -0800707 LOffsetTo<NonDefaultUVS>
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400708 nonDefaultUVS; /* Offset to Non-Default UVS Table. May be 0. */
709 public:
710 DEFINE_SIZE_STATIC (11);
711};
712
713struct CmapSubtableFormat14
714{
715 inline glyph_variant_t get_glyph_variant (hb_codepoint_t codepoint,
716 hb_codepoint_t variation_selector,
717 hb_codepoint_t *glyph) const
718 {
Behdad Esfahbod1dcf5fb2018-08-25 16:11:26 -0700719 return record[record.bsearch (variation_selector)].get_glyph (codepoint, glyph, this);
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400720 }
721
Behdad Esfahbod4806b382018-08-25 15:56:07 -0700722 inline void collect_variation_selectors (hb_set_t *out) const
723 {
724 unsigned int count = record.len;
725 for (unsigned int i = 0; i < count; i++)
726 out->add (record.arrayZ[i].varSelector);
727 }
Behdad Esfahbod1dcf5fb2018-08-25 16:11:26 -0700728 inline void collect_variation_unicodes (hb_codepoint_t variation_selector,
729 hb_set_t *out) const
730 {
731 record[record.bsearch (variation_selector)].collect_unicodes (out, this);
732 }
Behdad Esfahbod4806b382018-08-25 15:56:07 -0700733
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300734 inline bool sanitize (hb_sanitize_context_t *c) const
735 {
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400736 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100737 return_trace (c->check_struct (this) &&
738 record.sanitize (c, this));
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400739 }
740
741 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100742 HBUINT16 format; /* Format number is set to 14. */
Behdad Esfahbod5b93f692018-05-02 14:59:14 -0400743 HBUINT32 length; /* Byte length of this subtable. */
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100744 SortedArrayOf<VariationSelectorRecord, HBUINT32>
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400745 record; /* Variation selector records; sorted
746 * in increasing order of `varSelector'. */
747 public:
748 DEFINE_SIZE_ARRAY (10, record);
749};
750
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400751struct CmapSubtable
752{
Behdad Esfahbodc9558762014-05-14 00:42:18 -0400753 /* Note: We intentionally do NOT implement subtable formats 2 and 8. */
754
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400755 inline bool get_glyph (hb_codepoint_t codepoint,
756 hb_codepoint_t *glyph) const
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400757 {
758 switch (u.format) {
Rod Sheeter1725c352018-02-14 19:36:33 -0800759 case 0: return u.format0 .get_glyph (codepoint, glyph);
760 case 4: return u.format4 .get_glyph (codepoint, glyph);
761 case 6: return u.format6 .get_glyph (codepoint, glyph);
762 case 10: return u.format10.get_glyph (codepoint, glyph);
763 case 12: return u.format12.get_glyph (codepoint, glyph);
764 case 13: return u.format13.get_glyph (codepoint, glyph);
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400765 case 14:
766 default: return false;
767 }
768 }
Behdad Esfahbodbd0e5422018-08-25 09:33:30 -0700769 inline void collect_unicodes (hb_set_t *out) const
770 {
771 switch (u.format) {
Behdad Esfahbod7d382fa2018-08-25 09:35:45 -0700772 case 0: u.format0 .collect_unicodes (out); return;
Behdad Esfahbodbd0e5422018-08-25 09:33:30 -0700773 case 4: u.format4 .collect_unicodes (out); return;
Behdad Esfahbod7d382fa2018-08-25 09:35:45 -0700774 case 6: u.format6 .collect_unicodes (out); return;
775 case 10: u.format10.collect_unicodes (out); return;
Behdad Esfahbodbd0e5422018-08-25 09:33:30 -0700776 case 12: u.format12.collect_unicodes (out); return;
777 case 13: u.format13.collect_unicodes (out); return;
778 case 14:
779 default: return;
780 }
781 }
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400782
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300783 inline bool sanitize (hb_sanitize_context_t *c) const
784 {
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400785 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100786 if (!u.format.sanitize (c)) return_trace (false);
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400787 switch (u.format) {
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100788 case 0: return_trace (u.format0 .sanitize (c));
789 case 4: return_trace (u.format4 .sanitize (c));
790 case 6: return_trace (u.format6 .sanitize (c));
791 case 10: return_trace (u.format10.sanitize (c));
792 case 12: return_trace (u.format12.sanitize (c));
793 case 13: return_trace (u.format13.sanitize (c));
794 case 14: return_trace (u.format14.sanitize (c));
795 default:return_trace (true);
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400796 }
797 }
798
Behdad Esfahbod5473ebf2016-02-24 19:32:43 +0900799 public:
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400800 union {
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100801 HBUINT16 format; /* Format identifier */
Behdad Esfahbodb7878cd2014-05-13 21:47:51 -0400802 CmapSubtableFormat0 format0;
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400803 CmapSubtableFormat4 format4;
Behdad Esfahbod91bbfca2014-05-12 18:19:29 -0400804 CmapSubtableFormat6 format6;
805 CmapSubtableFormat10 format10;
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400806 CmapSubtableFormat12 format12;
Behdad Esfahbodd294a2c2014-05-12 17:58:31 -0400807 CmapSubtableFormat13 format13;
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400808 CmapSubtableFormat14 format14;
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400809 } u;
810 public:
811 DEFINE_SIZE_UNION (2, format);
812};
813
814
815struct EncodingRecord
816{
Behdad Esfahbodf1a72fe2014-06-04 19:00:29 -0400817 inline int cmp (const EncodingRecord &other) const
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400818 {
819 int ret;
Behdad Esfahbodf1a72fe2014-06-04 19:00:29 -0400820 ret = platformID.cmp (other.platformID);
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400821 if (ret) return ret;
Behdad Esfahbodf1a72fe2014-06-04 19:00:29 -0400822 ret = encodingID.cmp (other.encodingID);
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400823 if (ret) return ret;
824 return 0;
825 }
826
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300827 inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
828 {
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400829 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100830 return_trace (c->check_struct (this) &&
831 subtable.sanitize (c, base));
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400832 }
833
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100834 HBUINT16 platformID; /* Platform ID. */
835 HBUINT16 encodingID; /* Platform-specific encoding ID. */
Behdad Esfahbod5e156fa2017-01-22 20:28:56 -0800836 LOffsetTo<CmapSubtable>
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400837 subtable; /* Byte offset from beginning of table to the subtable for this encoding. */
838 public:
839 DEFINE_SIZE_STATIC (8);
840};
841
842struct cmap
843{
844 static const hb_tag_t tableTag = HB_OT_TAG_cmap;
845
Behdad Esfahbode6cb9382018-08-26 00:21:29 -0700846 struct subset_plan
847 {
Garret Rieger0053d132018-05-02 15:42:43 -0700848 subset_plan(void)
849 {
Garret Rieger295d67e2018-05-02 16:12:04 -0700850 format4_segments.init();
851 format12_groups.init();
Garret Rieger0053d132018-05-02 15:42:43 -0700852 }
853
854 ~subset_plan(void)
855 {
Garret Rieger295d67e2018-05-02 16:12:04 -0700856 format4_segments.fini();
857 format12_groups.fini();
Garret Rieger0053d132018-05-02 15:42:43 -0700858 }
859
860 inline size_t final_size() const
861 {
Garret Rieger9ef55a42018-05-02 18:50:56 -0700862 return 4 // header
Garret Riegerc8179922018-05-03 10:53:20 -0700863 + 8 * 3 // 3 EncodingRecord
Garret Rieger9ef55a42018-05-02 18:50:56 -0700864 + CmapSubtableFormat4::get_sub_table_size (this->format4_segments)
865 + CmapSubtableFormat12::get_sub_table_size (this->format12_groups);
Garret Rieger0053d132018-05-02 15:42:43 -0700866 }
867
Garret Rieger295d67e2018-05-02 16:12:04 -0700868 // Format 4
869 hb_vector_t<CmapSubtableFormat4::segment_plan> format4_segments;
Garret Rieger0053d132018-05-02 15:42:43 -0700870 // Format 12
Garret Rieger295d67e2018-05-02 16:12:04 -0700871 hb_vector_t<CmapSubtableLongGroup> format12_groups;
Garret Rieger0053d132018-05-02 15:42:43 -0700872 };
873
Behdad Esfahbod977ddff2017-11-14 20:06:19 -0800874 inline bool sanitize (hb_sanitize_context_t *c) const
875 {
876 TRACE_SANITIZE (this);
877 return_trace (c->check_struct (this) &&
878 likely (version == 0) &&
879 encodingRecord.sanitize (c, this));
880 }
881
Garret Rieger0053d132018-05-02 15:42:43 -0700882 inline bool _create_plan (const hb_subset_plan_t *plan,
883 subset_plan *cmap_plan) const
Garret Rieger5e318e02018-04-18 17:13:37 -0700884 {
Garret Rieger295d67e2018-05-02 16:12:04 -0700885 if (unlikely( !CmapSubtableFormat4::create_sub_table_plan (plan, &cmap_plan->format4_segments)))
886 return false;
887
888 return CmapSubtableFormat12::create_sub_table_plan (plan, &cmap_plan->format12_groups);
Garret Rieger5e318e02018-04-18 17:13:37 -0700889 }
890
Garret Rieger295d67e2018-05-02 16:12:04 -0700891 inline bool _subset (const hb_subset_plan_t *plan,
892 const subset_plan &cmap_subset_plan,
Behdad Esfahbodb1bd0b52018-02-14 18:50:19 -0800893 size_t dest_sz,
894 void *dest) const
Rod Sheeter9275bd02018-02-09 17:33:34 -0800895 {
Behdad Esfahbod6fa690c2018-02-18 16:27:59 -0800896 hb_serialize_context_t c (dest, dest_sz);
Rod Sheeter9275bd02018-02-09 17:33:34 -0800897
Behdad Esfahbode57a6382018-07-23 12:00:02 -0700898 cmap *table = c.start_serialize<cmap> ();
899 if (unlikely (!c.extend_min (*table)))
Rod Sheeter9275bd02018-02-09 17:33:34 -0800900 {
901 return false;
902 }
903
Behdad Esfahbode57a6382018-07-23 12:00:02 -0700904 table->version.set (0);
Rod Sheeter9275bd02018-02-09 17:33:34 -0800905
Behdad Esfahbode57a6382018-07-23 12:00:02 -0700906 if (unlikely (!table->encodingRecord.serialize (&c, /* numTables */ 3)))
Garret Rieger9ef55a42018-05-02 18:50:56 -0700907 return false;
Rod Sheeter9275bd02018-02-09 17:33:34 -0800908
Garret Rieger295d67e2018-05-02 16:12:04 -0700909 // TODO(grieger): Convert the below to a for loop
Rod Sheeter9275bd02018-02-09 17:33:34 -0800910
Garret Riegerc8179922018-05-03 10:53:20 -0700911 // Format 4, Plat 0 Encoding Record
Behdad Esfahbode57a6382018-07-23 12:00:02 -0700912 EncodingRecord &format4_plat0_rec = table->encodingRecord[0];
Garret Riegerc8179922018-05-03 10:53:20 -0700913 format4_plat0_rec.platformID.set (0); // Unicode
914 format4_plat0_rec.encodingID.set (3);
Rod Sheeter0301e5b2018-02-12 10:12:11 -0800915
Garret Riegerc8179922018-05-03 10:53:20 -0700916 // Format 4, Plat 3 Encoding Record
Behdad Esfahbode57a6382018-07-23 12:00:02 -0700917 EncodingRecord &format4_plat3_rec = table->encodingRecord[1];
Garret Riegerc8179922018-05-03 10:53:20 -0700918 format4_plat3_rec.platformID.set (3); // Windows
919 format4_plat3_rec.encodingID.set (1); // Unicode BMP
Rod Sheeter9275bd02018-02-09 17:33:34 -0800920
Garret Rieger295d67e2018-05-02 16:12:04 -0700921 // Format 12 Encoding Record
Behdad Esfahbode57a6382018-07-23 12:00:02 -0700922 EncodingRecord &format12_rec = table->encodingRecord[2];
Garret Rieger295d67e2018-05-02 16:12:04 -0700923 format12_rec.platformID.set (3); // Windows
924 format12_rec.encodingID.set (10); // Unicode UCS-4
Rod Sheeter0301e5b2018-02-12 10:12:11 -0800925
Garret Riegerc8179922018-05-03 10:53:20 -0700926 // Write out format 4 sub table
Garret Rieger295d67e2018-05-02 16:12:04 -0700927 {
Behdad Esfahbode57a6382018-07-23 12:00:02 -0700928 CmapSubtable &subtable = format4_plat0_rec.subtable.serialize (&c, table);
Garret Riegerc8179922018-05-03 10:53:20 -0700929 format4_plat3_rec.subtable.set (format4_plat0_rec.subtable);
Garret Rieger295d67e2018-05-02 16:12:04 -0700930 subtable.u.format.set (4);
Rod Sheeter9275bd02018-02-09 17:33:34 -0800931
Garret Rieger295d67e2018-05-02 16:12:04 -0700932 CmapSubtableFormat4 &format4 = subtable.u.format4;
Garret Rieger9ef55a42018-05-02 18:50:56 -0700933 if (unlikely (!format4.serialize (&c, plan, cmap_subset_plan.format4_segments)))
934 return false;
Garret Rieger295d67e2018-05-02 16:12:04 -0700935 }
Rod Sheeter9275bd02018-02-09 17:33:34 -0800936
Garret Rieger0053d132018-05-02 15:42:43 -0700937 // Write out format 12 sub table.
Garret Rieger295d67e2018-05-02 16:12:04 -0700938 {
Behdad Esfahbode57a6382018-07-23 12:00:02 -0700939 CmapSubtable &subtable = format12_rec.subtable.serialize (&c, table);
Garret Rieger295d67e2018-05-02 16:12:04 -0700940 subtable.u.format.set (12);
Rod Sheeter9275bd02018-02-09 17:33:34 -0800941
Garret Rieger295d67e2018-05-02 16:12:04 -0700942 CmapSubtableFormat12 &format12 = subtable.u.format12;
Garret Rieger9ef55a42018-05-02 18:50:56 -0700943 if (unlikely (!format12.serialize (&c, cmap_subset_plan.format12_groups)))
944 return false;
Garret Rieger295d67e2018-05-02 16:12:04 -0700945 }
Rod Sheeter9275bd02018-02-09 17:33:34 -0800946
Behdad Esfahbod6fa690c2018-02-18 16:27:59 -0800947 c.end_serialize ();
Rod Sheeter0301e5b2018-02-12 10:12:11 -0800948
Rod Sheeter0859a002018-02-07 15:59:36 -0800949 return true;
950 }
951
Rod Sheeter3ed70e52018-02-14 15:24:49 -0800952 inline bool subset (hb_subset_plan_t *plan) const
Rod Sheeter9275bd02018-02-09 17:33:34 -0800953 {
Garret Rieger0053d132018-05-02 15:42:43 -0700954 subset_plan cmap_subset_plan;
Rod Sheeter9275bd02018-02-09 17:33:34 -0800955
Garret Rieger0053d132018-05-02 15:42:43 -0700956 if (unlikely (!_create_plan (plan, &cmap_subset_plan)))
957 {
958 DEBUG_MSG(SUBSET, nullptr, "Failed to generate a cmap subsetting plan.");
959 return false;
960 }
Rod Sheeter9275bd02018-02-09 17:33:34 -0800961
962 // We now know how big our blob needs to be
Garret Rieger0053d132018-05-02 15:42:43 -0700963 size_t dest_sz = cmap_subset_plan.final_size();
Garret Rieger0fb8a5c2018-02-23 15:37:43 -0800964 void *dest = malloc (dest_sz);
Rod Sheeter1725c352018-02-14 19:36:33 -0800965 if (unlikely (!dest)) {
Behdad Esfahbodd1f16fc2018-02-20 10:32:09 -0800966 DEBUG_MSG(SUBSET, nullptr, "Unable to alloc %lu for cmap subset output", (unsigned long) dest_sz);
Rod Sheeterfa877702018-02-14 14:16:25 -0800967 return false;
Rod Sheeter9275bd02018-02-09 17:33:34 -0800968 }
969
Garret Rieger295d67e2018-05-02 16:12:04 -0700970 if (unlikely (!_subset (plan, cmap_subset_plan, dest_sz, dest)))
Rod Sheeter9275bd02018-02-09 17:33:34 -0800971 {
Garret Rieger0053d132018-05-02 15:42:43 -0700972 DEBUG_MSG(SUBSET, nullptr, "Failed to perform subsetting of cmap.");
Rod Sheeter1725c352018-02-14 19:36:33 -0800973 free (dest);
Rod Sheeterfa877702018-02-14 14:16:25 -0800974 return false;
Rod Sheeter9275bd02018-02-09 17:33:34 -0800975 }
976
977 // all done, write the blob into dest
Rod Sheeterfa877702018-02-14 14:16:25 -0800978 hb_blob_t *cmap_prime = hb_blob_create ((const char *)dest,
979 dest_sz,
980 HB_MEMORY_MODE_READONLY,
Garret Rieger0fb8a5c2018-02-23 15:37:43 -0800981 dest,
Rod Sheeterfa877702018-02-14 14:16:25 -0800982 free);
Garret Rieger251cc972018-05-30 12:23:51 -0700983 bool result = plan->add_table (HB_OT_TAG_cmap, cmap_prime);
Garret Rieger0fb8a5c2018-02-23 15:37:43 -0800984 hb_blob_destroy (cmap_prime);
985 return result;
Rod Sheeter9275bd02018-02-09 17:33:34 -0800986 }
987
Behdad Esfahbod02fe03e2018-08-25 15:33:05 -0700988 const CmapSubtable *find_best_subtable (bool *symbol = nullptr) const
989 {
990 if (symbol) *symbol = false;
991
992 const CmapSubtable *subtable;
993
994 /* 32-bit subtables. */
995 if ((subtable = this->find_subtable (3, 10))) return subtable;
996 if ((subtable = this->find_subtable (0, 6))) return subtable;
997 if ((subtable = this->find_subtable (0, 4))) return subtable;
998
999 /* 16-bit subtables. */
1000 if ((subtable = this->find_subtable (3, 1))) return subtable;
1001 if ((subtable = this->find_subtable (0, 3))) return subtable;
1002 if ((subtable = this->find_subtable (0, 2))) return subtable;
1003 if ((subtable = this->find_subtable (0, 1))) return subtable;
1004 if ((subtable = this->find_subtable (0, 0))) return subtable;
1005
1006 /* Symbol subtable. */
1007 if ((subtable = this->find_subtable (3, 0)))
1008 {
1009 if (symbol) *symbol = true;
1010 return subtable;
1011 }
1012
1013 /* Meh. */
1014 return &Null(CmapSubtable);
1015 }
1016
Behdad Esfahbod977ddff2017-11-14 20:06:19 -08001017 struct accelerator_t
1018 {
1019 inline void init (hb_face_t *face)
1020 {
Behdad Esfahbod36ed1632018-07-23 11:57:45 -07001021 this->blob = hb_sanitize_context_t().reference_table<cmap> (face);
Behdad Esfahbode57a6382018-07-23 12:00:02 -07001022 const cmap *table = this->blob->as<cmap> ();
Behdad Esfahbod36ed1632018-07-23 11:57:45 -07001023 const CmapSubtableFormat14 *subtable_uvs = nullptr;
Behdad Esfahbod02fe03e2018-08-25 15:33:05 -07001024 bool symbol;
1025 subtable = table->find_best_subtable (&symbol);
Behdad Esfahbod977ddff2017-11-14 20:06:19 -08001026
1027 /* UVS subtable. */
1028 if (!subtable_uvs)
1029 {
Behdad Esfahbode57a6382018-07-23 12:00:02 -07001030 const CmapSubtable *st = table->find_subtable (0, 5);
Behdad Esfahbod977ddff2017-11-14 20:06:19 -08001031 if (st && st->u.format == 14)
1032 subtable_uvs = &st->u.format14;
1033 }
1034 /* Meh. */
Behdad Esfahbod36ed1632018-07-23 11:57:45 -07001035 if (!subtable_uvs) subtable_uvs = &Null(CmapSubtableFormat14);
Behdad Esfahbod977ddff2017-11-14 20:06:19 -08001036
Behdad Esfahbod4806b382018-08-25 15:56:07 -07001037 this->subtable_uvs = subtable_uvs;
Behdad Esfahbod977ddff2017-11-14 20:06:19 -08001038
1039 this->get_glyph_data = subtable;
1040 if (unlikely (symbol))
Garret Rieger21a181a2018-04-10 15:40:24 -07001041 {
Behdad Esfahbod36ed1632018-07-23 11:57:45 -07001042 this->get_glyph_func = get_glyph_from_symbol<CmapSubtable>;
Garret Rieger21a181a2018-04-10 15:40:24 -07001043 } else {
Behdad Esfahbod977ddff2017-11-14 20:06:19 -08001044 switch (subtable->u.format) {
1045 /* Accelerate format 4 and format 12. */
Garret Rieger21a181a2018-04-10 15:40:24 -07001046 default:
Behdad Esfahbod36ed1632018-07-23 11:57:45 -07001047 this->get_glyph_func = get_glyph_from<CmapSubtable>;
Garret Rieger21a181a2018-04-10 15:40:24 -07001048 break;
1049 case 12:
Behdad Esfahbod36ed1632018-07-23 11:57:45 -07001050 this->get_glyph_func = get_glyph_from<CmapSubtableFormat12>;
Garret Rieger21a181a2018-04-10 15:40:24 -07001051 break;
Behdad Esfahbod977ddff2017-11-14 20:06:19 -08001052 case 4:
1053 {
1054 this->format4_accel.init (&subtable->u.format4);
1055 this->get_glyph_data = &this->format4_accel;
1056 this->get_glyph_func = this->format4_accel.get_glyph_func;
1057 }
1058 break;
1059 }
Garret Rieger21a181a2018-04-10 15:40:24 -07001060 }
Behdad Esfahbod977ddff2017-11-14 20:06:19 -08001061 }
1062
1063 inline void fini (void)
1064 {
1065 hb_blob_destroy (this->blob);
1066 }
1067
1068 inline bool get_nominal_glyph (hb_codepoint_t unicode,
1069 hb_codepoint_t *glyph) const
1070 {
1071 return this->get_glyph_func (this->get_glyph_data, unicode, glyph);
1072 }
1073
1074 inline bool get_variation_glyph (hb_codepoint_t unicode,
1075 hb_codepoint_t variation_selector,
1076 hb_codepoint_t *glyph) const
1077 {
Behdad Esfahbod4806b382018-08-25 15:56:07 -07001078 switch (this->subtable_uvs->get_glyph_variant (unicode,
Behdad Esfahbod977ddff2017-11-14 20:06:19 -08001079 variation_selector,
1080 glyph))
1081 {
Behdad Esfahbod36ed1632018-07-23 11:57:45 -07001082 case GLYPH_VARIANT_NOT_FOUND: return false;
1083 case GLYPH_VARIANT_FOUND: return true;
1084 case GLYPH_VARIANT_USE_DEFAULT: break;
Behdad Esfahbod977ddff2017-11-14 20:06:19 -08001085 }
1086
1087 return get_nominal_glyph (unicode, glyph);
1088 }
1089
Behdad Esfahbodd60c4652018-08-25 08:47:06 -07001090 inline void collect_unicodes (hb_set_t *out) const
Garret Rieger21a181a2018-04-10 15:40:24 -07001091 {
Behdad Esfahbodbd0e5422018-08-25 09:33:30 -07001092 subtable->collect_unicodes (out);
Garret Rieger21a181a2018-04-10 15:40:24 -07001093 }
Behdad Esfahbod4806b382018-08-25 15:56:07 -07001094 inline void collect_variation_selectors (hb_set_t *out) const
1095 {
1096 subtable_uvs->collect_variation_selectors (out);
1097 }
Behdad Esfahbod1dcf5fb2018-08-25 16:11:26 -07001098 inline void collect_variation_unicodes (hb_codepoint_t variation_selector,
1099 hb_set_t *out) const
1100 {
1101 subtable_uvs->collect_variation_unicodes (variation_selector, out);
1102 }
Garret Rieger21a181a2018-04-10 15:40:24 -07001103
Behdad Esfahbod977ddff2017-11-14 20:06:19 -08001104 protected:
1105 typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj,
1106 hb_codepoint_t codepoint,
1107 hb_codepoint_t *glyph);
Garret Rieger21a181a2018-04-10 15:40:24 -07001108
Behdad Esfahbod977ddff2017-11-14 20:06:19 -08001109 template <typename Type>
1110 static inline bool get_glyph_from (const void *obj,
1111 hb_codepoint_t codepoint,
1112 hb_codepoint_t *glyph)
1113 {
1114 const Type *typed_obj = (const Type *) obj;
1115 return typed_obj->get_glyph (codepoint, glyph);
1116 }
1117
1118 template <typename Type>
1119 static inline bool get_glyph_from_symbol (const void *obj,
1120 hb_codepoint_t codepoint,
1121 hb_codepoint_t *glyph)
1122 {
1123 const Type *typed_obj = (const Type *) obj;
1124 if (likely (typed_obj->get_glyph (codepoint, glyph)))
1125 return true;
1126
1127 if (codepoint <= 0x00FFu)
1128 {
1129 /* For symbol-encoded OpenType fonts, we duplicate the
1130 * U+F000..F0FF range at U+0000..U+00FF. That's what
1131 * Windows seems to do, and that's hinted about at:
Ebrahim Byagowif24b0b92018-04-12 13:40:45 +04301132 * https://docs.microsoft.com/en-us/typography/opentype/spec/recom
Behdad Esfahbod977ddff2017-11-14 20:06:19 -08001133 * under "Non-Standard (Symbol) Fonts". */
1134 return typed_obj->get_glyph (0xF000u + codepoint, glyph);
1135 }
1136
1137 return false;
1138 }
1139
1140 private:
Behdad Esfahbodbd0e5422018-08-25 09:33:30 -07001141 const CmapSubtable *subtable;
Behdad Esfahbod4806b382018-08-25 15:56:07 -07001142 const CmapSubtableFormat14 *subtable_uvs;
1143
Behdad Esfahbod977ddff2017-11-14 20:06:19 -08001144 hb_cmap_get_glyph_func_t get_glyph_func;
1145 const void *get_glyph_data;
Garret Rieger21a181a2018-04-10 15:40:24 -07001146
Behdad Esfahbod36ed1632018-07-23 11:57:45 -07001147 CmapSubtableFormat4::accelerator_t format4_accel;
Behdad Esfahbod977ddff2017-11-14 20:06:19 -08001148
Behdad Esfahbod977ddff2017-11-14 20:06:19 -08001149 hb_blob_t *blob;
1150 };
1151
1152 protected:
1153
Behdad Esfahbod3608a682014-05-12 13:46:29 -04001154 inline const CmapSubtable *find_subtable (unsigned int platform_id,
1155 unsigned int encoding_id) const
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -04001156 {
1157 EncodingRecord key;
1158 key.platformID.set (platform_id);
1159 key.encodingID.set (encoding_id);
1160
Behdad Esfahbod1becabe2018-08-25 15:37:56 -07001161 int result = encodingRecord.bsearch (key);
Behdad Esfahbod500737e2014-06-04 18:17:29 -04001162 if (result == -1 || !encodingRecord[result].subtable)
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001163 return nullptr;
Behdad Esfahbod3608a682014-05-12 13:46:29 -04001164
1165 return &(this+encodingRecord[result].subtable);
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -04001166 }
1167
Behdad Esfahbod977ddff2017-11-14 20:06:19 -08001168 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001169 HBUINT16 version; /* Table version number (0). */
Behdad Esfahboddf554af2014-06-19 15:39:18 -04001170 SortedArrayOf<EncodingRecord>
Behdad Esfahbodf1a72fe2014-06-04 19:00:29 -04001171 encodingRecord; /* Encoding tables. */
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -04001172 public:
1173 DEFINE_SIZE_ARRAY (4, encodingRecord);
1174};
1175
Behdad Esfahbod3a0b3a22018-08-26 15:11:24 -07001176struct cmap_accelerator_t : cmap::accelerator_t {};
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -04001177
1178} /* namespace OT */
1179
1180
1181#endif /* HB_OT_CMAP_TABLE_HH */