Imported Upstream version 1.7.6
[platform/upstream/harfbuzz.git] / src / hb-ot-kern-table.hh
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 {
49   inline int get_kerning (void) const
50   { return value; }
51
52   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
59   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 {
75   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
84   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 {
98   inline unsigned int get_class (hb_codepoint_t g) const { return classes[g - firstGlyph]; }
99
100   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   HBUINT16              firstGlyph;     /* First glyph in class range. */
108   ArrayOf<HBUINT16>     classes;        /* Glyph classes. */
109   public:
110   DEFINE_SIZE_ARRAY (4, classes);
111 };
112
113 struct KernSubTableFormat2
114 {
115   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+rightClassTable).get_class (right);
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
129   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   HBUINT16      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 {
155   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
164   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 */
188   inline const T* thiz (void) const { return static_cast<const T *> (this); }
189
190   inline bool is_horizontal (void) const
191   { return (thiz()->coverage & T::COVERAGE_CHECK_FLAGS) == T::COVERAGE_CHECK_HORIZONTAL; }
192
193   inline bool is_override (void) const
194   { return bool (thiz()->coverage & T::COVERAGE_OVERRIDE_FLAG); }
195
196   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
199   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
202   inline unsigned int get_size (void) const { return thiz()->length; }
203
204   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 */
218   inline const T* thiz (void) const { return static_cast<const T *> (this); }
219
220   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
235   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     HBUINT16    versionZ;       /* Unused. */
279     HBUINT16    length;         /* Length of the subtable (including this header). */
280     HBUINT8     format;         /* Subtable format. */
281     HBUINT8     coverage;       /* Coverage bits. */
282     KernSubTable subtable;      /* Subtable data. */
283     public:
284     DEFINE_SIZE_MIN (6);
285   };
286
287   protected:
288   HBUINT16      version;        /* Version--0x0000u */
289   HBUINT16      nTables;        /* Number of subtables in the kerning table. */
290   HBUINT8               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     HBUINT32    length;         /* Length of the subtable (including this header). */
318     HBUINT8     coverage;       /* Coverage bits. */
319     HBUINT8     format;         /* Subtable format. */
320     HBUINT16    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   HBUINT32              version;        /* Version--0x00010000u */
329   HBUINT32              nTables;        /* Number of subtables in the kerning table. */
330   HBUINT8               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
339   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
348   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   {
361     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     }
367     inline void fini (void)
368     {
369       hb_blob_destroy (blob);
370     }
371
372     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   HBUINT16              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 */