1/*
2 * Copyright �� 2016  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): Seigo Nonaka
25 */
26
27#ifndef HB_OT_CBDT_TABLE_HH
28#define HB_OT_CBDT_TABLE_HH
29
30#include "hb-open-type-private.hh"
31
32namespace OT {
33
34struct SmallGlyphMetrics
35{
36  inline bool sanitize (hb_sanitize_context_t *c) const
37  {
38    TRACE_SANITIZE (this);
39    return_trace (c->check_struct (this));
40  }
41
42  inline void get_extents (hb_glyph_extents_t *extents) const
43  {
44    extents->x_bearing = bearingX;
45    extents->y_bearing = bearingY;
46    extents->width = width;
47    extents->height = -height;
48  }
49
50  BYTE height;
51  BYTE width;
52  CHAR bearingX;
53  CHAR bearingY;
54  BYTE advance;
55
56  DEFINE_SIZE_STATIC(5);
57};
58
59struct BigGlyphMetrics : SmallGlyphMetrics
60{
61  CHAR vertBearingX;
62  CHAR vertBearingY;
63  BYTE vertAdvance;
64
65  DEFINE_SIZE_STATIC(8);
66};
67
68struct SBitLineMetrics
69{
70  inline bool sanitize (hb_sanitize_context_t *c) const
71  {
72    TRACE_SANITIZE (this);
73    return_trace (c->check_struct (this));
74  }
75
76  CHAR ascender;
77  CHAR decender;
78  BYTE widthMax;
79  CHAR caretSlopeNumerator;
80  CHAR caretSlopeDenominator;
81  CHAR caretOffset;
82  CHAR minOriginSB;
83  CHAR minAdvanceSB;
84  CHAR maxBeforeBL;
85  CHAR minAfterBL;
86  CHAR padding1;
87  CHAR padding2;
88
89  DEFINE_SIZE_STATIC(12);
90};
91
92
93/*
94 * Index Subtables.
95 */
96
97struct IndexSubtableHeader
98{
99  inline bool sanitize (hb_sanitize_context_t *c) const
100  {
101    TRACE_SANITIZE (this);
102    return_trace (c->check_struct (this));
103  }
104
105  USHORT indexFormat;
106  USHORT imageFormat;
107  ULONG imageDataOffset;
108
109  DEFINE_SIZE_STATIC(8);
110};
111
112template <typename OffsetType>
113struct IndexSubtableFormat1Or3
114{
115  inline bool sanitize (hb_sanitize_context_t *c, unsigned int glyph_count) const
116  {
117    TRACE_SANITIZE (this);
118    return_trace (c->check_struct (this) &&
119		  c->check_array (offsetArrayZ, offsetArrayZ[0].static_size, glyph_count + 1));
120  }
121
122  bool get_image_data (unsigned int idx,
123		       unsigned int *offset,
124		       unsigned int *length) const
125  {
126    if (unlikely (offsetArrayZ[idx + 1] <= offsetArrayZ[idx]))
127      return false;
128
129    *offset = header.imageDataOffset + offsetArrayZ[idx];
130    *length = offsetArrayZ[idx + 1] - offsetArrayZ[idx];
131    return true;
132  }
133
134  IndexSubtableHeader header;
135  Offset<OffsetType> offsetArrayZ[VAR];
136
137  DEFINE_SIZE_ARRAY(8, offsetArrayZ);
138};
139
140struct IndexSubtableFormat1 : IndexSubtableFormat1Or3<ULONG> {};
141struct IndexSubtableFormat3 : IndexSubtableFormat1Or3<USHORT> {};
142
143struct IndexSubtable
144{
145  inline bool sanitize (hb_sanitize_context_t *c, unsigned int glyph_count) const
146  {
147    TRACE_SANITIZE (this);
148    if (!u.header.sanitize (c)) return_trace (false);
149    switch (u.header.indexFormat) {
150    case 1: return_trace (u.format1.sanitize (c, glyph_count));
151    case 3: return_trace (u.format3.sanitize (c, glyph_count));
152    default:return_trace (true);
153    }
154  }
155
156  inline bool get_extents (hb_glyph_extents_t *extents) const
157  {
158    switch (u.header.indexFormat) {
159    case 2: case 5: /* TODO */
160    case 1: case 3: case 4: /* Variable-metrics formats do not have metrics here. */
161    default:return (false);
162    }
163  }
164
165  bool get_image_data (unsigned int idx,
166		       unsigned int *offset,
167		       unsigned int *length,
168		       unsigned int *format) const
169  {
170    *format = u.header.imageFormat;
171    switch (u.header.indexFormat) {
172    case 1: return u.format1.get_image_data (idx, offset, length);
173    case 3: return u.format3.get_image_data (idx, offset, length);
174    default: return false;
175    }
176  }
177
178  protected:
179  union {
180  IndexSubtableHeader	header;
181  IndexSubtableFormat1	format1;
182  IndexSubtableFormat3	format3;
183  /* TODO: Format 2, 4, 5. */
184  } u;
185  public:
186  DEFINE_SIZE_UNION (8, header);
187};
188
189struct IndexSubtableRecord
190{
191  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
192  {
193    TRACE_SANITIZE (this);
194    return_trace (c->check_struct (this) &&
195		  firstGlyphIndex <= lastGlyphIndex &&
196		  offsetToSubtable.sanitize (c, this, lastGlyphIndex - firstGlyphIndex + 1));
197  }
198
199  inline bool get_extents (hb_glyph_extents_t *extents) const
200  {
201    return (this+offsetToSubtable).get_extents (extents);
202  }
203
204  bool get_image_data (unsigned int gid,
205		       unsigned int *offset,
206		       unsigned int *length,
207		       unsigned int *format) const
208  {
209    if (gid < firstGlyphIndex || gid > lastGlyphIndex)
210    {
211      return false;
212    }
213    return (this+offsetToSubtable).get_image_data (gid - firstGlyphIndex,
214						   offset, length, format);
215  }
216
217  USHORT firstGlyphIndex;
218  USHORT lastGlyphIndex;
219  OffsetTo<IndexSubtable, ULONG> offsetToSubtable;
220
221  DEFINE_SIZE_STATIC(8);
222};
223
224struct IndexSubtableArray
225{
226  inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
227  {
228    TRACE_SANITIZE (this);
229    if (unlikely (!c->check_array (&indexSubtablesZ, indexSubtablesZ[0].static_size, count)))
230      return_trace (false);
231    for (unsigned int i = 0; i < count; i++)
232      if (unlikely (!indexSubtablesZ[i].sanitize (c, this)))
233	return_trace (false);
234    return_trace (true);
235  }
236
237  public:
238  const IndexSubtableRecord* find_table (hb_codepoint_t glyph, unsigned int numTables) const
239  {
240    for (unsigned int i = 0; i < numTables; ++i)
241    {
242      unsigned int firstGlyphIndex = indexSubtablesZ[i].firstGlyphIndex;
243      unsigned int lastGlyphIndex = indexSubtablesZ[i].lastGlyphIndex;
244      if (firstGlyphIndex <= glyph && glyph <= lastGlyphIndex) {
245        return &indexSubtablesZ[i];
246      }
247    }
248    return NULL;
249  }
250
251  protected:
252  IndexSubtableRecord indexSubtablesZ[VAR];
253
254  public:
255  DEFINE_SIZE_ARRAY(0, indexSubtablesZ);
256};
257
258struct BitmapSizeTable
259{
260  friend struct CBLC;
261
262  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
263  {
264    TRACE_SANITIZE (this);
265    return_trace (c->check_struct (this) &&
266		  indexSubtableArrayOffset.sanitize (c, base, numberOfIndexSubtables) &&
267		  c->check_range (&(base+indexSubtableArrayOffset), indexTablesSize) &&
268		  horizontal.sanitize (c) &&
269		  vertical.sanitize (c));
270  }
271
272  const IndexSubtableRecord *find_table (hb_codepoint_t glyph, const void *base) const
273  {
274    return (base+indexSubtableArrayOffset).find_table (glyph, numberOfIndexSubtables);
275  }
276
277  protected:
278  OffsetTo<IndexSubtableArray, ULONG> indexSubtableArrayOffset;
279  ULONG indexTablesSize;
280  ULONG numberOfIndexSubtables;
281  ULONG colorRef;
282  SBitLineMetrics horizontal;
283  SBitLineMetrics vertical;
284  USHORT startGlyphIndex;
285  USHORT endGlyphIndex;
286  BYTE ppemX;
287  BYTE ppemY;
288  BYTE bitDepth;
289  CHAR flags;
290
291public:
292  DEFINE_SIZE_STATIC(48);
293};
294
295
296/*
297 * Glyph Bitmap Data Formats.
298 */
299
300struct GlyphBitmapDataFormat17
301{
302  SmallGlyphMetrics glyphMetrics;
303  ULONG dataLen;
304  BYTE dataZ[VAR];
305
306  DEFINE_SIZE_ARRAY(9, dataZ);
307};
308
309
310/*
311 * CBLC -- Color Bitmap Location Table
312 */
313
314#define HB_OT_TAG_CBLC HB_TAG('C','B','L','C')
315
316struct CBLC
317{
318  static const hb_tag_t tableTag = HB_OT_TAG_CBLC;
319
320  inline bool sanitize (hb_sanitize_context_t *c) const
321  {
322    TRACE_SANITIZE (this);
323    return_trace (c->check_struct (this) &&
324		  likely (version.major == 2 || version.major == 3) &&
325		  sizeTables.sanitize (c, this));
326  }
327
328  public:
329  const IndexSubtableRecord *find_table (hb_codepoint_t glyph,
330					 unsigned int *x_ppem, unsigned int *y_ppem) const
331  {
332    /* TODO: Make it possible to select strike. */
333
334    unsigned int count = sizeTables.len;
335    for (uint32_t i = 0; i < count; ++i)
336    {
337      unsigned int startGlyphIndex = sizeTables.array[i].startGlyphIndex;
338      unsigned int endGlyphIndex = sizeTables.array[i].endGlyphIndex;
339      if (startGlyphIndex <= glyph && glyph <= endGlyphIndex)
340      {
341	*x_ppem = sizeTables[i].ppemX;
342	*y_ppem = sizeTables[i].ppemY;
343	return sizeTables[i].find_table (glyph, this);
344      }
345    }
346
347    return NULL;
348  }
349
350  protected:
351  FixedVersion<>version;
352  ArrayOf<BitmapSizeTable, ULONG> sizeTables;
353
354  public:
355  DEFINE_SIZE_ARRAY(8, sizeTables);
356};
357
358/*
359 * CBDT -- Color Bitmap Data Table
360 */
361#define HB_OT_TAG_CBDT HB_TAG('C','B','D','T')
362
363struct CBDT
364{
365  static const hb_tag_t tableTag = HB_OT_TAG_CBDT;
366
367  inline bool sanitize (hb_sanitize_context_t *c) const
368  {
369    TRACE_SANITIZE (this);
370    return_trace (c->check_struct (this) &&
371		  likely (version.major == 2 || version.major == 3));
372  }
373
374  protected:
375  FixedVersion<>version;
376  BYTE dataZ[VAR];
377
378  public:
379  DEFINE_SIZE_ARRAY(4, dataZ);
380};
381
382} /* namespace OT */
383
384#endif /* HB_OT_CBDT_TABLE_HH */
385