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 
41 namespace OT {
42 
43 
44 template <typename KernSubTableHeader>
45 struct KernSubTableFormat3
46 {
get_kerningOT::KernSubTableFormat347   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 
applyOT::KernSubTableFormat362   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 
sanitizeOT::KernSubTableFormat378   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 
114 template <typename KernSubTableHeader>
115 struct KernSubTable
116 {
get_sizeOT::KernSubTable117   unsigned int get_size () const { return u.header.length; }
get_typeOT::KernSubTable118   unsigned int get_type () const { return u.header.format; }
119 
get_kerningOT::KernSubTable120   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>
dispatchOT::KernSubTable130   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, hb_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, hb_forward<Ts> (ds)...) : c->default_return_value ());
142 #endif
143     default:	return_trace (c->default_return_value ());
144     }
145   }
146 
sanitizeOT::KernSubTable147   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 
170 struct KernOTSubTableHeader
171 {
172   static constexpr bool apple = false;
173   typedef AAT::ObsoleteTypes Types;
174 
tuple_countOT::KernOTSubTableHeader175   unsigned   tuple_count () const { return 0; }
is_horizontalOT::KernOTSubTableHeader176   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 
sanitizeOT::KernOTSubTableHeader190   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 
205 struct 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 
225 struct KernAATSubTableHeader
226 {
227   static constexpr bool apple = true;
228   typedef AAT::ObsoleteTypes Types;
229 
tuple_countOT::KernAATSubTableHeader230   unsigned   tuple_count () const { return 0; }
is_horizontalOT::KernAATSubTableHeader231   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 
sanitizeOT::KernAATSubTableHeader243   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 
260 struct 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 
279 struct kern
280 {
281   static constexpr hb_tag_t tableTag = HB_OT_TAG_kern;
282 
has_dataOT::kern283   bool     has_data () const { return u.version32; }
get_typeOT::kern284   unsigned get_type () const { return u.major; }
285 
has_state_machineOT::kern286   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 
has_cross_streamOT::kern297   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 
get_h_kerningOT::kern308   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 
applyOT::kern319   bool apply (AAT::hb_aat_apply_context_t *c) const
320   { return dispatch (c); }
321 
322   template <typename context_t, typename ...Ts>
dispatchOT::kern323   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, hb_forward<Ts> (ds)...));
329 #ifndef HB_NO_AAT_SHAPE
330     case 1:	return_trace (c->dispatch (u.aat, hb_forward<Ts> (ds)...));
331 #endif
332     default:	return_trace (c->default_return_value ());
333     }
334   }
335 
sanitizeOT::kern336   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