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 
32 namespace OT {
33 
34 struct SmallGlyphMetrics
35 {
sanitizeOT::SmallGlyphMetrics36   inline bool sanitize (hb_sanitize_context_t *c) const
37   {
38     TRACE_SANITIZE (this);
39     return_trace (c->check_struct (this));
40   }
41 
get_extentsOT::SmallGlyphMetrics42   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 
59 struct BigGlyphMetrics : SmallGlyphMetrics
60 {
61   CHAR vertBearingX;
62   CHAR vertBearingY;
63   BYTE vertAdvance;
64 
65   DEFINE_SIZE_STATIC(8);
66 };
67 
68 struct SBitLineMetrics
69 {
sanitizeOT::SBitLineMetrics70   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 
97 struct IndexSubtableHeader
98 {
sanitizeOT::IndexSubtableHeader99   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 
112 template <typename OffsetType>
113 struct IndexSubtableFormat1Or3
114 {
sanitizeOT::IndexSubtableFormat1Or3115   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 
get_image_dataOT::IndexSubtableFormat1Or3122   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 
140 struct IndexSubtableFormat1 : IndexSubtableFormat1Or3<ULONG> {};
141 struct IndexSubtableFormat3 : IndexSubtableFormat1Or3<USHORT> {};
142 
143 struct IndexSubtable
144 {
sanitizeOT::IndexSubtable145   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 
get_extentsOT::IndexSubtable156   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 
get_image_dataOT::IndexSubtable165   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 
189 struct IndexSubtableRecord
190 {
sanitizeOT::IndexSubtableRecord191   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 
get_extentsOT::IndexSubtableRecord199   inline bool get_extents (hb_glyph_extents_t *extents) const
200   {
201     return (this+offsetToSubtable).get_extents (extents);
202   }
203 
get_image_dataOT::IndexSubtableRecord204   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 
224 struct IndexSubtableArray
225 {
sanitizeOT::IndexSubtableArray226   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:
find_tableOT::IndexSubtableArray238   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 
258 struct BitmapSizeTable
259 {
260   friend struct CBLC;
261 
sanitizeOT::BitmapSizeTable262   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 
find_tableOT::BitmapSizeTable272   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 
291 public:
292   DEFINE_SIZE_STATIC(48);
293 };
294 
295 
296 /*
297  * Glyph Bitmap Data Formats.
298  */
299 
300 struct 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 
316 struct CBLC
317 {
318   static const hb_tag_t tableTag = HB_OT_TAG_CBLC;
319 
sanitizeOT::CBLC320   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:
find_tableOT::CBLC329   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 
363 struct CBDT
364 {
365   static const hb_tag_t tableTag = HB_OT_TAG_CBDT;
366 
sanitizeOT::CBDT367   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