blob: a2a6f8ba8c44ce97b908ce01bba2ec76a514e0f6 [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
33namespace OT {
34
35
36/*
37 * cmap -- Character To Glyph Index Mapping Table
38 */
39
40#define HB_OT_TAG_cmap HB_TAG('c','m','a','p')
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
Rod Sheeter9275bd02018-02-09 17:33:34 -0800274 inline bool serialize(hb_serialize_context_t *context,
275 unsigned int group_count,
276 Supplier<CmapSubtableLongGroup> &group_supplier)
277 {
278 TRACE_SERIALIZE (this);
279 if (unlikely(!context->extend_min (*this))) return_trace (false);
280 if (unlikely(!groups.serialize(context, group_count))) return_trace (false);
Behdad Esfahbod9aa2eb62018-02-11 19:00:42 -0600281 for (unsigned int i = 0; i < group_count; i++)
282 {
Rod Sheeter9275bd02018-02-09 17:33:34 -0800283 const CmapSubtableLongGroup &group = group_supplier[i];
284 memcpy(&groups[i], &group, sizeof(group));
285 }
286 return true;
287 }
288
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400289 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100290 HBUINT16 format; /* Subtable format; set to 12. */
291 HBUINT16 reservedZ; /* Reserved; set to 0. */
292 HBUINT32 lengthZ; /* Byte length of this subtable. */
293 HBUINT32 languageZ; /* Ignore. */
294 SortedArrayOf<CmapSubtableLongGroup, HBUINT32>
Behdad Esfahbodd294a2c2014-05-12 17:58:31 -0400295 groups; /* Groupings. */
296 public:
297 DEFINE_SIZE_ARRAY (16, groups);
298};
299
Behdad Esfahbodca7b7742014-05-13 21:26:34 -0400300struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
Behdad Esfahbodd294a2c2014-05-12 17:58:31 -0400301{
Behdad Esfahbodca7b7742014-05-13 21:26:34 -0400302 static inline hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
303 hb_codepoint_t u)
304 { return group.glyphID + (u - group.startCharCode); }
305};
Behdad Esfahbodd294a2c2014-05-12 17:58:31 -0400306
Behdad Esfahbodca7b7742014-05-13 21:26:34 -0400307struct CmapSubtableFormat13 : CmapSubtableLongSegmented<CmapSubtableFormat13>
308{
309 static inline hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
310 hb_codepoint_t u HB_UNUSED)
311 { return group.glyphID; }
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400312};
313
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400314typedef enum
315{
316 GLYPH_VARIANT_NOT_FOUND = 0,
317 GLYPH_VARIANT_FOUND = 1,
318 GLYPH_VARIANT_USE_DEFAULT = 2
319} glyph_variant_t;
320
321struct UnicodeValueRange
322{
323 inline int cmp (const hb_codepoint_t &codepoint) const
324 {
325 if (codepoint < startUnicodeValue) return -1;
326 if (codepoint > startUnicodeValue + additionalCount) return +1;
327 return 0;
328 }
329
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300330 inline bool sanitize (hb_sanitize_context_t *c) const
331 {
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400332 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100333 return_trace (c->check_struct (this));
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400334 }
335
336 UINT24 startUnicodeValue; /* First value in this range. */
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100337 HBUINT8 additionalCount; /* Number of additional values in this
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400338 * range. */
339 public:
340 DEFINE_SIZE_STATIC (4);
341};
342
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100343typedef SortedArrayOf<UnicodeValueRange, HBUINT32> DefaultUVS;
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400344
345struct UVSMapping
346{
347 inline int cmp (const hb_codepoint_t &codepoint) const
348 {
349 return unicodeValue.cmp (codepoint);
350 }
351
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300352 inline bool sanitize (hb_sanitize_context_t *c) const
353 {
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400354 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100355 return_trace (c->check_struct (this));
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400356 }
357
358 UINT24 unicodeValue; /* Base Unicode value of the UVS */
359 GlyphID glyphID; /* Glyph ID of the UVS */
360 public:
361 DEFINE_SIZE_STATIC (5);
362};
363
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100364typedef SortedArrayOf<UVSMapping, HBUINT32> NonDefaultUVS;
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400365
366struct VariationSelectorRecord
367{
368 inline glyph_variant_t get_glyph (hb_codepoint_t codepoint,
369 hb_codepoint_t *glyph,
370 const void *base) const
371 {
372 int i;
373 const DefaultUVS &defaults = base+defaultUVS;
374 i = defaults.bsearch (codepoint);
375 if (i != -1)
376 return GLYPH_VARIANT_USE_DEFAULT;
377 const NonDefaultUVS &nonDefaults = base+nonDefaultUVS;
378 i = nonDefaults.bsearch (codepoint);
379 if (i != -1)
380 {
381 *glyph = nonDefaults[i].glyphID;
382 return GLYPH_VARIANT_FOUND;
383 }
384 return GLYPH_VARIANT_NOT_FOUND;
385 }
386
387 inline int cmp (const hb_codepoint_t &variation_selector) const
388 {
389 return varSelector.cmp (variation_selector);
390 }
391
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300392 inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
393 {
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400394 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100395 return_trace (c->check_struct (this) &&
396 defaultUVS.sanitize (c, base) &&
397 nonDefaultUVS.sanitize (c, base));
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400398 }
399
400 UINT24 varSelector; /* Variation selector. */
Behdad Esfahbod5e156fa2017-01-22 20:28:56 -0800401 LOffsetTo<DefaultUVS>
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400402 defaultUVS; /* Offset to Default UVS Table. May be 0. */
Behdad Esfahbod5e156fa2017-01-22 20:28:56 -0800403 LOffsetTo<NonDefaultUVS>
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400404 nonDefaultUVS; /* Offset to Non-Default UVS Table. May be 0. */
405 public:
406 DEFINE_SIZE_STATIC (11);
407};
408
409struct CmapSubtableFormat14
410{
411 inline glyph_variant_t get_glyph_variant (hb_codepoint_t codepoint,
412 hb_codepoint_t variation_selector,
413 hb_codepoint_t *glyph) const
414 {
415 return record[record.bsearch(variation_selector)].get_glyph (codepoint, glyph, this);
416 }
417
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300418 inline bool sanitize (hb_sanitize_context_t *c) const
419 {
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400420 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100421 return_trace (c->check_struct (this) &&
422 record.sanitize (c, this));
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400423 }
424
425 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100426 HBUINT16 format; /* Format number is set to 14. */
427 HBUINT32 lengthZ; /* Byte length of this subtable. */
428 SortedArrayOf<VariationSelectorRecord, HBUINT32>
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400429 record; /* Variation selector records; sorted
430 * in increasing order of `varSelector'. */
431 public:
432 DEFINE_SIZE_ARRAY (10, record);
433};
434
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400435struct CmapSubtable
436{
Behdad Esfahbodc9558762014-05-14 00:42:18 -0400437 /* Note: We intentionally do NOT implement subtable formats 2 and 8. */
438
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400439 inline bool get_glyph (hb_codepoint_t codepoint,
440 hb_codepoint_t *glyph) const
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400441 {
442 switch (u.format) {
Behdad Esfahbodb7878cd2014-05-13 21:47:51 -0400443 case 0: return u.format0 .get_glyph(codepoint, glyph);
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400444 case 4: return u.format4 .get_glyph(codepoint, glyph);
Behdad Esfahbod91bbfca2014-05-12 18:19:29 -0400445 case 6: return u.format6 .get_glyph(codepoint, glyph);
446 case 10: return u.format10.get_glyph(codepoint, glyph);
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400447 case 12: return u.format12.get_glyph(codepoint, glyph);
Behdad Esfahbodd294a2c2014-05-12 17:58:31 -0400448 case 13: return u.format13.get_glyph(codepoint, glyph);
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400449 case 14:
450 default: return false;
451 }
452 }
453
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300454 inline bool sanitize (hb_sanitize_context_t *c) const
455 {
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400456 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100457 if (!u.format.sanitize (c)) return_trace (false);
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400458 switch (u.format) {
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100459 case 0: return_trace (u.format0 .sanitize (c));
460 case 4: return_trace (u.format4 .sanitize (c));
461 case 6: return_trace (u.format6 .sanitize (c));
462 case 10: return_trace (u.format10.sanitize (c));
463 case 12: return_trace (u.format12.sanitize (c));
464 case 13: return_trace (u.format13.sanitize (c));
465 case 14: return_trace (u.format14.sanitize (c));
466 default:return_trace (true);
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400467 }
468 }
469
Behdad Esfahbod5473ebf2016-02-24 19:32:43 +0900470 public:
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400471 union {
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100472 HBUINT16 format; /* Format identifier */
Behdad Esfahbodb7878cd2014-05-13 21:47:51 -0400473 CmapSubtableFormat0 format0;
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400474 CmapSubtableFormat4 format4;
Behdad Esfahbod91bbfca2014-05-12 18:19:29 -0400475 CmapSubtableFormat6 format6;
476 CmapSubtableFormat10 format10;
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400477 CmapSubtableFormat12 format12;
Behdad Esfahbodd294a2c2014-05-12 17:58:31 -0400478 CmapSubtableFormat13 format13;
Behdad Esfahboda5a47362014-06-27 17:03:22 -0400479 CmapSubtableFormat14 format14;
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400480 } u;
481 public:
482 DEFINE_SIZE_UNION (2, format);
483};
484
485
486struct EncodingRecord
487{
Behdad Esfahbodf1a72fe2014-06-04 19:00:29 -0400488 inline int cmp (const EncodingRecord &other) const
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400489 {
490 int ret;
Behdad Esfahbodf1a72fe2014-06-04 19:00:29 -0400491 ret = platformID.cmp (other.platformID);
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400492 if (ret) return ret;
Behdad Esfahbodf1a72fe2014-06-04 19:00:29 -0400493 ret = encodingID.cmp (other.encodingID);
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400494 if (ret) return ret;
495 return 0;
496 }
497
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300498 inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
499 {
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400500 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100501 return_trace (c->check_struct (this) &&
502 subtable.sanitize (c, base));
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400503 }
504
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100505 HBUINT16 platformID; /* Platform ID. */
506 HBUINT16 encodingID; /* Platform-specific encoding ID. */
Behdad Esfahbod5e156fa2017-01-22 20:28:56 -0800507 LOffsetTo<CmapSubtable>
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400508 subtable; /* Byte offset from beginning of table to the subtable for this encoding. */
509 public:
510 DEFINE_SIZE_STATIC (8);
511};
512
513struct cmap
514{
515 static const hb_tag_t tableTag = HB_OT_TAG_cmap;
516
Behdad Esfahbod977ddff2017-11-14 20:06:19 -0800517 inline bool sanitize (hb_sanitize_context_t *c) const
518 {
519 TRACE_SANITIZE (this);
520 return_trace (c->check_struct (this) &&
521 likely (version == 0) &&
522 encodingRecord.sanitize (c, this));
523 }
524
Behdad Esfahbodc31fcf42018-02-10 14:20:10 -0600525 inline void populate_groups(hb_prealloced_array_t<hb_codepoint_t> &codepoints,
526 hb_prealloced_array_t<CmapSubtableLongGroup> *groups) const
Rod Sheeter0859a002018-02-07 15:59:36 -0800527 {
Rod Sheeter1cd98d02018-02-08 19:39:57 -0800528 CmapSubtableLongGroup *group = nullptr;
Rod Sheeter9275bd02018-02-09 17:33:34 -0800529 for (unsigned int i = 0; i < codepoints.len; i++) {
530 hb_codepoint_t cp = codepoints[i];
Rod Sheeter1cd98d02018-02-08 19:39:57 -0800531 if (!group)
532 {
Rod Sheeter9275bd02018-02-09 17:33:34 -0800533 group = groups->push();
Rod Sheeter1cd98d02018-02-08 19:39:57 -0800534 group->startCharCode.set(cp);
535 group->endCharCode.set(cp);
536 group->glyphID.set(i); // index in codepoints is new gid
537 } else if (cp -1 == group->endCharCode)
538 {
539 group->endCharCode.set(cp);
540 } else
541 {
542 group = nullptr;
543 }
544 }
545
546 DEBUG_MSG(SUBSET, nullptr, "cmap");
Rod Sheeter9275bd02018-02-09 17:33:34 -0800547 for (unsigned int i = 0; i < groups->len; i++) {
548 CmapSubtableLongGroup& group = (*groups)[i];
549 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 -0800550 }
Rod Sheeter9275bd02018-02-09 17:33:34 -0800551 }
552
Behdad Esfahbodc31fcf42018-02-10 14:20:10 -0600553 hb_bool_t _subset (hb_prealloced_array_t<CmapSubtableLongGroup> &groups,
Rod Sheeter9275bd02018-02-09 17:33:34 -0800554 size_t dest_sz,
555 void *dest) const
556 {
557 hb_serialize_context_t context(dest, dest_sz);
558
559 OT::cmap *cmap = context.start_serialize<OT::cmap> ();
560 if (unlikely(!context.extend_min(*cmap)))
561 {
562 return false;
563 }
564
565 cmap->version.set(0);
566
567 if (unlikely(!cmap->encodingRecord.serialize(&context, /* numTables */ 1)))
568 {
569 return false;
570 }
571
572 EncodingRecord &rec = cmap->encodingRecord[0];
573 rec.platformID.set (3); // Windows
574 rec.encodingID.set (1); // Unicode BMP
575
576 CmapSubtable &subtable = rec.subtable.serialize(&context, &rec.subtable);
577 subtable.u.format.set(12);
578
579 CmapSubtableFormat12 &format12 = subtable.u.format12;
580 format12.format.set(12);
581 format12.reservedZ.set(0);
582
583 OT::Supplier<CmapSubtableLongGroup> group_supplier (&groups[0], groups.len, sizeof (CmapSubtableLongGroup));
584 if (unlikely(!format12.serialize(&context, groups.len, group_supplier)))
Rod Sheeter9275bd02018-02-09 17:33:34 -0800585 return false;
Rod Sheeter9275bd02018-02-09 17:33:34 -0800586
587 context.end_serialize ();
Rod Sheeter0859a002018-02-07 15:59:36 -0800588 return true;
589 }
590
Rod Sheeter9275bd02018-02-09 17:33:34 -0800591 hb_blob_t * subset (hb_subset_plan_t *plan, hb_face_t *source) const
592 {
Behdad Esfahbodc31fcf42018-02-10 14:20:10 -0600593 hb_prealloced_array_t<CmapSubtableLongGroup> groups;
Rod Sheeter9275bd02018-02-09 17:33:34 -0800594
595 populate_groups(plan->codepoints, &groups);
596
597 // We now know how big our blob needs to be
598 // TODO use APIs from the structs to get size?
599 size_t dest_sz = 4 // header
600 + 8 // 1 EncodingRecord
601 + 16 // Format 12 header
602 + 12 * groups.len; // SequentialMapGroup records
603 void *dest = calloc(dest_sz, 1);
604 if (unlikely(!dest)) {
605 DEBUG_MSG(SUBSET, nullptr, "Unable to alloc %ld for cmap subset output", dest_sz);
606 return nullptr;
607 }
608
609 if (unlikely(!_subset(groups, dest_sz, dest)))
610 {
611 free(dest);
612 return nullptr;
613 }
614
615 // all done, write the blob into dest
616 return hb_blob_create((const char *)dest,
617 dest_sz,
618 HB_MEMORY_MODE_READONLY,
619 /* userdata */ nullptr,
620 free);
621 }
622
Behdad Esfahbod977ddff2017-11-14 20:06:19 -0800623 struct accelerator_t
624 {
625 inline void init (hb_face_t *face)
626 {
Behdad Esfahbod470fe5b2018-01-09 15:48:51 +0100627 this->blob = OT::Sanitizer<OT::cmap>().sanitize (face->reference_table (HB_OT_TAG_cmap));
Behdad Esfahbod977ddff2017-11-14 20:06:19 -0800628 const OT::cmap *cmap = OT::Sanitizer<OT::cmap>::lock_instance (this->blob);
629 const OT::CmapSubtable *subtable = nullptr;
630 const OT::CmapSubtableFormat14 *subtable_uvs = nullptr;
631
632 bool symbol = false;
633 /* 32-bit subtables. */
634 if (!subtable) subtable = cmap->find_subtable (3, 10);
635 if (!subtable) subtable = cmap->find_subtable (0, 6);
636 if (!subtable) subtable = cmap->find_subtable (0, 4);
637 /* 16-bit subtables. */
638 if (!subtable) subtable = cmap->find_subtable (3, 1);
639 if (!subtable) subtable = cmap->find_subtable (0, 3);
640 if (!subtable) subtable = cmap->find_subtable (0, 2);
641 if (!subtable) subtable = cmap->find_subtable (0, 1);
642 if (!subtable) subtable = cmap->find_subtable (0, 0);
643 if (!subtable)
644 {
645 subtable = cmap->find_subtable (3, 0);
646 if (subtable) symbol = true;
647 }
648 /* Meh. */
649 if (!subtable) subtable = &OT::Null(OT::CmapSubtable);
650
651 /* UVS subtable. */
652 if (!subtable_uvs)
653 {
654 const OT::CmapSubtable *st = cmap->find_subtable (0, 5);
655 if (st && st->u.format == 14)
656 subtable_uvs = &st->u.format14;
657 }
658 /* Meh. */
659 if (!subtable_uvs) subtable_uvs = &OT::Null(OT::CmapSubtableFormat14);
660
661 this->uvs_table = subtable_uvs;
662
663 this->get_glyph_data = subtable;
664 if (unlikely (symbol))
665 this->get_glyph_func = get_glyph_from_symbol<OT::CmapSubtable>;
666 else
667 switch (subtable->u.format) {
668 /* Accelerate format 4 and format 12. */
669 default: this->get_glyph_func = get_glyph_from<OT::CmapSubtable>; break;
670 case 12: this->get_glyph_func = get_glyph_from<OT::CmapSubtableFormat12>; break;
671 case 4:
672 {
673 this->format4_accel.init (&subtable->u.format4);
674 this->get_glyph_data = &this->format4_accel;
675 this->get_glyph_func = this->format4_accel.get_glyph_func;
676 }
677 break;
678 }
679 }
680
681 inline void fini (void)
682 {
683 hb_blob_destroy (this->blob);
684 }
685
686 inline bool get_nominal_glyph (hb_codepoint_t unicode,
687 hb_codepoint_t *glyph) const
688 {
689 return this->get_glyph_func (this->get_glyph_data, unicode, glyph);
690 }
691
692 inline bool get_variation_glyph (hb_codepoint_t unicode,
693 hb_codepoint_t variation_selector,
694 hb_codepoint_t *glyph) const
695 {
696 switch (this->uvs_table->get_glyph_variant (unicode,
697 variation_selector,
698 glyph))
699 {
700 case OT::GLYPH_VARIANT_NOT_FOUND: return false;
701 case OT::GLYPH_VARIANT_FOUND: return true;
702 case OT::GLYPH_VARIANT_USE_DEFAULT: break;
703 }
704
705 return get_nominal_glyph (unicode, glyph);
706 }
707
708 protected:
709 typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj,
710 hb_codepoint_t codepoint,
711 hb_codepoint_t *glyph);
712
713 template <typename Type>
714 static inline bool get_glyph_from (const void *obj,
715 hb_codepoint_t codepoint,
716 hb_codepoint_t *glyph)
717 {
718 const Type *typed_obj = (const Type *) obj;
719 return typed_obj->get_glyph (codepoint, glyph);
720 }
721
722 template <typename Type>
723 static inline bool get_glyph_from_symbol (const void *obj,
724 hb_codepoint_t codepoint,
725 hb_codepoint_t *glyph)
726 {
727 const Type *typed_obj = (const Type *) obj;
728 if (likely (typed_obj->get_glyph (codepoint, glyph)))
729 return true;
730
731 if (codepoint <= 0x00FFu)
732 {
733 /* For symbol-encoded OpenType fonts, we duplicate the
734 * U+F000..F0FF range at U+0000..U+00FF. That's what
735 * Windows seems to do, and that's hinted about at:
736 * http://www.microsoft.com/typography/otspec/recom.htm
737 * under "Non-Standard (Symbol) Fonts". */
738 return typed_obj->get_glyph (0xF000u + codepoint, glyph);
739 }
740
741 return false;
742 }
743
744 private:
745 hb_cmap_get_glyph_func_t get_glyph_func;
746 const void *get_glyph_data;
747 OT::CmapSubtableFormat4::accelerator_t format4_accel;
748
749 const OT::CmapSubtableFormat14 *uvs_table;
750 hb_blob_t *blob;
751 };
752
753 protected:
754
Behdad Esfahbod3608a682014-05-12 13:46:29 -0400755 inline const CmapSubtable *find_subtable (unsigned int platform_id,
756 unsigned int encoding_id) const
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400757 {
758 EncodingRecord key;
759 key.platformID.set (platform_id);
760 key.encodingID.set (encoding_id);
761
Behdad Esfahboddf554af2014-06-19 15:39:18 -0400762 /* Note: We can use bsearch, but since it has no performance
763 * implications, we use lsearch and as such accept fonts with
764 * unsorted subtable list. */
765 int result = encodingRecord./*bsearch*/lsearch (key);
Behdad Esfahbod500737e2014-06-04 18:17:29 -0400766 if (result == -1 || !encodingRecord[result].subtable)
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200767 return nullptr;
Behdad Esfahbod3608a682014-05-12 13:46:29 -0400768
769 return &(this+encodingRecord[result].subtable);
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400770 }
771
Behdad Esfahbod977ddff2017-11-14 20:06:19 -0800772 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100773 HBUINT16 version; /* Table version number (0). */
Behdad Esfahboddf554af2014-06-19 15:39:18 -0400774 SortedArrayOf<EncodingRecord>
Behdad Esfahbodf1a72fe2014-06-04 19:00:29 -0400775 encodingRecord; /* Encoding tables. */
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400776 public:
777 DEFINE_SIZE_ARRAY (4, encodingRecord);
778};
779
780
781} /* namespace OT */
782
783
784#endif /* HB_OT_CMAP_TABLE_HH */