1 | /* |
2 | * Copyright © 2018 Ebrahim Byagowi |
3 | * Copyright © 2018 Google, Inc. |
4 | * |
5 | * This is part of HarfBuzz, a text shaping library. |
6 | * |
7 | * Permission is hereby granted, without written agreement and without |
8 | * license or royalty fees, to use, copy, modify, and distribute this |
9 | * software and its documentation for any purpose, provided that the |
10 | * above copyright notice and the following two paragraphs appear in |
11 | * all copies of this software. |
12 | * |
13 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR |
14 | * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES |
15 | * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN |
16 | * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |
17 | * DAMAGE. |
18 | * |
19 | * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, |
20 | * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
21 | * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS |
22 | * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO |
23 | * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
24 | * |
25 | * Google Author(s): Behdad Esfahbod |
26 | */ |
27 | |
28 | #ifndef HB_AAT_LAYOUT_KERX_TABLE_HH |
29 | #define HB_AAT_LAYOUT_KERX_TABLE_HH |
30 | |
31 | #include "hb-open-type.hh" |
32 | #include "hb-aat-layout-common.hh" |
33 | #include "hb-aat-layout-ankr-table.hh" |
34 | |
35 | /* |
36 | * kerx -- Extended Kerning |
37 | * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6kerx.html |
38 | */ |
39 | #define HB_AAT_TAG_kerx HB_TAG('k','e','r','x') |
40 | |
41 | |
42 | namespace AAT { |
43 | |
44 | using namespace OT; |
45 | |
46 | |
47 | struct KerxFormat0Records |
48 | { |
49 | inline bool sanitize (hb_sanitize_context_t *c) const |
50 | { |
51 | TRACE_SANITIZE (this); |
52 | return_trace (likely (c->check_struct (this))); |
53 | } |
54 | |
55 | protected: |
56 | GlyphID left; |
57 | GlyphID right; |
58 | FWORD value; |
59 | public: |
60 | DEFINE_SIZE_STATIC (6); |
61 | }; |
62 | |
63 | struct KerxSubTableFormat0 |
64 | { |
65 | // TODO(ebraminio) Enable when we got suitable BinSearchArrayOf |
66 | // inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const |
67 | // { |
68 | // hb_glyph_pair_t pair = {left, right}; |
69 | // int i = pairs.bsearch (pair); |
70 | // if (i == -1) |
71 | // return 0; |
72 | // return pairs[i].get_kerning (); |
73 | // } |
74 | |
75 | inline bool sanitize (hb_sanitize_context_t *c) const |
76 | { |
77 | TRACE_SANITIZE (this); |
78 | return_trace (likely (c->check_struct (this) && |
79 | recordsZ.sanitize (c, nPairs))); |
80 | } |
81 | |
82 | protected: |
83 | // TODO(ebraminio): A custom version of "BinSearchArrayOf<KerxPair> pairs;" is |
84 | // needed here to use HBUINT32 instead |
85 | HBUINT32 nPairs; /* The number of kerning pairs in this subtable */ |
86 | HBUINT32 searchRange; /* The largest power of two less than or equal to the value of nPairs, |
87 | * multiplied by the size in bytes of an entry in the subtable. */ |
88 | HBUINT32 entrySelector; /* This is calculated as log2 of the largest power of two less |
89 | * than or equal to the value of nPairs. */ |
90 | HBUINT32 rangeShift; /* The value of nPairs minus the largest power of two less than or equal to nPairs. */ |
91 | UnsizedArrayOf<KerxFormat0Records> |
92 | recordsZ; /* VAR=nPairs */ |
93 | public: |
94 | DEFINE_SIZE_ARRAY (16, recordsZ); |
95 | }; |
96 | |
97 | struct KerxSubTableFormat1 |
98 | { |
99 | inline bool sanitize (hb_sanitize_context_t *c) const |
100 | { |
101 | TRACE_SANITIZE (this); |
102 | return_trace (likely (c->check_struct (this) && |
103 | stateHeader.sanitize (c))); |
104 | } |
105 | |
106 | protected: |
107 | StateTable<HBUINT16> ; |
108 | LOffsetTo<ArrayOf<HBUINT16> > valueTable; |
109 | public: |
110 | DEFINE_SIZE_STATIC (20); |
111 | }; |
112 | |
113 | // TODO(ebraminio): Maybe this can be replaced with Lookup<HBUINT16>? |
114 | struct KerxClassTable |
115 | { |
116 | inline unsigned int get_class (hb_codepoint_t g) const { return classes[g - firstGlyph]; } |
117 | |
118 | inline bool sanitize (hb_sanitize_context_t *c) const |
119 | { |
120 | TRACE_SANITIZE (this); |
121 | return_trace (likely (firstGlyph.sanitize (c) && |
122 | classes.sanitize (c))); |
123 | } |
124 | |
125 | protected: |
126 | HBUINT16 firstGlyph; /* First glyph in class range. */ |
127 | ArrayOf<HBUINT16> classes; /* Glyph classes. */ |
128 | public: |
129 | DEFINE_SIZE_ARRAY (4, classes); |
130 | }; |
131 | |
132 | struct KerxSubTableFormat2 |
133 | { |
134 | inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right, const char *end) const |
135 | { |
136 | unsigned int l = (this+leftClassTable).get_class (left); |
137 | unsigned int r = (this+leftClassTable).get_class (left); |
138 | unsigned int offset = l * rowWidth + r * sizeof (FWORD); |
139 | const FWORD *arr = &(this+array); |
140 | if (unlikely ((const void *) arr < (const void *) this || (const void *) arr >= (const void *) end)) |
141 | return 0; |
142 | const FWORD *v = &StructAtOffset<FWORD> (arr, offset); |
143 | if (unlikely ((const void *) v < (const void *) arr || (const void *) (v + 1) > (const void *) end)) |
144 | return 0; |
145 | return *v; |
146 | } |
147 | |
148 | inline bool sanitize (hb_sanitize_context_t *c) const |
149 | { |
150 | TRACE_SANITIZE (this); |
151 | return_trace (likely (c->check_struct (this) && |
152 | rowWidth.sanitize (c) && |
153 | leftClassTable.sanitize (c, this) && |
154 | rightClassTable.sanitize (c, this) && |
155 | array.sanitize (c, this))); |
156 | } |
157 | |
158 | protected: |
159 | HBUINT32 rowWidth; /* The width, in bytes, of a row in the table. */ |
160 | LOffsetTo<KerxClassTable> |
161 | leftClassTable; /* Offset from beginning of this subtable to |
162 | * left-hand class table. */ |
163 | LOffsetTo<KerxClassTable> |
164 | rightClassTable;/* Offset from beginning of this subtable to |
165 | * right-hand class table. */ |
166 | LOffsetTo<FWORD> |
167 | array; /* Offset from beginning of this subtable to |
168 | * the start of the kerning array. */ |
169 | public: |
170 | DEFINE_SIZE_STATIC (16); |
171 | }; |
172 | |
173 | struct KerxSubTableFormat4 |
174 | { |
175 | inline bool sanitize (hb_sanitize_context_t *c) const |
176 | { |
177 | TRACE_SANITIZE (this); |
178 | return_trace (likely (c->check_struct (this) && |
179 | rowWidth.sanitize (c) && |
180 | leftClassTable.sanitize (c, this) && |
181 | rightClassTable.sanitize (c, this) && |
182 | array.sanitize (c, this))); |
183 | } |
184 | |
185 | protected: |
186 | HBUINT32 rowWidth; /* The width, in bytes, of a row in the table. */ |
187 | LOffsetTo<KerxClassTable> |
188 | leftClassTable; /* Offset from beginning of this subtable to |
189 | * left-hand class table. */ |
190 | LOffsetTo<KerxClassTable> |
191 | rightClassTable;/* Offset from beginning of this subtable to |
192 | * right-hand class table. */ |
193 | LOffsetTo<FWORD> |
194 | array; /* Offset from beginning of this subtable to |
195 | * the start of the kerning array. */ |
196 | public: |
197 | DEFINE_SIZE_STATIC (16); |
198 | }; |
199 | |
200 | struct KerxSubTableFormat6 |
201 | { |
202 | inline bool sanitize (hb_sanitize_context_t *c) const |
203 | { |
204 | TRACE_SANITIZE (this); |
205 | return_trace (likely (c->check_struct (this) && |
206 | rowIndexTable.sanitize (c, this) && |
207 | columnIndexTable.sanitize (c, this) && |
208 | kerningArray.sanitize (c, this) && |
209 | kerningVector.sanitize (c, this))); |
210 | } |
211 | |
212 | protected: |
213 | HBUINT32 flags; |
214 | HBUINT16 rowCount; |
215 | HBUINT16 columnCount; |
216 | LOffsetTo<Lookup<HBUINT16> > rowIndexTable; |
217 | LOffsetTo<Lookup<HBUINT16> > columnIndexTable; |
218 | LOffsetTo<Lookup<HBUINT16> > kerningArray; |
219 | LOffsetTo<Lookup<HBUINT16> > kerningVector; |
220 | public: |
221 | DEFINE_SIZE_STATIC (24); |
222 | }; |
223 | |
224 | enum coverage_flags_t |
225 | { |
226 | COVERAGE_VERTICAL_FLAG = 0x80u, |
227 | COVERAGE_CROSSSTREAM_FLAG = 0x40u, |
228 | COVERAGE_VARIATION_FLAG = 0x20u, |
229 | COVERAGE_PROCESS_DIRECTION = 0x10u, |
230 | }; |
231 | |
232 | struct KerxTable |
233 | { |
234 | inline bool apply (hb_aat_apply_context_t *c, const AAT::ankr *ankr) const |
235 | { |
236 | TRACE_APPLY (this); |
237 | /* TODO */ |
238 | return_trace (false); |
239 | } |
240 | |
241 | inline unsigned int get_size (void) const { return length; } |
242 | |
243 | inline bool sanitize (hb_sanitize_context_t *c) const |
244 | { |
245 | TRACE_SANITIZE (this); |
246 | if (unlikely (!c->check_struct (this))) |
247 | return_trace (false); |
248 | |
249 | switch (format) { |
250 | case 0: return u.format0.sanitize (c); |
251 | case 1: return u.format1.sanitize (c); |
252 | case 2: return u.format2.sanitize (c); |
253 | case 4: return u.format4.sanitize (c); |
254 | case 6: return u.format6.sanitize (c); |
255 | default:return_trace (false); |
256 | } |
257 | } |
258 | |
259 | protected: |
260 | HBUINT32 length; |
261 | HBUINT8 coverage; |
262 | HBUINT16 unused; |
263 | HBUINT8 format; |
264 | HBUINT32 tupleIndex; |
265 | union { |
266 | KerxSubTableFormat0 format0; |
267 | KerxSubTableFormat1 format1; |
268 | KerxSubTableFormat2 format2; |
269 | KerxSubTableFormat4 format4; |
270 | KerxSubTableFormat6 format6; |
271 | } u; |
272 | public: |
273 | DEFINE_SIZE_MIN (12); |
274 | }; |
275 | |
276 | struct SubtableGlyphCoverageArray |
277 | { |
278 | inline bool sanitize (hb_sanitize_context_t *c) const |
279 | { |
280 | TRACE_SANITIZE (this); |
281 | return_trace (likely (c->check_struct (this))); |
282 | } |
283 | |
284 | protected: |
285 | HBUINT32 length; |
286 | HBUINT32 coverage; |
287 | HBUINT32 tupleCount; |
288 | public: |
289 | DEFINE_SIZE_STATIC (12); |
290 | }; |
291 | |
292 | struct kerx |
293 | { |
294 | static const hb_tag_t tableTag = HB_AAT_TAG_kerx; |
295 | |
296 | inline bool apply (hb_aat_apply_context_t *c, const AAT::ankr *ankr) const |
297 | { |
298 | TRACE_APPLY (this); |
299 | const KerxTable &table = StructAfter<KerxTable> (*this); |
300 | return_trace (table.apply (c, ankr)); |
301 | } |
302 | |
303 | inline bool sanitize (hb_sanitize_context_t *c) const |
304 | { |
305 | TRACE_SANITIZE (this); |
306 | if (unlikely (!(c->check_struct (this)))) |
307 | return_trace (false); |
308 | |
309 | /* TODO: Something like `morx`s ChainSubtable should be done here instead */ |
310 | const KerxTable *table = &StructAfter<KerxTable> (*this); |
311 | if (unlikely (!(table->sanitize (c)))) |
312 | return_trace (false); |
313 | |
314 | for (unsigned int i = 0; i < nTables - 1; ++i) |
315 | { |
316 | table = &StructAfter<KerxTable> (*table); |
317 | if (unlikely (!(table->sanitize (c)))) |
318 | return_trace (false); |
319 | } |
320 | |
321 | // If version is less than 3, we are done here; otherwise better to check footer also |
322 | if (version < 3) |
323 | return_trace (true); |
324 | |
325 | // TODO: Investigate why this just work on some fonts no matter of version |
326 | // const SubtableGlyphCoverageArray &footer = |
327 | // StructAfter<SubtableGlyphCoverageArray> (*table); |
328 | // return_trace (footer.sanitize (c)); |
329 | |
330 | return_trace (true); |
331 | } |
332 | |
333 | protected: |
334 | HBUINT16 version; |
335 | HBUINT16 padding; |
336 | HBUINT32 nTables; |
337 | /*KerxTable tablesZ[VAR]; XXX ArrayOf??? */ |
338 | /*SubtableGlyphCoverageArray coverage_array;*/ |
339 | public: |
340 | DEFINE_SIZE_STATIC (8); |
341 | }; |
342 | |
343 | } /* namespace AAT */ |
344 | |
345 | |
346 | #endif /* HB_AAT_LAYOUT_KERX_TABLE_HH */ |
347 | |