blob: 2456de2c18949b9db569222b6e691cbeaa86e4a1 [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
30#include "hb-open-type-private.hh"
31
32
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
43struct CmapSubtableFormat4
44{
45 friend struct CmapSubtable;
46
47 private:
48 inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
49 {
Behdad Esfahbodc8a47452014-05-09 19:55:51 -040050 unsigned int segCount;
51 const USHORT *endCount;
52 const USHORT *startCount;
53 const USHORT *idDelta;
54 const USHORT *idRangeOffset;
55 const USHORT *glyphIdArray;
56 unsigned int glyphIdArrayLength;
57
58 segCount = this->segCountX2 / 2;
59 endCount = this->values;
60 startCount = endCount + segCount + 1;
61 idDelta = startCount + segCount;
62 idRangeOffset = idDelta + segCount;
63 glyphIdArray = idRangeOffset + segCount;
64 glyphIdArrayLength = (this->length - 16 - 8 * segCount) / 2;
65
66 /* Custom bsearch. */
67 int min = 0, max = (int) segCount - 1;
68 unsigned int i;
69 while (min <= max)
70 {
71 int mid = (min + max) / 2;
72 if (codepoint < startCount[mid])
73 max = mid - 1;
74 else if (codepoint > endCount[mid])
75 min = mid + 1;
76 else
77 {
78 i = mid;
79 goto found;
80 }
81 }
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -040082 return false;
Behdad Esfahbodc8a47452014-05-09 19:55:51 -040083
84 found:
85 hb_codepoint_t gid;
86 unsigned int rangeOffset = idRangeOffset[i];
87 if (rangeOffset == 0)
88 gid = codepoint + idDelta[i];
89 else
90 {
91 /* Somebody has been smoking... */
92 unsigned int index = rangeOffset / 2 + (codepoint - startCount[i]) + i - segCount;
93 if (unlikely (index >= glyphIdArrayLength))
94 return false;
95 gid = glyphIdArray[index];
96 if (unlikely (!gid))
97 return false;
98 gid += idDelta[i];
99 }
100
101 *glyph = gid & 0xFFFF;
102 return true;
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400103 }
104
105 inline bool sanitize (hb_sanitize_context_t *c) {
106 TRACE_SANITIZE (this);
107 return TRACE_RETURN (c->check_struct (this) &&
108 c->check_range (this, length) &&
109 16 + 4 * (unsigned int) segCountX2 < length);
110 }
111
112 protected:
113 USHORT format; /* Format number is set to 4. */
114 USHORT length; /* This is the length in bytes of the
115 * subtable. */
116 USHORT language; /* Ignore. */
117 USHORT segCountX2; /* 2 x segCount. */
118 USHORT searchRange; /* 2 * (2**floor(log2(segCount))) */
119 USHORT entrySelector; /* log2(searchRange/2) */
120 USHORT rangeShift; /* 2 x segCount - searchRange */
121
122 USHORT values[VAR];
123#if 0
124 USHORT endCount[segCount]; /* End characterCode for each segment,
125 * last=0xFFFF. */
126 USHORT reservedPad; /* Set to 0. */
127 USHORT startCount[segCount]; /* Start character code for each segment. */
128 SHORT idDelta[segCount]; /* Delta for all character codes in segment. */
129 USHORT idRangeOffset[segCount];/* Offsets into glyphIdArray or 0 */
130 USHORT glyphIdArray[VAR]; /* Glyph index array (arbitrary length) */
131#endif
132
133 public:
134 DEFINE_SIZE_ARRAY (14, values);
135};
136
Behdad Esfahbodd294a2c2014-05-12 17:58:31 -0400137struct CmapSubtableLongGroup
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400138{
139 friend struct CmapSubtableFormat12;
Behdad Esfahbodd294a2c2014-05-12 17:58:31 -0400140 friend struct CmapSubtableFormat13;
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400141
142 int cmp (hb_codepoint_t codepoint) const
143 {
144 if (codepoint < startCharCode) return -1;
145 if (codepoint > endCharCode) return +1;
146 return 0;
147 }
148
149 inline bool sanitize (hb_sanitize_context_t *c) {
150 TRACE_SANITIZE (this);
151 return TRACE_RETURN (c->check_struct (this));
152 }
153
154 private:
155 ULONG startCharCode; /* First character code in this group. */
156 ULONG endCharCode; /* Last character code in this group. */
Behdad Esfahbodd294a2c2014-05-12 17:58:31 -0400157 ULONG glyphID; /* Glyph index; interpretation depends on
158 * subtable format. */
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400159 public:
160 DEFINE_SIZE_STATIC (12);
161};
162
163struct CmapSubtableFormat12
164{
165 friend struct CmapSubtable;
166
167 private:
168 inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
169 {
170 int i = groups.search (codepoint);
171 if (i == -1)
172 return false;
Behdad Esfahbodd294a2c2014-05-12 17:58:31 -0400173 const CmapSubtableLongGroup &group = groups[i];
174 *glyph = group.glyphID + (codepoint - group.startCharCode);
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400175 return true;
176 }
177
178 inline bool sanitize (hb_sanitize_context_t *c) {
179 TRACE_SANITIZE (this);
180 return TRACE_RETURN (c->check_struct (this) && groups.sanitize (c));
181 }
182
183 protected:
184 USHORT format; /* Subtable format; set to 12. */
185 USHORT reserved; /* Reserved; set to 0. */
186 ULONG length; /* Byte length of this subtable (including the header). */
187 ULONG language; /* Ignore. */
Behdad Esfahbodd294a2c2014-05-12 17:58:31 -0400188 LongArrayOf<CmapSubtableLongGroup>
189 groups; /* Groupings. */
190 public:
191 DEFINE_SIZE_ARRAY (16, groups);
192};
193
194struct CmapSubtableFormat13
195{
196 friend struct CmapSubtable;
197
198 private:
199 inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
200 {
201 int i = groups.search (codepoint);
202 if (i == -1)
203 return false;
204 const CmapSubtableLongGroup &group = groups[i];
205 *glyph = group.glyphID;
206 return true;
207 }
208
209 inline bool sanitize (hb_sanitize_context_t *c) {
210 TRACE_SANITIZE (this);
211 return TRACE_RETURN (c->check_struct (this) && groups.sanitize (c));
212 }
213
214 protected:
215 USHORT format; /* Subtable format; set to 12. */
216 USHORT reserved; /* Reserved; set to 0. */
217 ULONG length; /* Byte length of this subtable (including the header). */
218 ULONG language; /* Ignore. */
219 LongArrayOf<CmapSubtableLongGroup>
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400220 groups; /* Groupings. */
221 public:
222 DEFINE_SIZE_ARRAY (16, groups);
223};
224
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400225struct CmapSubtable
226{
227 inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
228 {
229 switch (u.format) {
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400230 case 4: return u.format4 .get_glyph(codepoint, glyph);
231 case 12: return u.format12.get_glyph(codepoint, glyph);
Behdad Esfahbodd294a2c2014-05-12 17:58:31 -0400232 case 13: return u.format13.get_glyph(codepoint, glyph);
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400233 default:return false;
234 }
235 }
236
237 inline bool sanitize (hb_sanitize_context_t *c) {
238 TRACE_SANITIZE (this);
239 if (!u.format.sanitize (c)) return TRACE_RETURN (false);
240 switch (u.format) {
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400241 case 4: return TRACE_RETURN (u.format4 .sanitize (c));
242 case 12: return TRACE_RETURN (u.format12.sanitize (c));
Behdad Esfahbodd294a2c2014-05-12 17:58:31 -0400243 case 13: return TRACE_RETURN (u.format13.sanitize (c));
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400244 default:return TRACE_RETURN (true);
245 }
246 }
247
248 protected:
249 union {
250 USHORT format; /* Format identifier */
251 CmapSubtableFormat4 format4;
Behdad Esfahbod0d757932014-05-12 17:51:15 -0400252 CmapSubtableFormat12 format12;
Behdad Esfahbodd294a2c2014-05-12 17:58:31 -0400253 CmapSubtableFormat13 format13;
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400254 } u;
255 public:
256 DEFINE_SIZE_UNION (2, format);
257};
258
259
260struct EncodingRecord
261{
262 int cmp (const EncodingRecord &other) const
263 {
264 int ret;
265 ret = other.platformID.cmp (platformID);
266 if (ret) return ret;
267 ret = other.encodingID.cmp (encodingID);
268 if (ret) return ret;
269 return 0;
270 }
271
272 inline bool sanitize (hb_sanitize_context_t *c, void *base) {
273 TRACE_SANITIZE (this);
274 return TRACE_RETURN (c->check_struct (this) &&
275 subtable.sanitize (c, base));
276 }
277
278 USHORT platformID; /* Platform ID. */
279 USHORT encodingID; /* Platform-specific encoding ID. */
280 LongOffsetTo<CmapSubtable>
281 subtable; /* Byte offset from beginning of table to the subtable for this encoding. */
282 public:
283 DEFINE_SIZE_STATIC (8);
284};
285
286struct cmap
287{
288 static const hb_tag_t tableTag = HB_OT_TAG_cmap;
289
Behdad Esfahbod3608a682014-05-12 13:46:29 -0400290 inline const CmapSubtable *find_subtable (unsigned int platform_id,
291 unsigned int encoding_id) const
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400292 {
293 EncodingRecord key;
294 key.platformID.set (platform_id);
295 key.encodingID.set (encoding_id);
296
Behdad Esfahbod3608a682014-05-12 13:46:29 -0400297 int result = encodingRecord.search (key);
298 if (result == -1)
299 return NULL;
300
301 return &(this+encodingRecord[result].subtable);
Behdad Esfahbod41ca1fb2014-05-09 15:35:56 -0400302 }
303
304 inline bool sanitize (hb_sanitize_context_t *c) {
305 TRACE_SANITIZE (this);
306 return TRACE_RETURN (c->check_struct (this) &&
307 likely (version == 0) &&
308 encodingRecord.sanitize (c, this));
309 }
310
311 USHORT version; /* Table version number (0). */
312 ArrayOf<EncodingRecord> encodingRecord; /* Encoding tables. */
313 public:
314 DEFINE_SIZE_ARRAY (4, encodingRecord);
315};
316
317
318} /* namespace OT */
319
320
321#endif /* HB_OT_CMAP_TABLE_HH */