blob: 959ca97f2895cd46b967914f4072afe12327bf05 [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 Esfahbod9682ef12018-02-08 17:35:57 -060030#include "hb-open-type-private.hh"
Rod Sheeter0859a002018-02-07 15:59:36 -080031#include "hb-subset-plan.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
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;
51 return true;
52 }
53
Behdad Esfahbodde2118e2015-02-17 17:27:44 +030054 inline bool sanitize (hb_sanitize_context_t *c) const
55 {
Behdad Esfahbodb7878cd2014-05-13 21:47:51 -040056 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +010057 return_trace (c->check_struct (this));
Behdad Esfahbodb7878cd2014-05-13 21:47:51 -040058 }
59
60 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +010061 HBUINT16 format; /* Format number is set to 0. */
62 HBUINT16 lengthZ; /* Byte length of this subtable. */
63 HBUINT16 languageZ; /* Ignore. */
Behdad Esfahbod9aa2eb62018-02-11 19:00:42 -060064 HBUINT8 glyphIdArray[256];/* An array that maps character
Behdad Esfahbodb7878cd2014-05-13 21:47:51 -040065 * code to glyph index values. */
66 public:
67 DEFINE_SIZE_STATIC (6 + 256);
68};
69
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -040070struct CmapSubtableFormat4
71{
Behdad Esfahbod23335de2016-02-24 20:27:13 +090072 struct accelerator_t
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -040073 {
Behdad Esfahbod23335de2016-02-24 20:27:13 +090074 inline void init (const CmapSubtableFormat4 *subtable)
75 {
76 segCount = subtable->segCountX2 / 2;
77 endCount = subtable->values;
78 startCount = endCount + segCount + 1;
79 idDelta = startCount + segCount;
80 idRangeOffset = idDelta + segCount;
81 glyphIdArray = idRangeOffset + segCount;
82 glyphIdArrayLength = (subtable->length - 16 - 8 * segCount) / 2;
83 }
84
85 static inline bool get_glyph_func (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph)
86 {
87 const accelerator_t *thiz = (const accelerator_t *) obj;
88
89 /* Custom two-array bsearch. */
90 int min = 0, max = (int) thiz->segCount - 1;
Behdad Esfahbod6b191782018-01-10 03:07:30 +010091 const HBUINT16 *startCount = thiz->startCount;
92 const HBUINT16 *endCount = thiz->endCount;
Behdad Esfahbod23335de2016-02-24 20:27:13 +090093 unsigned int i;
94 while (min <= max)
95 {
96 int mid = (min + max) / 2;
97 if (codepoint < startCount[mid])
98 max = mid - 1;
99 else if (codepoint > endCount[mid])
100 min = mid + 1;
101 else
102 {
103 i = mid;
104 goto found;
105 }
106 }
107 return false;
108
109 found:
110 hb_codepoint_t gid;
111 unsigned int rangeOffset = thiz->idRangeOffset[i];
112 if (rangeOffset == 0)
113 gid = codepoint + thiz->idDelta[i];
114 else
115 {
116 /* Somebody has been smoking... */
117 unsigned int index = rangeOffset / 2 + (codepoint - thiz->startCount[i]) + i - thiz->segCount;
118 if (unlikely (index >= thiz->glyphIdArrayLength))
119 return false;
120 gid = thiz->glyphIdArray[index];
121 if (unlikely (!gid))
122 return false;
123 gid += thiz->idDelta[i];
124 }
125
126 *glyph = gid & 0xFFFFu;
127 return true;
128 }
129
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100130 const HBUINT16 *endCount;
131 const HBUINT16 *startCount;
132 const HBUINT16 *idDelta;
133 const HBUINT16 *idRangeOffset;
134 const HBUINT16 *glyphIdArray;
Behdad Esfahbod23335de2016-02-24 20:27:13 +0900135 unsigned int segCount;
Behdad Esfahbodc8a47452014-05-09 19:55:51 -0400136 unsigned int glyphIdArrayLength;
Behdad Esfahbod23335de2016-02-24 20:27:13 +0900137 };
Behdad Esfahbodc8a47452014-05-09 19:55:51 -0400138
Behdad Esfahbod23335de2016-02-24 20:27:13 +0900139 inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
140 {
141 accelerator_t accel;
142 accel.init (this);
143 return accel.get_glyph_func (&accel, codepoint, glyph);
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400144 }
145
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300146 inline bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbod257d1ad2014-06-04 18:47:55 -0400147 {
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400148 TRACE_SANITIZE (this);
Behdad Esfahbod257d1ad2014-06-04 18:47:55 -0400149 if (unlikely (!c->check_struct (this)))
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100150 return_trace (false);
Behdad Esfahbod257d1ad2014-06-04 18:47:55 -0400151
152 if (unlikely (!c->check_range (this, length)))
153 {
154 /* Some broken fonts have too long of a "length" value.
155 * If that is the case, just change the value to truncate
156 * the subtable at the end of the blob. */
157 uint16_t new_length = (uint16_t) MIN ((uintptr_t) 65535,
158 (uintptr_t) (c->end -
159 (char *) this));
160 if (!c->try_set (&length, new_length))
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100161 return_trace (false);
Behdad Esfahbod257d1ad2014-06-04 18:47:55 -0400162 }
163
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100164 return_trace (16 + 4 * (unsigned int) segCountX2 <= length);
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400165 }
166
167 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100168 HBUINT16 format; /* Format number is set to 4. */
169 HBUINT16 length; /* This is the length in bytes of the
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400170 * subtable. */
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100171 HBUINT16 languageZ; /* Ignore. */
172 HBUINT16 segCountX2; /* 2 x segCount. */
173 HBUINT16 searchRangeZ; /* 2 * (2**floor(log2(segCount))) */
174 HBUINT16 entrySelectorZ; /* log2(searchRange/2) */
175 HBUINT16 rangeShiftZ; /* 2 x segCount - searchRange */
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400176
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100177 HBUINT16 values[VAR];
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400178#if 0
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100179 HBUINT16 endCount[segCount]; /* End characterCode for each segment,
Behdad Esfahbod76271002014-07-11 14:54:42 -0400180 * last=0xFFFFu. */
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100181 HBUINT16 reservedPad; /* Set to 0. */
182 HBUINT16 startCount[segCount]; /* Start character code for each segment. */
183 HBINT16 idDelta[segCount]; /* Delta for all character codes in segment. */
184 HBUINT16 idRangeOffset[segCount];/* Offsets into glyphIdArray or 0 */
185 HBUINT16 glyphIdArray[VAR]; /* Glyph index array (arbitrary length) */
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400186#endif
187
188 public:
189 DEFINE_SIZE_ARRAY (14, values);
190};
191
Behdad Esfahbodd294a2c2014-05-12 17:58:31 -0400192struct CmapSubtableLongGroup
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400193{
194 friend struct CmapSubtableFormat12;
Behdad Esfahbodd294a2c2014-05-12 17:58:31 -0400195 friend struct CmapSubtableFormat13;
Rod Sheeter1cd98d02018-02-08 19:39:57 -0800196 friend struct cmap;
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400197
198 int cmp (hb_codepoint_t codepoint) const
199 {
200 if (codepoint < startCharCode) return -1;
201 if (codepoint > endCharCode) return +1;
202 return 0;
203 }
204
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300205 inline bool sanitize (hb_sanitize_context_t *c) const
206 {
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400207 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100208 return_trace (c->check_struct (this));
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400209 }
210
211 private:
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100212 HBUINT32 startCharCode; /* First character code in this group. */
213 HBUINT32 endCharCode; /* Last character code in this group. */
214 HBUINT32 glyphID; /* Glyph index; interpretation depends on
Behdad Esfahbodd294a2c2014-05-12 17:58:31 -0400215 * subtable format. */
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400216 public:
217 DEFINE_SIZE_STATIC (12);
218};
219
Behdad Esfahbod94759e82014-05-13 21:17:28 -0400220template <typename UINT>
221struct CmapSubtableTrimmed
Behdad Esfahbod91bbfca2014-05-12 18:19:29 -0400222{
Behdad Esfahbod91bbfca2014-05-12 18:19:29 -0400223 inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
224 {
225 /* Rely on our implicit array bound-checking. */
226 hb_codepoint_t gid = glyphIdArray[codepoint - startCharCode];
227 if (!gid)
228 return false;
229 *glyph = gid;
230 return true;
231 }
232
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300233 inline bool sanitize (hb_sanitize_context_t *c) const
234 {
Behdad Esfahbod91bbfca2014-05-12 18:19:29 -0400235 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100236 return_trace (c->check_struct (this) && glyphIdArray.sanitize (c));
Behdad Esfahbod91bbfca2014-05-12 18:19:29 -0400237 }
238
239 protected:
Behdad Esfahbod94759e82014-05-13 21:17:28 -0400240 UINT formatReserved; /* Subtable format and (maybe) padding. */
Behdad Esfahbod7d4ada62014-06-27 17:30:59 -0400241 UINT lengthZ; /* Byte length of this subtable. */
242 UINT languageZ; /* Ignore. */
Behdad Esfahbod94759e82014-05-13 21:17:28 -0400243 UINT startCharCode; /* First character code covered. */
Behdad Esfahbod9da552d2014-06-27 15:09:42 -0400244 ArrayOf<GlyphID, UINT>
Behdad Esfahbod91bbfca2014-05-12 18:19:29 -0400245 glyphIdArray; /* Array of glyph index values for character
246 * codes in the range. */
247 public:
Behdad Esfahbod94759e82014-05-13 21:17:28 -0400248 DEFINE_SIZE_ARRAY (5 * sizeof (UINT), glyphIdArray);
Behdad Esfahbod91bbfca2014-05-12 18:19:29 -0400249};
250
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100251struct CmapSubtableFormat6 : CmapSubtableTrimmed<HBUINT16> {};
252struct CmapSubtableFormat10 : CmapSubtableTrimmed<HBUINT32 > {};
Behdad Esfahbod91bbfca2014-05-12 18:19:29 -0400253
Behdad Esfahbodca7b7742014-05-13 21:26:34 -0400254template <typename T>
255struct CmapSubtableLongSegmented
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400256{
Rod Sheeter9275bd02018-02-09 17:33:34 -0800257 friend struct cmap;
258
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400259 inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
260 {
Behdad Esfahboddf554af2014-06-19 15:39:18 -0400261 int i = groups.bsearch (codepoint);
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400262 if (i == -1)
263 return false;
Behdad Esfahbodca7b7742014-05-13 21:26:34 -0400264 *glyph = T::group_get_glyph (groups[i], codepoint);
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400265 return true;
266 }
267
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300268 inline bool sanitize (hb_sanitize_context_t *c) const
269 {
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400270 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100271 return_trace (c->check_struct (this) && groups.sanitize (c));
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400272 }
273
Behdad Esfahbod6fa690c2018-02-18 16:27:59 -0800274 inline bool serialize (hb_serialize_context_t *c,
Rod Sheeter1725c352018-02-14 19:36:33 -0800275 hb_prealloced_array_t<CmapSubtableLongGroup> &group_data)
Rod Sheeter9275bd02018-02-09 17:33:34 -0800276 {
277 TRACE_SERIALIZE (this);
Behdad Esfahbod6fa690c2018-02-18 16:27:59 -0800278 if (unlikely (!c->extend_min (*this))) return_trace (false);
Rod Sheeter1725c352018-02-14 19:36:33 -0800279 Supplier<CmapSubtableLongGroup> supplier (group_data.array, group_data.len);
Behdad Esfahbod6fa690c2018-02-18 16:27:59 -0800280 if (unlikely (!groups.serialize (c, supplier, group_data.len))) return_trace (false);
Rod Sheeter9275bd02018-02-09 17:33:34 -0800281 return true;
282 }
283
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400284 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100285 HBUINT16 format; /* Subtable format; set to 12. */
286 HBUINT16 reservedZ; /* Reserved; set to 0. */
Ebrahim Byagowib799fc82018-04-11 18:36:09 +0430287 HBUINT32 lengthZ; /* Byte length of this subtable. */
288 HBUINT32 languageZ; /* Ignore. */
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100289 SortedArrayOf<CmapSubtableLongGroup, HBUINT32>
Behdad Esfahbodd294a2c2014-05-12 17:58:31 -0400290 groups; /* Groupings. */
291 public:
292 DEFINE_SIZE_ARRAY (16, groups);
293};
294
Behdad Esfahbodca7b7742014-05-13 21:26:34 -0400295struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
Behdad Esfahbodd294a2c2014-05-12 17:58:31 -0400296{
Behdad Esfahbodca7b7742014-05-13 21:26:34 -0400297 static inline hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
298 hb_codepoint_t u)
299 { return group.glyphID + (u - group.startCharCode); }
300};
Behdad Esfahbodd294a2c2014-05-12 17:58:31 -0400301
Behdad Esfahbodca7b7742014-05-13 21:26:34 -0400302struct CmapSubtableFormat13 : CmapSubtableLongSegmented<CmapSubtableFormat13>
303{
304 static inline hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
305 hb_codepoint_t u HB_UNUSED)
306 { return group.glyphID; }
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400307};
308
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400309typedef enum
310{
311 GLYPH_VARIANT_NOT_FOUND = 0,
312 GLYPH_VARIANT_FOUND = 1,
313 GLYPH_VARIANT_USE_DEFAULT = 2
314} glyph_variant_t;
315
316struct UnicodeValueRange
317{
318 inline int cmp (const hb_codepoint_t &codepoint) const
319 {
320 if (codepoint < startUnicodeValue) return -1;
321 if (codepoint > startUnicodeValue + additionalCount) return +1;
322 return 0;
323 }
324
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300325 inline bool sanitize (hb_sanitize_context_t *c) const
326 {
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400327 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100328 return_trace (c->check_struct (this));
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400329 }
330
331 UINT24 startUnicodeValue; /* First value in this range. */
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100332 HBUINT8 additionalCount; /* Number of additional values in this
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400333 * range. */
334 public:
335 DEFINE_SIZE_STATIC (4);
336};
337
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100338typedef SortedArrayOf<UnicodeValueRange, HBUINT32> DefaultUVS;
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400339
340struct UVSMapping
341{
342 inline int cmp (const hb_codepoint_t &codepoint) const
343 {
344 return unicodeValue.cmp (codepoint);
345 }
346
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300347 inline bool sanitize (hb_sanitize_context_t *c) const
348 {
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400349 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100350 return_trace (c->check_struct (this));
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400351 }
352
353 UINT24 unicodeValue; /* Base Unicode value of the UVS */
354 GlyphID glyphID; /* Glyph ID of the UVS */
355 public:
356 DEFINE_SIZE_STATIC (5);
357};
358
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100359typedef SortedArrayOf<UVSMapping, HBUINT32> NonDefaultUVS;
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400360
361struct VariationSelectorRecord
362{
363 inline glyph_variant_t get_glyph (hb_codepoint_t codepoint,
364 hb_codepoint_t *glyph,
365 const void *base) const
366 {
367 int i;
368 const DefaultUVS &defaults = base+defaultUVS;
369 i = defaults.bsearch (codepoint);
370 if (i != -1)
371 return GLYPH_VARIANT_USE_DEFAULT;
372 const NonDefaultUVS &nonDefaults = base+nonDefaultUVS;
373 i = nonDefaults.bsearch (codepoint);
374 if (i != -1)
375 {
376 *glyph = nonDefaults[i].glyphID;
377 return GLYPH_VARIANT_FOUND;
378 }
379 return GLYPH_VARIANT_NOT_FOUND;
380 }
381
382 inline int cmp (const hb_codepoint_t &variation_selector) const
383 {
384 return varSelector.cmp (variation_selector);
385 }
386
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300387 inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
388 {
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400389 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100390 return_trace (c->check_struct (this) &&
391 defaultUVS.sanitize (c, base) &&
392 nonDefaultUVS.sanitize (c, base));
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400393 }
394
395 UINT24 varSelector; /* Variation selector. */
Behdad Esfahbod5e156fa2017-01-22 20:28:56 -0800396 LOffsetTo<DefaultUVS>
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400397 defaultUVS; /* Offset to Default UVS Table. May be 0. */
Behdad Esfahbod5e156fa2017-01-22 20:28:56 -0800398 LOffsetTo<NonDefaultUVS>
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400399 nonDefaultUVS; /* Offset to Non-Default UVS Table. May be 0. */
400 public:
401 DEFINE_SIZE_STATIC (11);
402};
403
404struct CmapSubtableFormat14
405{
406 inline glyph_variant_t get_glyph_variant (hb_codepoint_t codepoint,
407 hb_codepoint_t variation_selector,
408 hb_codepoint_t *glyph) const
409 {
410 return record[record.bsearch(variation_selector)].get_glyph (codepoint, glyph, this);
411 }
412
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300413 inline bool sanitize (hb_sanitize_context_t *c) const
414 {
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400415 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100416 return_trace (c->check_struct (this) &&
417 record.sanitize (c, this));
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400418 }
419
420 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100421 HBUINT16 format; /* Format number is set to 14. */
422 HBUINT32 lengthZ; /* Byte length of this subtable. */
423 SortedArrayOf<VariationSelectorRecord, HBUINT32>
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400424 record; /* Variation selector records; sorted
425 * in increasing order of `varSelector'. */
426 public:
427 DEFINE_SIZE_ARRAY (10, record);
428};
429
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400430struct CmapSubtable
431{
Behdad Esfahbodc9558762014-05-14 00:42:18 -0400432 /* Note: We intentionally do NOT implement subtable formats 2 and 8. */
433
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400434 inline bool get_glyph (hb_codepoint_t codepoint,
435 hb_codepoint_t *glyph) const
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400436 {
437 switch (u.format) {
Rod Sheeter1725c352018-02-14 19:36:33 -0800438 case 0: return u.format0 .get_glyph (codepoint, glyph);
439 case 4: return u.format4 .get_glyph (codepoint, glyph);
440 case 6: return u.format6 .get_glyph (codepoint, glyph);
441 case 10: return u.format10.get_glyph (codepoint, glyph);
442 case 12: return u.format12.get_glyph (codepoint, glyph);
443 case 13: return u.format13.get_glyph (codepoint, glyph);
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400444 case 14:
445 default: return false;
446 }
447 }
448
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300449 inline bool sanitize (hb_sanitize_context_t *c) const
450 {
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400451 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100452 if (!u.format.sanitize (c)) return_trace (false);
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400453 switch (u.format) {
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100454 case 0: return_trace (u.format0 .sanitize (c));
455 case 4: return_trace (u.format4 .sanitize (c));
456 case 6: return_trace (u.format6 .sanitize (c));
457 case 10: return_trace (u.format10.sanitize (c));
458 case 12: return_trace (u.format12.sanitize (c));
459 case 13: return_trace (u.format13.sanitize (c));
460 case 14: return_trace (u.format14.sanitize (c));
461 default:return_trace (true);
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400462 }
463 }
464
Behdad Esfahbod5473ebf2016-02-24 19:32:43 +0900465 public:
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400466 union {
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100467 HBUINT16 format; /* Format identifier */
Behdad Esfahbodb7878cd2014-05-13 21:47:51 -0400468 CmapSubtableFormat0 format0;
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400469 CmapSubtableFormat4 format4;
Behdad Esfahbod91bbfca2014-05-12 18:19:29 -0400470 CmapSubtableFormat6 format6;
471 CmapSubtableFormat10 format10;
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400472 CmapSubtableFormat12 format12;
Behdad Esfahbodd294a2c2014-05-12 17:58:31 -0400473 CmapSubtableFormat13 format13;
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400474 CmapSubtableFormat14 format14;
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400475 } u;
476 public:
477 DEFINE_SIZE_UNION (2, format);
478};
479
480
481struct EncodingRecord
482{
Behdad Esfahbodf1a72fe2014-06-04 19:00:29 -0400483 inline int cmp (const EncodingRecord &other) const
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400484 {
485 int ret;
Behdad Esfahbodf1a72fe2014-06-04 19:00:29 -0400486 ret = platformID.cmp (other.platformID);
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400487 if (ret) return ret;
Behdad Esfahbodf1a72fe2014-06-04 19:00:29 -0400488 ret = encodingID.cmp (other.encodingID);
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400489 if (ret) return ret;
490 return 0;
491 }
492
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300493 inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
494 {
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400495 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100496 return_trace (c->check_struct (this) &&
497 subtable.sanitize (c, base));
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400498 }
499
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100500 HBUINT16 platformID; /* Platform ID. */
501 HBUINT16 encodingID; /* Platform-specific encoding ID. */
Behdad Esfahbod5e156fa2017-01-22 20:28:56 -0800502 LOffsetTo<CmapSubtable>
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400503 subtable; /* Byte offset from beginning of table to the subtable for this encoding. */
504 public:
505 DEFINE_SIZE_STATIC (8);
506};
507
508struct cmap
509{
510 static const hb_tag_t tableTag = HB_OT_TAG_cmap;
511
Behdad Esfahbod977ddff2017-11-14 20:06:19 -0800512 inline bool sanitize (hb_sanitize_context_t *c) const
513 {
514 TRACE_SANITIZE (this);
515 return_trace (c->check_struct (this) &&
516 likely (version == 0) &&
517 encodingRecord.sanitize (c, this));
518 }
519
Rod Sheeter1725c352018-02-14 19:36:33 -0800520 inline bool populate_groups (hb_subset_plan_t *plan,
521 hb_prealloced_array_t<CmapSubtableLongGroup> *groups) const
Rod Sheeter0859a002018-02-07 15:59:36 -0800522 {
Rod Sheeter1cd98d02018-02-08 19:39:57 -0800523 CmapSubtableLongGroup *group = nullptr;
Rod Sheeter1330edc2018-02-12 14:29:23 -0800524 for (unsigned int i = 0; i < plan->codepoints.len; i++) {
525
526 hb_codepoint_t cp = plan->codepoints[i];
Rod Sheetera5713bc2018-02-12 11:30:45 -0800527 if (!group || cp - 1 != group->endCharCode)
Rod Sheeter1cd98d02018-02-08 19:39:57 -0800528 {
Rod Sheeter1725c352018-02-14 19:36:33 -0800529 group = groups->push ();
530 group->startCharCode.set (cp);
531 group->endCharCode.set (cp);
Rod Sheeter1330edc2018-02-12 14:29:23 -0800532 hb_codepoint_t new_gid;
Rod Sheeter1725c352018-02-14 19:36:33 -0800533 if (unlikely (!hb_subset_plan_new_gid_for_codepoint (plan, cp, &new_gid)))
Rod Sheeter1330edc2018-02-12 14:29:23 -0800534 {
535 DEBUG_MSG(SUBSET, nullptr, "Unable to find new gid for %04x", cp);
536 return false;
537 }
Rod Sheeter1725c352018-02-14 19:36:33 -0800538 group->glyphID.set (new_gid);
Rod Sheeter1cd98d02018-02-08 19:39:57 -0800539 } else
540 {
Rod Sheeter1725c352018-02-14 19:36:33 -0800541 group->endCharCode.set (cp);
Rod Sheeter1cd98d02018-02-08 19:39:57 -0800542 }
543 }
544
545 DEBUG_MSG(SUBSET, nullptr, "cmap");
Rod Sheeter9275bd02018-02-09 17:33:34 -0800546 for (unsigned int i = 0; i < groups->len; i++) {
547 CmapSubtableLongGroup& group = (*groups)[i];
548 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));
Rod Sheeter1cd98d02018-02-08 19:39:57 -0800549 }
Rod Sheeter1330edc2018-02-12 14:29:23 -0800550
551 return true;
Rod Sheeter9275bd02018-02-09 17:33:34 -0800552 }
553
Behdad Esfahbodb1bd0b52018-02-14 18:50:19 -0800554 inline bool _subset (hb_prealloced_array_t<CmapSubtableLongGroup> &groups,
555 size_t dest_sz,
556 void *dest) const
Rod Sheeter9275bd02018-02-09 17:33:34 -0800557 {
Behdad Esfahbod6fa690c2018-02-18 16:27:59 -0800558 hb_serialize_context_t c (dest, dest_sz);
Rod Sheeter9275bd02018-02-09 17:33:34 -0800559
Behdad Esfahbod6fa690c2018-02-18 16:27:59 -0800560 OT::cmap *cmap = c.start_serialize<OT::cmap> ();
561 if (unlikely (!c.extend_min (*cmap)))
Rod Sheeter9275bd02018-02-09 17:33:34 -0800562 {
563 return false;
564 }
565
Rod Sheeter1725c352018-02-14 19:36:33 -0800566 cmap->version.set (0);
Rod Sheeter9275bd02018-02-09 17:33:34 -0800567
Behdad Esfahbod6fa690c2018-02-18 16:27:59 -0800568 if (unlikely (!cmap->encodingRecord.serialize (&c, /* numTables */ 1))) return false;
Rod Sheeter9275bd02018-02-09 17:33:34 -0800569
570 EncodingRecord &rec = cmap->encodingRecord[0];
571 rec.platformID.set (3); // Windows
Rod Sheeterd1a4d562018-02-12 16:25:32 -0800572 rec.encodingID.set (10); // Unicode UCS-4
Rod Sheeter9275bd02018-02-09 17:33:34 -0800573
Rod Sheeter0301e5b2018-02-12 10:12:11 -0800574 /* capture offset to subtable */
Behdad Esfahbod6fa690c2018-02-18 16:27:59 -0800575 CmapSubtable &subtable = rec.subtable.serialize (&c, cmap);
Rod Sheeter0301e5b2018-02-12 10:12:11 -0800576
Rod Sheeter1725c352018-02-14 19:36:33 -0800577 subtable.u.format.set (12);
Rod Sheeter9275bd02018-02-09 17:33:34 -0800578
579 CmapSubtableFormat12 &format12 = subtable.u.format12;
Behdad Esfahbod6fa690c2018-02-18 16:27:59 -0800580 if (unlikely (!c.extend_min (format12))) return false;
Rod Sheeter0301e5b2018-02-12 10:12:11 -0800581
Rod Sheeter1725c352018-02-14 19:36:33 -0800582 format12.format.set (12);
583 format12.reservedZ.set (0);
584 format12.lengthZ.set (16 + 12 * groups.len);
Rod Sheeter9275bd02018-02-09 17:33:34 -0800585
Behdad Esfahbod6fa690c2018-02-18 16:27:59 -0800586 if (unlikely (!format12.serialize (&c, groups))) return false;
Rod Sheeter9275bd02018-02-09 17:33:34 -0800587
Behdad Esfahbod6fa690c2018-02-18 16:27:59 -0800588 c.end_serialize ();
Rod Sheeter0301e5b2018-02-12 10:12:11 -0800589
Rod Sheeter0859a002018-02-07 15:59:36 -0800590 return true;
591 }
592
Rod Sheeter3ed70e52018-02-14 15:24:49 -0800593 inline bool subset (hb_subset_plan_t *plan) const
Rod Sheeter9275bd02018-02-09 17:33:34 -0800594 {
Behdad Esfahbod41906cd2018-02-11 19:46:06 -0600595 hb_auto_array_t<CmapSubtableLongGroup> groups;
Rod Sheeter9275bd02018-02-09 17:33:34 -0800596
Rod Sheeter1725c352018-02-14 19:36:33 -0800597 if (unlikely (!populate_groups (plan, &groups))) return false;
Rod Sheeter9275bd02018-02-09 17:33:34 -0800598
599 // We now know how big our blob needs to be
600 // TODO use APIs from the structs to get size?
601 size_t dest_sz = 4 // header
602 + 8 // 1 EncodingRecord
603 + 16 // Format 12 header
604 + 12 * groups.len; // SequentialMapGroup records
Garret Rieger0fb8a5c2018-02-23 15:37:43 -0800605 void *dest = malloc (dest_sz);
Rod Sheeter1725c352018-02-14 19:36:33 -0800606 if (unlikely (!dest)) {
Behdad Esfahbodd1f16fc2018-02-20 10:32:09 -0800607 DEBUG_MSG(SUBSET, nullptr, "Unable to alloc %lu for cmap subset output", (unsigned long) dest_sz);
Rod Sheeterfa877702018-02-14 14:16:25 -0800608 return false;
Rod Sheeter9275bd02018-02-09 17:33:34 -0800609 }
610
Rod Sheeter1725c352018-02-14 19:36:33 -0800611 if (unlikely (!_subset (groups, dest_sz, dest)))
Rod Sheeter9275bd02018-02-09 17:33:34 -0800612 {
Rod Sheeter1725c352018-02-14 19:36:33 -0800613 free (dest);
Rod Sheeterfa877702018-02-14 14:16:25 -0800614 return false;
Rod Sheeter9275bd02018-02-09 17:33:34 -0800615 }
616
617 // all done, write the blob into dest
Rod Sheeterfa877702018-02-14 14:16:25 -0800618 hb_blob_t *cmap_prime = hb_blob_create ((const char *)dest,
619 dest_sz,
620 HB_MEMORY_MODE_READONLY,
Garret Rieger0fb8a5c2018-02-23 15:37:43 -0800621 dest,
Rod Sheeterfa877702018-02-14 14:16:25 -0800622 free);
Garret Rieger0fb8a5c2018-02-23 15:37:43 -0800623 bool result = hb_subset_plan_add_table (plan, HB_OT_TAG_cmap, cmap_prime);
624 hb_blob_destroy (cmap_prime);
625 return result;
Rod Sheeter9275bd02018-02-09 17:33:34 -0800626 }
627
Behdad Esfahbod977ddff2017-11-14 20:06:19 -0800628 struct accelerator_t
629 {
630 inline void init (hb_face_t *face)
631 {
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100632 this->blob = OT::Sanitizer<OT::cmap>().sanitize (face->reference_table (HB_OT_TAG_cmap));
Behdad Esfahbod977ddff2017-11-14 20:06:19 -0800633 const OT::cmap *cmap = OT::Sanitizer<OT::cmap>::lock_instance (this->blob);
634 const OT::CmapSubtable *subtable = nullptr;
635 const OT::CmapSubtableFormat14 *subtable_uvs = nullptr;
636
637 bool symbol = false;
638 /* 32-bit subtables. */
639 if (!subtable) subtable = cmap->find_subtable (3, 10);
640 if (!subtable) subtable = cmap->find_subtable (0, 6);
641 if (!subtable) subtable = cmap->find_subtable (0, 4);
642 /* 16-bit subtables. */
643 if (!subtable) subtable = cmap->find_subtable (3, 1);
644 if (!subtable) subtable = cmap->find_subtable (0, 3);
645 if (!subtable) subtable = cmap->find_subtable (0, 2);
646 if (!subtable) subtable = cmap->find_subtable (0, 1);
647 if (!subtable) subtable = cmap->find_subtable (0, 0);
648 if (!subtable)
649 {
650 subtable = cmap->find_subtable (3, 0);
651 if (subtable) symbol = true;
652 }
653 /* Meh. */
654 if (!subtable) subtable = &OT::Null(OT::CmapSubtable);
655
656 /* UVS subtable. */
657 if (!subtable_uvs)
658 {
659 const OT::CmapSubtable *st = cmap->find_subtable (0, 5);
660 if (st && st->u.format == 14)
661 subtable_uvs = &st->u.format14;
662 }
663 /* Meh. */
664 if (!subtable_uvs) subtable_uvs = &OT::Null(OT::CmapSubtableFormat14);
665
666 this->uvs_table = subtable_uvs;
667
668 this->get_glyph_data = subtable;
669 if (unlikely (symbol))
670 this->get_glyph_func = get_glyph_from_symbol<OT::CmapSubtable>;
671 else
672 switch (subtable->u.format) {
673 /* Accelerate format 4 and format 12. */
674 default: this->get_glyph_func = get_glyph_from<OT::CmapSubtable>; break;
675 case 12: this->get_glyph_func = get_glyph_from<OT::CmapSubtableFormat12>; break;
676 case 4:
677 {
678 this->format4_accel.init (&subtable->u.format4);
679 this->get_glyph_data = &this->format4_accel;
680 this->get_glyph_func = this->format4_accel.get_glyph_func;
681 }
682 break;
683 }
684 }
685
686 inline void fini (void)
687 {
688 hb_blob_destroy (this->blob);
689 }
690
691 inline bool get_nominal_glyph (hb_codepoint_t unicode,
692 hb_codepoint_t *glyph) const
693 {
694 return this->get_glyph_func (this->get_glyph_data, unicode, glyph);
695 }
696
697 inline bool get_variation_glyph (hb_codepoint_t unicode,
698 hb_codepoint_t variation_selector,
699 hb_codepoint_t *glyph) const
700 {
701 switch (this->uvs_table->get_glyph_variant (unicode,
702 variation_selector,
703 glyph))
704 {
705 case OT::GLYPH_VARIANT_NOT_FOUND: return false;
706 case OT::GLYPH_VARIANT_FOUND: return true;
707 case OT::GLYPH_VARIANT_USE_DEFAULT: break;
708 }
709
710 return get_nominal_glyph (unicode, glyph);
711 }
712
713 protected:
714 typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj,
715 hb_codepoint_t codepoint,
716 hb_codepoint_t *glyph);
717
718 template <typename Type>
719 static inline bool get_glyph_from (const void *obj,
720 hb_codepoint_t codepoint,
721 hb_codepoint_t *glyph)
722 {
723 const Type *typed_obj = (const Type *) obj;
724 return typed_obj->get_glyph (codepoint, glyph);
725 }
726
727 template <typename Type>
728 static inline bool get_glyph_from_symbol (const void *obj,
729 hb_codepoint_t codepoint,
730 hb_codepoint_t *glyph)
731 {
732 const Type *typed_obj = (const Type *) obj;
733 if (likely (typed_obj->get_glyph (codepoint, glyph)))
734 return true;
735
736 if (codepoint <= 0x00FFu)
737 {
738 /* For symbol-encoded OpenType fonts, we duplicate the
739 * U+F000..F0FF range at U+0000..U+00FF. That's what
740 * Windows seems to do, and that's hinted about at:
Ebrahim Byagowif24b0b92018-04-12 13:40:45 +0430741 * https://docs.microsoft.com/en-us/typography/opentype/spec/recom
Behdad Esfahbod977ddff2017-11-14 20:06:19 -0800742 * under "Non-Standard (Symbol) Fonts". */
743 return typed_obj->get_glyph (0xF000u + codepoint, glyph);
744 }
745
746 return false;
747 }
748
749 private:
750 hb_cmap_get_glyph_func_t get_glyph_func;
751 const void *get_glyph_data;
752 OT::CmapSubtableFormat4::accelerator_t format4_accel;
753
754 const OT::CmapSubtableFormat14 *uvs_table;
755 hb_blob_t *blob;
756 };
757
758 protected:
759
Behdad Esfahbod3608a682014-05-12 13:46:29 -0400760 inline const CmapSubtable *find_subtable (unsigned int platform_id,
761 unsigned int encoding_id) const
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400762 {
763 EncodingRecord key;
764 key.platformID.set (platform_id);
765 key.encodingID.set (encoding_id);
766
Behdad Esfahboddf554af2014-06-19 15:39:18 -0400767 /* Note: We can use bsearch, but since it has no performance
768 * implications, we use lsearch and as such accept fonts with
769 * unsorted subtable list. */
770 int result = encodingRecord./*bsearch*/lsearch (key);
Behdad Esfahbod500737e2014-06-04 18:17:29 -0400771 if (result == -1 || !encodingRecord[result].subtable)
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200772 return nullptr;
Behdad Esfahbod3608a682014-05-12 13:46:29 -0400773
774 return &(this+encodingRecord[result].subtable);
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400775 }
776
Behdad Esfahbod977ddff2017-11-14 20:06:19 -0800777 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100778 HBUINT16 version; /* Table version number (0). */
Behdad Esfahboddf554af2014-06-19 15:39:18 -0400779 SortedArrayOf<EncodingRecord>
Behdad Esfahbodf1a72fe2014-06-04 19:00:29 -0400780 encodingRecord; /* Encoding tables. */
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400781 public:
782 DEFINE_SIZE_ARRAY (4, encodingRecord);
783};
784
785
786} /* namespace OT */
787
788
789#endif /* HB_OT_CMAP_TABLE_HH */