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-open-type-private.hh"
31 
32 namespace OT {
33 
34 
35 /*
36  * kern -- Kerning
37  */
38 
39 #define HB_OT_TAG_kern HB_TAG('k','e','r','n')
40 
41 struct hb_glyph_pair_t
42 {
43   hb_codepoint_t left;
44   hb_codepoint_t right;
45 };
46 
47 struct KernPair
48 {
get_kerningOT::KernPair49   inline int get_kerning (void) const
50   { return value; }
51 
cmpOT::KernPair52   inline int cmp (const hb_glyph_pair_t &o) const
53   {
54     int ret = left.cmp (o.left);
55     if (ret) return ret;
56     return right.cmp (o.right);
57   }
58 
sanitizeOT::KernPair59   inline bool sanitize (hb_sanitize_context_t *c) const
60   {
61     TRACE_SANITIZE (this);
62     return_trace (c->check_struct (this));
63   }
64 
65   protected:
66   GlyphID	left;
67   GlyphID	right;
68   FWORD		value;
69   public:
70   DEFINE_SIZE_STATIC (6);
71 };
72 
73 struct KernSubTableFormat0
74 {
get_kerningOT::KernSubTableFormat075   inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
76   {
77     hb_glyph_pair_t pair = {left, right};
78     int i = pairs.bsearch (pair);
79     if (i == -1)
80       return 0;
81     return pairs[i].get_kerning ();
82   }
83 
sanitizeOT::KernSubTableFormat084   inline bool sanitize (hb_sanitize_context_t *c) const
85   {
86     TRACE_SANITIZE (this);
87     return_trace (pairs.sanitize (c));
88   }
89 
90   protected:
91   BinSearchArrayOf<KernPair> pairs;	/* Array of kerning pairs. */
92   public:
93   DEFINE_SIZE_ARRAY (8, pairs);
94 };
95 
96 struct KernClassTable
97 {
get_classOT::KernClassTable98   inline unsigned int get_class (hb_codepoint_t g) const { return classes[g - firstGlyph]; }
99 
sanitizeOT::KernClassTable100   inline bool sanitize (hb_sanitize_context_t *c) const
101   {
102     TRACE_SANITIZE (this);
103     return_trace (firstGlyph.sanitize (c) && classes.sanitize (c));
104   }
105 
106   protected:
107   UINT16		firstGlyph;	/* First glyph in class range. */
108   ArrayOf<UINT16>	classes;	/* Glyph classes. */
109   public:
110   DEFINE_SIZE_ARRAY (4, classes);
111 };
112 
113 struct KernSubTableFormat2
114 {
get_kerningOT::KernSubTableFormat2115   inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right, const char *end) const
116   {
117     unsigned int l = (this+leftClassTable).get_class (left);
118     unsigned int r = (this+leftClassTable).get_class (left);
119     unsigned int offset = l * rowWidth + r * sizeof (FWORD);
120     const FWORD *arr = &(this+array);
121     if (unlikely ((const void *) arr < (const void *) this || (const void *) arr >= (const void *) end))
122       return 0;
123     const FWORD *v = &StructAtOffset<FWORD> (arr, offset);
124     if (unlikely ((const void *) v < (const void *) arr || (const void *) (v + 1) > (const void *) end))
125       return 0;
126     return *v;
127   }
128 
sanitizeOT::KernSubTableFormat2129   inline bool sanitize (hb_sanitize_context_t *c) const
130   {
131     TRACE_SANITIZE (this);
132     return_trace (rowWidth.sanitize (c) &&
133 		  leftClassTable.sanitize (c, this) &&
134 		  rightClassTable.sanitize (c, this) &&
135 		  array.sanitize (c, this));
136   }
137 
138   protected:
139   UINT16	rowWidth;	/* The width, in bytes, of a row in the table. */
140   OffsetTo<KernClassTable>
141 		leftClassTable;	/* Offset from beginning of this subtable to
142 				 * left-hand class table. */
143   OffsetTo<KernClassTable>
144 		rightClassTable;/* Offset from beginning of this subtable to
145 				 * right-hand class table. */
146   OffsetTo<FWORD>
147 		array;		/* Offset from beginning of this subtable to
148 				 * the start of the kerning array. */
149   public:
150   DEFINE_SIZE_MIN (8);
151 };
152 
153 struct KernSubTable
154 {
get_kerningOT::KernSubTable155   inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right, const char *end, unsigned int format) const
156   {
157     switch (format) {
158     case 0: return u.format0.get_kerning (left, right);
159     case 2: return u.format2.get_kerning (left, right, end);
160     default:return 0;
161     }
162   }
163 
sanitizeOT::KernSubTable164   inline bool sanitize (hb_sanitize_context_t *c, unsigned int format) const
165   {
166     TRACE_SANITIZE (this);
167     switch (format) {
168     case 0: return_trace (u.format0.sanitize (c));
169     case 2: return_trace (u.format2.sanitize (c));
170     default:return_trace (true);
171     }
172   }
173 
174   protected:
175   union {
176   KernSubTableFormat0	format0;
177   KernSubTableFormat2	format2;
178   } u;
179   public:
180   DEFINE_SIZE_MIN (0);
181 };
182 
183 
184 template <typename T>
185 struct KernSubTableWrapper
186 {
187   /* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */
thizOT::KernSubTableWrapper188   inline const T* thiz (void) const { return static_cast<const T *> (this); }
189 
is_horizontalOT::KernSubTableWrapper190   inline bool is_horizontal (void) const
191   { return (thiz()->coverage & T::COVERAGE_CHECK_FLAGS) == T::COVERAGE_CHECK_HORIZONTAL; }
192 
is_overrideOT::KernSubTableWrapper193   inline bool is_override (void) const
194   { return bool (thiz()->coverage & T::COVERAGE_OVERRIDE_FLAG); }
195 
get_kerningOT::KernSubTableWrapper196   inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right, const char *end) const
197   { return thiz()->subtable.get_kerning (left, right, end, thiz()->format); }
198 
get_h_kerningOT::KernSubTableWrapper199   inline int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right, const char *end) const
200   { return is_horizontal () ? get_kerning (left, right, end) : 0; }
201 
get_sizeOT::KernSubTableWrapper202   inline unsigned int get_size (void) const { return thiz()->length; }
203 
sanitizeOT::KernSubTableWrapper204   inline bool sanitize (hb_sanitize_context_t *c) const
205   {
206     TRACE_SANITIZE (this);
207     return_trace (c->check_struct (thiz()) &&
208 		  thiz()->length >= thiz()->min_size &&
209 		  c->check_array (thiz(), 1, thiz()->length) &&
210 		  thiz()->subtable.sanitize (c, thiz()->format));
211   }
212 };
213 
214 template <typename T>
215 struct KernTable
216 {
217   /* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */
thizOT::KernTable218   inline const T* thiz (void) const { return static_cast<const T *> (this); }
219 
get_h_kerningOT::KernTable220   inline int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right, unsigned int table_length) const
221   {
222     int v = 0;
223     const typename T::SubTableWrapper *st = CastP<typename T::SubTableWrapper> (thiz()->data);
224     unsigned int count = thiz()->nTables;
225     for (unsigned int i = 0; i < count; i++)
226     {
227       if (st->is_override ())
228         v = 0;
229       v += st->get_h_kerning (left, right, table_length + (const char *) this);
230       st = &StructAfter<typename T::SubTableWrapper> (*st);
231     }
232     return v;
233   }
234 
sanitizeOT::KernTable235   inline bool sanitize (hb_sanitize_context_t *c) const
236   {
237     TRACE_SANITIZE (this);
238     if (unlikely (!c->check_struct (thiz()) ||
239 		  thiz()->version != T::VERSION))
240       return_trace (false);
241 
242     const typename T::SubTableWrapper *st = CastP<typename T::SubTableWrapper> (thiz()->data);
243     unsigned int count = thiz()->nTables;
244     for (unsigned int i = 0; i < count; i++)
245     {
246       if (unlikely (!st->sanitize (c)))
247 	return_trace (false);
248       st = &StructAfter<typename T::SubTableWrapper> (*st);
249     }
250 
251     return_trace (true);
252   }
253 };
254 
255 struct KernOT : KernTable<KernOT>
256 {
257   friend struct KernTable<KernOT>;
258 
259   static const uint16_t VERSION = 0x0000u;
260 
261   struct SubTableWrapper : KernSubTableWrapper<SubTableWrapper>
262   {
263     friend struct KernSubTableWrapper<SubTableWrapper>;
264 
265     enum coverage_flags_t {
266       COVERAGE_DIRECTION_FLAG	= 0x01u,
267       COVERAGE_MINIMUM_FLAG	= 0x02u,
268       COVERAGE_CROSSSTREAM_FLAG	= 0x04u,
269       COVERAGE_OVERRIDE_FLAG	= 0x08u,
270 
271       COVERAGE_VARIATION_FLAG	= 0x00u, /* Not supported. */
272 
273       COVERAGE_CHECK_FLAGS	= 0x07u,
274       COVERAGE_CHECK_HORIZONTAL	= 0x01u
275     };
276 
277     protected:
278     UINT16	versionZ;	/* Unused. */
279     UINT16	length;		/* Length of the subtable (including this header). */
280     UINT8	format;		/* Subtable format. */
281     UINT8	coverage;	/* Coverage bits. */
282     KernSubTable subtable;	/* Subtable data. */
283     public:
284     DEFINE_SIZE_MIN (6);
285   };
286 
287   protected:
288   UINT16	version;	/* Version--0x0000u */
289   UINT16	nTables;	/* Number of subtables in the kerning table. */
290   UINT8		data[VAR];
291   public:
292   DEFINE_SIZE_ARRAY (4, data);
293 };
294 
295 struct KernAAT : KernTable<KernAAT>
296 {
297   friend struct KernTable<KernAAT>;
298 
299   static const uint32_t VERSION = 0x00010000u;
300 
301   struct SubTableWrapper : KernSubTableWrapper<SubTableWrapper>
302   {
303     friend struct KernSubTableWrapper<SubTableWrapper>;
304 
305     enum coverage_flags_t {
306       COVERAGE_DIRECTION_FLAG	= 0x80u,
307       COVERAGE_CROSSSTREAM_FLAG	= 0x40u,
308       COVERAGE_VARIATION_FLAG	= 0x20u,
309 
310       COVERAGE_OVERRIDE_FLAG	= 0x00u, /* Not supported. */
311 
312       COVERAGE_CHECK_FLAGS	= 0xE0u,
313       COVERAGE_CHECK_HORIZONTAL	= 0x00u
314     };
315 
316     protected:
317     UINT32	length;		/* Length of the subtable (including this header). */
318     UINT8	coverage;	/* Coverage bits. */
319     UINT8	format;		/* Subtable format. */
320     UINT16	tupleIndex;	/* The tuple index (used for variations fonts).
321 				 * This value specifies which tuple this subtable covers. */
322     KernSubTable subtable;	/* Subtable data. */
323     public:
324     DEFINE_SIZE_MIN (8);
325   };
326 
327   protected:
328   UINT32		version;	/* Version--0x00010000u */
329   UINT32		nTables;	/* Number of subtables in the kerning table. */
330   UINT8		data[VAR];
331   public:
332   DEFINE_SIZE_ARRAY (8, data);
333 };
334 
335 struct kern
336 {
337   static const hb_tag_t tableTag = HB_OT_TAG_kern;
338 
get_h_kerningOT::kern339   inline int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right, unsigned int table_length) const
340   {
341     switch (u.major) {
342     case 0: return u.ot.get_h_kerning (left, right, table_length);
343     case 1: return u.aat.get_h_kerning (left, right, table_length);
344     default:return 0;
345     }
346   }
347 
sanitizeOT::kern348   inline bool sanitize (hb_sanitize_context_t *c) const
349   {
350     TRACE_SANITIZE (this);
351     if (!u.major.sanitize (c)) return_trace (false);
352     switch (u.major) {
353     case 0: return_trace (u.ot.sanitize (c));
354     case 1: return_trace (u.aat.sanitize (c));
355     default:return_trace (true);
356     }
357   }
358 
359   struct accelerator_t
360   {
initOT::kern::accelerator_t361     inline void init (hb_face_t *face)
362     {
363       blob = Sanitizer<kern>::sanitize (face->reference_table (HB_OT_TAG_kern));
364       table = Sanitizer<kern>::lock_instance (blob);
365       table_length = hb_blob_get_length (blob);
366     }
finiOT::kern::accelerator_t367     inline void fini (void)
368     {
369       hb_blob_destroy (blob);
370     }
371 
get_h_kerningOT::kern::accelerator_t372     inline int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right) const
373     { return table->get_h_kerning (left, right, table_length); }
374 
375     private:
376     hb_blob_t *blob;
377     const kern *table;
378     unsigned int table_length;
379   };
380 
381   protected:
382   union {
383   UINT16		major;
384   KernOT		ot;
385   KernAAT		aat;
386   } u;
387   public:
388   DEFINE_SIZE_UNION (2, major);
389 };
390 
391 } /* namespace OT */
392 
393 
394 #endif /* HB_OT_KERN_TABLE_HH */
395