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	header;
90   HBUINT16		glyphCount;	/* The number of glyphs in this font. */
91   HBUINT8		kernValueCount;	/* The number of kerning values. */
92   HBUINT8		leftClassCount;	/* The number of left-hand classes. */
93   HBUINT8		rightClassCount;/* The number of right-hand classes. */
94   HBUINT8		flags;		/* Set to zero (reserved for future use). */
95   UnsizedArrayOf<FWORD>	kernValueZ;	/* The kerning values.
96 					 * Length kernValueCount. */
97 #if 0
98   UnsizedArrayOf<HBUINT8>leftClass;	/* The left-hand classes.
99 					 * Length glyphCount. */
100   UnsizedArrayOf<HBUINT8>rightClass;	/* The right-hand classes.
101 					 * Length glyphCount. */
102   UnsizedArrayOf<HBUINT8>kernIndex;	/* The indices into the kernValue array.
103 					 * Length leftClassCount * rightClassCount */
104 #endif
105   public:
106   DEFINE_SIZE_ARRAY (KernSubTableHeader::static_size + 6, kernValueZ);
107 };
108 
109 template <typename KernSubTableHeader>
110 struct KernSubTable
111 {
get_sizeOT::KernSubTable112   unsigned int get_size () const { return u.header.length; }
get_typeOT::KernSubTable113   unsigned int get_type () const { return u.header.format; }
114 
get_kerningOT::KernSubTable115   int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
116   {
117     switch (get_type ()) {
118     /* This method hooks up to hb_font_t's get_h_kerning.  Only support Format0. */
119     case 0: return u.format0.get_kerning (left, right);
120     default:return 0;
121     }
122   }
123 
124   template <typename context_t, typename ...Ts>
dispatchOT::KernSubTable125   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
126   {
127     unsigned int subtable_type = get_type ();
128     TRACE_DISPATCH (this, subtable_type);
129     switch (subtable_type) {
130     case 0:	return_trace (c->dispatch (u.format0));
131 #ifndef HB_NO_AAT_SHAPE
132     case 1:	return_trace (u.header.apple ? c->dispatch (u.format1, hb_forward<Ts> (ds)...) : c->default_return_value ());
133 #endif
134     case 2:	return_trace (c->dispatch (u.format2));
135 #ifndef HB_NO_AAT_SHAPE
136     case 3:	return_trace (u.header.apple ? c->dispatch (u.format3, hb_forward<Ts> (ds)...) : c->default_return_value ());
137 #endif
138     default:	return_trace (c->default_return_value ());
139     }
140   }
141 
sanitizeOT::KernSubTable142   bool sanitize (hb_sanitize_context_t *c) const
143   {
144     TRACE_SANITIZE (this);
145     if (unlikely (!u.header.sanitize (c) ||
146 		  u.header.length < u.header.min_size ||
147 		  !c->check_range (this, u.header.length))) return_trace (false);
148 
149     return_trace (dispatch (c));
150   }
151 
152   public:
153   union {
154   KernSubTableHeader				header;
155   AAT::KerxSubTableFormat0<KernSubTableHeader>	format0;
156   AAT::KerxSubTableFormat1<KernSubTableHeader>	format1;
157   AAT::KerxSubTableFormat2<KernSubTableHeader>	format2;
158   KernSubTableFormat3<KernSubTableHeader>	format3;
159   } u;
160   public:
161   DEFINE_SIZE_MIN (KernSubTableHeader::static_size);
162 };
163 
164 
165 struct KernOTSubTableHeader
166 {
167   static constexpr bool apple = false;
168   typedef AAT::ObsoleteTypes Types;
169 
tuple_countOT::KernOTSubTableHeader170   unsigned   tuple_count () const { return 0; }
is_horizontalOT::KernOTSubTableHeader171   bool     is_horizontal () const { return (coverage & Horizontal); }
172 
173   enum Coverage
174   {
175     Horizontal	= 0x01u,
176     Minimum	= 0x02u,
177     CrossStream	= 0x04u,
178     Override	= 0x08u,
179 
180     /* Not supported: */
181     Backwards	= 0x00u,
182     Variation	= 0x00u,
183   };
184 
sanitizeOT::KernOTSubTableHeader185   bool sanitize (hb_sanitize_context_t *c) const
186   {
187     TRACE_SANITIZE (this);
188     return_trace (c->check_struct (this));
189   }
190 
191   public:
192   HBUINT16	versionZ;	/* Unused. */
193   HBUINT16	length;		/* Length of the subtable (including this header). */
194   HBUINT8	format;		/* Subtable format. */
195   HBUINT8	coverage;	/* Coverage bits. */
196   public:
197   DEFINE_SIZE_STATIC (6);
198 };
199 
200 struct KernOT : AAT::KerxTable<KernOT>
201 {
202   friend struct AAT::KerxTable<KernOT>;
203 
204   static constexpr hb_tag_t tableTag = HB_OT_TAG_kern;
205   static constexpr unsigned minVersion = 0u;
206 
207   typedef KernOTSubTableHeader SubTableHeader;
208   typedef SubTableHeader::Types Types;
209   typedef KernSubTable<SubTableHeader> SubTable;
210 
211   protected:
212   HBUINT16	version;	/* Version--0x0000u */
213   HBUINT16	tableCount;	/* Number of subtables in the kerning table. */
214   SubTable	firstSubTable;	/* Subtables. */
215   public:
216   DEFINE_SIZE_MIN (4);
217 };
218 
219 
220 struct KernAATSubTableHeader
221 {
222   static constexpr bool apple = true;
223   typedef AAT::ObsoleteTypes Types;
224 
tuple_countOT::KernAATSubTableHeader225   unsigned   tuple_count () const { return 0; }
is_horizontalOT::KernAATSubTableHeader226   bool     is_horizontal () const { return !(coverage & Vertical); }
227 
228   enum Coverage
229   {
230     Vertical	= 0x80u,
231     CrossStream	= 0x40u,
232     Variation	= 0x20u,
233 
234     /* Not supported: */
235     Backwards	= 0x00u,
236   };
237 
sanitizeOT::KernAATSubTableHeader238   bool sanitize (hb_sanitize_context_t *c) const
239   {
240     TRACE_SANITIZE (this);
241     return_trace (c->check_struct (this));
242   }
243 
244   public:
245   HBUINT32	length;		/* Length of the subtable (including this header). */
246   HBUINT8	coverage;	/* Coverage bits. */
247   HBUINT8	format;		/* Subtable format. */
248   HBUINT16	tupleIndex;	/* The tuple index (used for variations fonts).
249 			       * This value specifies which tuple this subtable covers.
250 			       * Note: We don't implement. */
251   public:
252   DEFINE_SIZE_STATIC (8);
253 };
254 
255 struct KernAAT : AAT::KerxTable<KernAAT>
256 {
257   friend struct AAT::KerxTable<KernAAT>;
258 
259   static constexpr hb_tag_t tableTag = HB_OT_TAG_kern;
260   static constexpr unsigned minVersion = 0x00010000u;
261 
262   typedef KernAATSubTableHeader SubTableHeader;
263   typedef SubTableHeader::Types Types;
264   typedef KernSubTable<SubTableHeader> SubTable;
265 
266   protected:
267   HBUINT32	version;	/* Version--0x00010000u */
268   HBUINT32	tableCount;	/* Number of subtables in the kerning table. */
269   SubTable	firstSubTable;	/* Subtables. */
270   public:
271   DEFINE_SIZE_MIN (8);
272 };
273 
274 struct kern
275 {
276   static constexpr hb_tag_t tableTag = HB_OT_TAG_kern;
277 
has_dataOT::kern278   bool     has_data () const { return u.version32; }
get_typeOT::kern279   unsigned get_type () const { return u.major; }
280 
has_state_machineOT::kern281   bool has_state_machine () const
282   {
283     switch (get_type ()) {
284     case 0: return u.ot.has_state_machine ();
285 #ifndef HB_NO_AAT_SHAPE
286     case 1: return u.aat.has_state_machine ();
287 #endif
288     default:return false;
289     }
290   }
291 
has_cross_streamOT::kern292   bool has_cross_stream () const
293   {
294     switch (get_type ()) {
295     case 0: return u.ot.has_cross_stream ();
296 #ifndef HB_NO_AAT_SHAPE
297     case 1: return u.aat.has_cross_stream ();
298 #endif
299     default:return false;
300     }
301   }
302 
get_h_kerningOT::kern303   int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right) const
304   {
305     switch (get_type ()) {
306     case 0: return u.ot.get_h_kerning (left, right);
307 #ifndef HB_NO_AAT_SHAPE
308     case 1: return u.aat.get_h_kerning (left, right);
309 #endif
310     default:return 0;
311     }
312   }
313 
applyOT::kern314   bool apply (AAT::hb_aat_apply_context_t *c) const
315   { return dispatch (c); }
316 
317   template <typename context_t, typename ...Ts>
dispatchOT::kern318   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
319   {
320     unsigned int subtable_type = get_type ();
321     TRACE_DISPATCH (this, subtable_type);
322     switch (subtable_type) {
323     case 0:	return_trace (c->dispatch (u.ot, hb_forward<Ts> (ds)...));
324 #ifndef HB_NO_AAT_SHAPE
325     case 1:	return_trace (c->dispatch (u.aat, hb_forward<Ts> (ds)...));
326 #endif
327     default:	return_trace (c->default_return_value ());
328     }
329   }
330 
sanitizeOT::kern331   bool sanitize (hb_sanitize_context_t *c) const
332   {
333     TRACE_SANITIZE (this);
334     if (!u.version32.sanitize (c)) return_trace (false);
335     return_trace (dispatch (c));
336   }
337 
338   protected:
339   union {
340   HBUINT32		version32;
341   HBUINT16		major;
342   KernOT		ot;
343 #ifndef HB_NO_AAT_SHAPE
344   KernAAT		aat;
345 #endif
346   } u;
347   public:
348   DEFINE_SIZE_UNION (4, version32);
349 };
350 
351 } /* namespace OT */
352 
353 
354 #endif /* HB_OT_KERN_TABLE_HH */
355