1/*
2 * Copyright © 2017 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_KERN_TABLE_HH
28#define HB_OT_KERN_TABLE_HH
29
30#include "hb-aat-layout-kerx-table.hh"
31
32
33/*
34 * kern -- Kerning
35 * https://docs.microsoft.com/en-us/typography/opentype/spec/kern
36 * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6kern.html
37 */
38#define HB_OT_TAG_kern HB_TAG('k','e','r','n')
39
40
41namespace OT {
42
43
44template <typename KernSubTableHeader>
45struct KernSubTableFormat3
46{
47 int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
48 {
49 hb_array_t<const FWORD> kernValue = kernValueZ.as_array (kernValueCount);
50 hb_array_t<const HBUINT8> leftClass = StructAfter<const UnsizedArrayOf<HBUINT8>> (kernValue).as_array (glyphCount);
51 hb_array_t<const HBUINT8> rightClass = StructAfter<const UnsizedArrayOf<HBUINT8>> (leftClass).as_array (glyphCount);
52 hb_array_t<const HBUINT8> kernIndex = StructAfter<const UnsizedArrayOf<HBUINT8>> (rightClass).as_array (leftClassCount * rightClassCount);
53
54 unsigned int leftC = leftClass[left];
55 unsigned int rightC = rightClass[right];
56 if (unlikely (leftC >= leftClassCount || rightC >= rightClassCount))
57 return 0;
58 unsigned int i = leftC * rightClassCount + rightC;
59 return kernValue[kernIndex[i]];
60 }
61
62 bool apply (AAT::hb_aat_apply_context_t *c) const
63 {
64 TRACE_APPLY (this);
65
66 if (!c->plan->requested_kerning)
67 return false;
68
69 if (header.coverage & header.Backwards)
70 return false;
71
72 hb_kern_machine_t<KernSubTableFormat3> machine (*this, header.coverage & header.CrossStream);
73 machine.kern (c->font, c->buffer, c->plan->kern_mask);
74
75 return_trace (true);
76 }
77
78 bool sanitize (hb_sanitize_context_t *c) const
79 {
80 TRACE_SANITIZE (this);
81 return_trace (c->check_struct (this) &&
82 c->check_range (kernValueZ,
83 kernValueCount * sizeof (FWORD) +
84 glyphCount * 2 +
85 leftClassCount * rightClassCount));
86 }
87
88 protected:
89 KernSubTableHeader
90 header;
91 HBUINT16 glyphCount; /* The number of glyphs in this font. */
92 HBUINT8 kernValueCount; /* The number of kerning values. */
93 HBUINT8 leftClassCount; /* The number of left-hand classes. */
94 HBUINT8 rightClassCount;/* The number of right-hand classes. */
95 HBUINT8 flags; /* Set to zero (reserved for future use). */
96 UnsizedArrayOf<FWORD>
97 kernValueZ; /* The kerning values.
98 * Length kernValueCount. */
99#if 0
100 UnsizedArrayOf<HBUINT8>
101 leftClass; /* The left-hand classes.
102 * Length glyphCount. */
103 UnsizedArrayOf<HBUINT8>
104 rightClass; /* The right-hand classes.
105 * Length glyphCount. */
106 UnsizedArrayOf<HBUINT8>kernIndex;
107 /* The indices into the kernValue array.
108 * Length leftClassCount * rightClassCount */
109#endif
110 public:
111 DEFINE_SIZE_ARRAY (KernSubTableHeader::static_size + 6, kernValueZ);
112};
113
114template <typename KernSubTableHeader>
115struct KernSubTable
116{
117 unsigned int get_size () const { return u.header.length; }
118 unsigned int get_type () const { return u.header.format; }
119
120 int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
121 {
122 switch (get_type ()) {
123 /* This method hooks up to hb_font_t's get_h_kerning. Only support Format0. */
124 case 0: return u.format0.get_kerning (left, right);
125 default:return 0;
126 }
127 }
128
129 template <typename context_t, typename ...Ts>
130 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
131 {
132 unsigned int subtable_type = get_type ();
133 TRACE_DISPATCH (this, subtable_type);
134 switch (subtable_type) {
135 case 0: return_trace (c->dispatch (u.format0));
136#ifndef HB_NO_AAT_SHAPE
137 case 1: return_trace (u.header.apple ? c->dispatch (u.format1, std::forward<Ts> (ds)...) : c->default_return_value ());
138#endif
139 case 2: return_trace (c->dispatch (u.format2));
140#ifndef HB_NO_AAT_SHAPE
141 case 3: return_trace (u.header.apple ? c->dispatch (u.format3, std::forward<Ts> (ds)...) : c->default_return_value ());
142#endif
143 default: return_trace (c->default_return_value ());
144 }
145 }
146
147 bool sanitize (hb_sanitize_context_t *c) const
148 {
149 TRACE_SANITIZE (this);
150 if (unlikely (!u.header.sanitize (c) ||
151 u.header.length < u.header.min_size ||
152 !c->check_range (this, u.header.length))) return_trace (false);
153
154 return_trace (dispatch (c));
155 }
156
157 public:
158 union {
159 KernSubTableHeader header;
160 AAT::KerxSubTableFormat0<KernSubTableHeader> format0;
161 AAT::KerxSubTableFormat1<KernSubTableHeader> format1;
162 AAT::KerxSubTableFormat2<KernSubTableHeader> format2;
163 KernSubTableFormat3<KernSubTableHeader> format3;
164 } u;
165 public:
166 DEFINE_SIZE_MIN (KernSubTableHeader::static_size);
167};
168
169
170struct KernOTSubTableHeader
171{
172 static constexpr bool apple = false;
173 typedef AAT::ObsoleteTypes Types;
174
175 unsigned tuple_count () const { return 0; }
176 bool is_horizontal () const { return (coverage & Horizontal); }
177
178 enum Coverage
179 {
180 Horizontal = 0x01u,
181 Minimum = 0x02u,
182 CrossStream = 0x04u,
183 Override = 0x08u,
184
185 /* Not supported: */
186 Backwards = 0x00u,
187 Variation = 0x00u,
188 };
189
190 bool sanitize (hb_sanitize_context_t *c) const
191 {
192 TRACE_SANITIZE (this);
193 return_trace (c->check_struct (this));
194 }
195
196 public:
197 HBUINT16 versionZ; /* Unused. */
198 HBUINT16 length; /* Length of the subtable (including this header). */
199 HBUINT8 format; /* Subtable format. */
200 HBUINT8 coverage; /* Coverage bits. */
201 public:
202 DEFINE_SIZE_STATIC (6);
203};
204
205struct KernOT : AAT::KerxTable<KernOT>
206{
207 friend struct AAT::KerxTable<KernOT>;
208
209 static constexpr hb_tag_t tableTag = HB_OT_TAG_kern;
210 static constexpr unsigned minVersion = 0u;
211
212 typedef KernOTSubTableHeader SubTableHeader;
213 typedef SubTableHeader::Types Types;
214 typedef KernSubTable<SubTableHeader> SubTable;
215
216 protected:
217 HBUINT16 version; /* Version--0x0000u */
218 HBUINT16 tableCount; /* Number of subtables in the kerning table. */
219 SubTable firstSubTable; /* Subtables. */
220 public:
221 DEFINE_SIZE_MIN (4);
222};
223
224
225struct KernAATSubTableHeader
226{
227 static constexpr bool apple = true;
228 typedef AAT::ObsoleteTypes Types;
229
230 unsigned tuple_count () const { return 0; }
231 bool is_horizontal () const { return !(coverage & Vertical); }
232
233 enum Coverage
234 {
235 Vertical = 0x80u,
236 CrossStream = 0x40u,
237 Variation = 0x20u,
238
239 /* Not supported: */
240 Backwards = 0x00u,
241 };
242
243 bool sanitize (hb_sanitize_context_t *c) const
244 {
245 TRACE_SANITIZE (this);
246 return_trace (c->check_struct (this));
247 }
248
249 public:
250 HBUINT32 length; /* Length of the subtable (including this header). */
251 HBUINT8 coverage; /* Coverage bits. */
252 HBUINT8 format; /* Subtable format. */
253 HBUINT16 tupleIndex; /* The tuple index (used for variations fonts).
254 * This value specifies which tuple this subtable covers.
255 * Note: We don't implement. */
256 public:
257 DEFINE_SIZE_STATIC (8);
258};
259
260struct KernAAT : AAT::KerxTable<KernAAT>
261{
262 friend struct AAT::KerxTable<KernAAT>;
263
264 static constexpr hb_tag_t tableTag = HB_OT_TAG_kern;
265 static constexpr unsigned minVersion = 0x00010000u;
266
267 typedef KernAATSubTableHeader SubTableHeader;
268 typedef SubTableHeader::Types Types;
269 typedef KernSubTable<SubTableHeader> SubTable;
270
271 protected:
272 HBUINT32 version; /* Version--0x00010000u */
273 HBUINT32 tableCount; /* Number of subtables in the kerning table. */
274 SubTable firstSubTable; /* Subtables. */
275 public:
276 DEFINE_SIZE_MIN (8);
277};
278
279struct kern
280{
281 static constexpr hb_tag_t tableTag = HB_OT_TAG_kern;
282
283 bool has_data () const { return u.version32; }
284 unsigned get_type () const { return u.major; }
285
286 bool has_state_machine () const
287 {
288 switch (get_type ()) {
289 case 0: return u.ot.has_state_machine ();
290#ifndef HB_NO_AAT_SHAPE
291 case 1: return u.aat.has_state_machine ();
292#endif
293 default:return false;
294 }
295 }
296
297 bool has_cross_stream () const
298 {
299 switch (get_type ()) {
300 case 0: return u.ot.has_cross_stream ();
301#ifndef HB_NO_AAT_SHAPE
302 case 1: return u.aat.has_cross_stream ();
303#endif
304 default:return false;
305 }
306 }
307
308 int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right) const
309 {
310 switch (get_type ()) {
311 case 0: return u.ot.get_h_kerning (left, right);
312#ifndef HB_NO_AAT_SHAPE
313 case 1: return u.aat.get_h_kerning (left, right);
314#endif
315 default:return 0;
316 }
317 }
318
319 bool apply (AAT::hb_aat_apply_context_t *c) const
320 { return dispatch (c); }
321
322 template <typename context_t, typename ...Ts>
323 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
324 {
325 unsigned int subtable_type = get_type ();
326 TRACE_DISPATCH (this, subtable_type);
327 switch (subtable_type) {
328 case 0: return_trace (c->dispatch (u.ot, std::forward<Ts> (ds)...));
329#ifndef HB_NO_AAT_SHAPE
330 case 1: return_trace (c->dispatch (u.aat, std::forward<Ts> (ds)...));
331#endif
332 default: return_trace (c->default_return_value ());
333 }
334 }
335
336 bool sanitize (hb_sanitize_context_t *c) const
337 {
338 TRACE_SANITIZE (this);
339 if (!u.version32.sanitize (c)) return_trace (false);
340 return_trace (dispatch (c));
341 }
342
343 protected:
344 union {
345 HBUINT32 version32;
346 HBUINT16 major;
347 KernOT ot;
348#ifndef HB_NO_AAT_SHAPE
349 KernAAT aat;
350#endif
351 } u;
352 public:
353 DEFINE_SIZE_UNION (4, version32);
354};
355
356} /* namespace OT */
357
358
359#endif /* HB_OT_KERN_TABLE_HH */
360