Imported Upstream version 1.8.1
[platform/upstream/harfbuzz.git] / src / hb-aat-layout-kerx-table.hh
1 /*
2  * Copyright © 2018  Ebrahim Byagowi
3  * Copyright © 2018  Google, Inc.
4  *
5  *  This is part of HarfBuzz, a text shaping library.
6  *
7  * Permission is hereby granted, without written agreement and without
8  * license or royalty fees, to use, copy, modify, and distribute this
9  * software and its documentation for any purpose, provided that the
10  * above copyright notice and the following two paragraphs appear in
11  * all copies of this software.
12  *
13  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
17  * DAMAGE.
18  *
19  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
22  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24  *
25  * Google Author(s): Behdad Esfahbod
26  */
27
28 #ifndef HB_AAT_LAYOUT_KERX_TABLE_HH
29 #define HB_AAT_LAYOUT_KERX_TABLE_HH
30
31 #include "hb-open-type-private.hh"
32 #include "hb-aat-layout-common-private.hh"
33 #include "hb-aat-layout-ankr-table.hh"
34
35 /*
36  * kerx -- Extended Kerning
37  * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6kerx.html
38  */
39 #define HB_AAT_TAG_kerx HB_TAG('k','e','r','x')
40
41
42 namespace AAT {
43
44 using namespace OT;
45
46
47 struct KerxFormat0Records
48 {
49   inline bool sanitize (hb_sanitize_context_t *c) const
50   {
51     TRACE_SANITIZE (this);
52     return_trace (likely (c->check_struct (this)));
53   }
54
55   protected:
56   GlyphID       left;
57   GlyphID       right;
58   FWORD         value;
59   public:
60   DEFINE_SIZE_STATIC (6);
61 };
62
63 struct KerxSubTableFormat0
64 {
65   // TODO(ebraminio) Enable when we got suitable BinSearchArrayOf
66   // inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
67   // {
68   //   hb_glyph_pair_t pair = {left, right};
69   //   int i = pairs.bsearch (pair);
70   //   if (i == -1)
71   //     return 0;
72   //   return pairs[i].get_kerning ();
73   // }
74
75   inline bool sanitize (hb_sanitize_context_t *c) const
76   {
77     TRACE_SANITIZE (this);
78     return_trace (likely (c->check_struct (this) &&
79                           recordsZ.sanitize (c, nPairs)));
80   }
81
82   protected:
83   // TODO(ebraminio): A custom version of "BinSearchArrayOf<KerxPair> pairs;" is
84   // needed here to use HBUINT32 instead
85   HBUINT32      nPairs;         /* The number of kerning pairs in this subtable */
86   HBUINT32      searchRange;    /* The largest power of two less than or equal to the value of nPairs,
87                                  * multiplied by the size in bytes of an entry in the subtable. */
88   HBUINT32      entrySelector;  /* This is calculated as log2 of the largest power of two less
89                                  * than or equal to the value of nPairs. */
90   HBUINT32      rangeShift;     /* The value of nPairs minus the largest power of two less than or equal to nPairs. */
91   UnsizedArrayOf<KerxFormat0Records>
92                 recordsZ;       /* VAR=nPairs */
93   public:
94   DEFINE_SIZE_ARRAY (16, recordsZ);
95 };
96
97 struct KerxSubTableFormat1
98 {
99   inline bool sanitize (hb_sanitize_context_t *c) const
100   {
101     TRACE_SANITIZE (this);
102     return_trace (likely (c->check_struct (this) &&
103                           stateHeader.sanitize (c)));
104   }
105
106   protected:
107   StateTable<HBUINT16>          stateHeader;
108   LOffsetTo<ArrayOf<HBUINT16> > valueTable;
109   public:
110   DEFINE_SIZE_STATIC (20);
111 };
112
113 // TODO(ebraminio): Maybe this can be replaced with Lookup<HBUINT16>?
114 struct KerxClassTable
115 {
116   inline unsigned int get_class (hb_codepoint_t g) const { return classes[g - firstGlyph]; }
117
118   inline bool sanitize (hb_sanitize_context_t *c) const
119   {
120     TRACE_SANITIZE (this);
121     return_trace (likely (firstGlyph.sanitize (c) &&
122                           classes.sanitize (c)));
123   }
124
125   protected:
126   HBUINT16              firstGlyph;     /* First glyph in class range. */
127   ArrayOf<HBUINT16>     classes;        /* Glyph classes. */
128   public:
129   DEFINE_SIZE_ARRAY (4, classes);
130 };
131
132 struct KerxSubTableFormat2
133 {
134   inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right, const char *end) const
135   {
136     unsigned int l = (this+leftClassTable).get_class (left);
137     unsigned int r = (this+leftClassTable).get_class (left);
138     unsigned int offset = l * rowWidth + r * sizeof (FWORD);
139     const FWORD *arr = &(this+array);
140     if (unlikely ((const void *) arr < (const void *) this || (const void *) arr >= (const void *) end))
141       return 0;
142     const FWORD *v = &StructAtOffset<FWORD> (arr, offset);
143     if (unlikely ((const void *) v < (const void *) arr || (const void *) (v + 1) > (const void *) end))
144       return 0;
145     return *v;
146   }
147
148   inline bool sanitize (hb_sanitize_context_t *c) const
149   {
150     TRACE_SANITIZE (this);
151     return_trace (likely (c->check_struct (this) &&
152                           rowWidth.sanitize (c) &&
153                           leftClassTable.sanitize (c, this) &&
154                           rightClassTable.sanitize (c, this) &&
155                           array.sanitize (c, this)));
156   }
157
158   protected:
159   HBUINT32      rowWidth;       /* The width, in bytes, of a row in the table. */
160   LOffsetTo<KerxClassTable>
161                 leftClassTable; /* Offset from beginning of this subtable to
162                                  * left-hand class table. */
163   LOffsetTo<KerxClassTable>
164                 rightClassTable;/* Offset from beginning of this subtable to
165                                  * right-hand class table. */
166   LOffsetTo<FWORD>
167                 array;          /* Offset from beginning of this subtable to
168                                  * the start of the kerning array. */
169   public:
170   DEFINE_SIZE_STATIC (16);
171 };
172
173 struct KerxSubTableFormat4
174 {
175   inline bool sanitize (hb_sanitize_context_t *c) const
176   {
177     TRACE_SANITIZE (this);
178     return_trace (likely (c->check_struct (this) &&
179                           rowWidth.sanitize (c) &&
180                           leftClassTable.sanitize (c, this) &&
181                           rightClassTable.sanitize (c, this) &&
182                           array.sanitize (c, this)));
183   }
184
185   protected:
186   HBUINT32      rowWidth;       /* The width, in bytes, of a row in the table. */
187   LOffsetTo<KerxClassTable>
188                 leftClassTable; /* Offset from beginning of this subtable to
189                                  * left-hand class table. */
190   LOffsetTo<KerxClassTable>
191                 rightClassTable;/* Offset from beginning of this subtable to
192                                  * right-hand class table. */
193   LOffsetTo<FWORD>
194                 array;          /* Offset from beginning of this subtable to
195                                  * the start of the kerning array. */
196   public:
197   DEFINE_SIZE_STATIC (16);
198 };
199
200 struct KerxSubTableFormat6
201 {
202   inline bool sanitize (hb_sanitize_context_t *c) const
203   {
204     TRACE_SANITIZE (this);
205     return_trace (likely (c->check_struct (this) &&
206                           rowIndexTable.sanitize (c, this) &&
207                           columnIndexTable.sanitize (c, this) &&
208                           kerningArray.sanitize (c, this) &&
209                           kerningVector.sanitize (c, this)));
210   }
211
212   protected:
213   HBUINT32      flags;
214   HBUINT16      rowCount;
215   HBUINT16      columnCount;
216   LOffsetTo<Lookup<HBUINT16> >  rowIndexTable;
217   LOffsetTo<Lookup<HBUINT16> >  columnIndexTable;
218   LOffsetTo<Lookup<HBUINT16> >  kerningArray;
219   LOffsetTo<Lookup<HBUINT16> >  kerningVector;
220   public:
221   DEFINE_SIZE_STATIC (24);
222 };
223
224 enum coverage_flags_t
225 {
226   COVERAGE_VERTICAL_FLAG        = 0x80u,
227   COVERAGE_CROSSSTREAM_FLAG     = 0x40u,
228   COVERAGE_VARIATION_FLAG       = 0x20u,
229   COVERAGE_PROCESS_DIRECTION    = 0x10u,
230 };
231
232 struct KerxTable
233 {
234   inline bool apply (hb_aat_apply_context_t *c, const AAT::ankr *ankr) const
235   {
236     TRACE_APPLY (this);
237     /* TODO */
238     return_trace (false);
239   }
240
241   inline unsigned int get_size (void) const { return length; }
242
243   inline bool sanitize (hb_sanitize_context_t *c) const
244   {
245     TRACE_SANITIZE (this);
246     if (unlikely (!c->check_struct (this)))
247       return_trace (false);
248
249     switch (format) {
250     case 0: return u.format0.sanitize (c);
251     case 1: return u.format1.sanitize (c);
252     case 2: return u.format2.sanitize (c);
253     case 4: return u.format4.sanitize (c);
254     case 6: return u.format6.sanitize (c);
255     default:return_trace (false);
256     }
257   }
258
259 protected:
260   HBUINT32      length;
261   HBUINT8       coverage;
262   HBUINT16      unused;
263   HBUINT8       format;
264   HBUINT32      tupleIndex;
265   union {
266   KerxSubTableFormat0   format0;
267   KerxSubTableFormat1   format1;
268   KerxSubTableFormat2   format2;
269   KerxSubTableFormat4   format4;
270   KerxSubTableFormat6   format6;
271   } u;
272 public:
273   DEFINE_SIZE_MIN (12);
274 };
275
276 struct SubtableGlyphCoverageArray
277 {
278   inline bool sanitize (hb_sanitize_context_t *c) const
279   {
280     TRACE_SANITIZE (this);
281     return_trace (likely (c->check_struct (this)));
282   }
283
284   protected:
285   HBUINT32      length;
286   HBUINT32      coverage;
287   HBUINT32      tupleCount;
288   public:
289   DEFINE_SIZE_STATIC (12);
290 };
291
292 struct kerx
293 {
294   static const hb_tag_t tableTag = HB_AAT_TAG_kerx;
295
296   inline bool apply (hb_aat_apply_context_t *c, const AAT::ankr *ankr) const
297   {
298     TRACE_APPLY (this);
299     const KerxTable &table = StructAfter<KerxTable> (*this);
300     return_trace (table.apply (c, ankr));
301   }
302
303   inline bool sanitize (hb_sanitize_context_t *c) const
304   {
305     TRACE_SANITIZE (this);
306     if (unlikely (!(c->check_struct (this))))
307      return_trace (false);
308
309     /* TODO: Something like `morx`s ChainSubtable should be done here instead */
310     const KerxTable *table = &StructAfter<KerxTable> (*this);
311     if (unlikely (!(table->sanitize (c))))
312       return_trace (false);
313
314     for (unsigned int i = 0; i < nTables - 1; ++i)
315     {
316       table = &StructAfter<KerxTable> (*table);
317       if (unlikely (!(table->sanitize (c))))
318         return_trace (false);
319     }
320
321     // If version is less than 3, we are done here; otherwise better to check footer also
322     if (version < 3)
323       return_trace (true);
324
325     // TODO: Investigate why this just work on some fonts no matter of version
326     // const SubtableGlyphCoverageArray &footer =
327     //   StructAfter<SubtableGlyphCoverageArray> (*table);
328     // return_trace (footer.sanitize (c));
329
330     return_trace (true);
331   }
332
333   protected:
334   HBUINT16              version;
335   HBUINT16              padding;
336   HBUINT32              nTables;
337 /*KerxTable tablesZ[VAR]; XXX ArrayOf??? */
338 /*SubtableGlyphCoverageArray coverage_array;*/
339   public:
340   DEFINE_SIZE_STATIC (8);
341 };
342
343 } /* namespace AAT */
344
345
346 #endif /* HB_AAT_LAYOUT_KERX_TABLE_HH */