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   UINT8 height;
51   UINT8 width;
52   INT8 bearingX;
53   INT8 bearingY;
54   UINT8 advance;
55 
56   DEFINE_SIZE_STATIC(5);
57 };
58 
59 struct BigGlyphMetrics : SmallGlyphMetrics
60 {
61   INT8 vertBearingX;
62   INT8 vertBearingY;
63   UINT8 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   INT8 ascender;
77   INT8 decender;
78   UINT8 widthMax;
79   INT8 caretSlopeNumerator;
80   INT8 caretSlopeDenominator;
81   INT8 caretOffset;
82   INT8 minOriginSB;
83   INT8 minAdvanceSB;
84   INT8 maxBeforeBL;
85   INT8 minAfterBL;
86   INT8 padding1;
87   INT8 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   UINT16 indexFormat;
106   UINT16 imageFormat;
107   UINT32 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<UINT32> {};
141 struct IndexSubtableFormat3 : IndexSubtableFormat1Or3<UINT16> {};
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   UINT16 firstGlyphIndex;
218   UINT16 lastGlyphIndex;
219   LOffsetTo<IndexSubtable> 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 nullptr;
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   LOffsetTo<IndexSubtableArray> indexSubtableArrayOffset;
279   UINT32 indexTablesSize;
280   UINT32 numberOfIndexSubtables;
281   UINT32 colorRef;
282   SBitLineMetrics horizontal;
283   SBitLineMetrics vertical;
284   UINT16 startGlyphIndex;
285   UINT16 endGlyphIndex;
286   UINT8 ppemX;
287   UINT8 ppemY;
288   UINT8 bitDepth;
289   INT8 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   UINT32 dataLen;
304   UINT8 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   friend struct CBDT;
319 
320   static const hb_tag_t tableTag = HB_OT_TAG_CBLC;
321 
sanitizeOT::CBLC322   inline bool sanitize (hb_sanitize_context_t *c) const
323   {
324     TRACE_SANITIZE (this);
325     return_trace (c->check_struct (this) &&
326 		  likely (version.major == 2 || version.major == 3) &&
327 		  sizeTables.sanitize (c, this));
328   }
329 
330   protected:
find_tableOT::CBLC331   const IndexSubtableRecord *find_table (hb_codepoint_t glyph,
332 					 unsigned int *x_ppem, unsigned int *y_ppem) const
333   {
334     /* TODO: Make it possible to select strike. */
335 
336     unsigned int count = sizeTables.len;
337     for (uint32_t i = 0; i < count; ++i)
338     {
339       unsigned int startGlyphIndex = sizeTables.array[i].startGlyphIndex;
340       unsigned int endGlyphIndex = sizeTables.array[i].endGlyphIndex;
341       if (startGlyphIndex <= glyph && glyph <= endGlyphIndex)
342       {
343 	*x_ppem = sizeTables[i].ppemX;
344 	*y_ppem = sizeTables[i].ppemY;
345 	return sizeTables[i].find_table (glyph, this);
346       }
347     }
348 
349     return nullptr;
350   }
351 
352   protected:
353   FixedVersion<>		version;
354   LArrayOf<BitmapSizeTable>	sizeTables;
355 
356   public:
357   DEFINE_SIZE_ARRAY(8, sizeTables);
358 };
359 
360 /*
361  * CBDT -- Color Bitmap Data Table
362  */
363 #define HB_OT_TAG_CBDT HB_TAG('C','B','D','T')
364 
365 struct CBDT
366 {
367   static const hb_tag_t tableTag = HB_OT_TAG_CBDT;
368 
sanitizeOT::CBDT369   inline bool sanitize (hb_sanitize_context_t *c) const
370   {
371     TRACE_SANITIZE (this);
372     return_trace (c->check_struct (this) &&
373 		  likely (version.major == 2 || version.major == 3));
374   }
375 
376   struct accelerator_t
377   {
initOT::CBDT::accelerator_t378     inline void init (hb_face_t *face)
379     {
380       upem = face->get_upem();
381 
382       cblc_blob = Sanitizer<CBLC>::sanitize (face->reference_table (HB_OT_TAG_CBLC));
383       cbdt_blob = Sanitizer<CBDT>::sanitize (face->reference_table (HB_OT_TAG_CBDT));
384       cbdt_len = hb_blob_get_length (cbdt_blob);
385 
386       if (hb_blob_get_length (cblc_blob) == 0) {
387 	cblc = nullptr;
388 	cbdt = nullptr;
389 	return;  /* Not a bitmap font. */
390       }
391       cblc = Sanitizer<CBLC>::lock_instance (cblc_blob);
392       cbdt = Sanitizer<CBDT>::lock_instance (cbdt_blob);
393 
394     }
395 
finiOT::CBDT::accelerator_t396     inline void fini (void)
397     {
398       hb_blob_destroy (this->cblc_blob);
399       hb_blob_destroy (this->cbdt_blob);
400     }
401 
get_extentsOT::CBDT::accelerator_t402     inline bool get_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
403     {
404       unsigned int x_ppem = upem, y_ppem = upem; /* TODO Use font ppem if available. */
405 
406       if (!cblc)
407 	return false;  // Not a color bitmap font.
408 
409       const IndexSubtableRecord *subtable_record = this->cblc->find_table(glyph, &x_ppem, &y_ppem);
410       if (!subtable_record || !x_ppem || !y_ppem)
411 	return false;
412 
413       if (subtable_record->get_extents (extents))
414 	return true;
415 
416       unsigned int image_offset = 0, image_length = 0, image_format = 0;
417       if (!subtable_record->get_image_data (glyph, &image_offset, &image_length, &image_format))
418 	return false;
419 
420       {
421 	if (unlikely (image_offset > cbdt_len || cbdt_len - image_offset < image_length))
422 	  return false;
423 
424 	switch (image_format)
425 	{
426 	  case 17: {
427 	    if (unlikely (image_length < GlyphBitmapDataFormat17::min_size))
428 	      return false;
429 
430 	    const GlyphBitmapDataFormat17& glyphFormat17 =
431 		StructAtOffset<GlyphBitmapDataFormat17> (this->cbdt, image_offset);
432 	    glyphFormat17.glyphMetrics.get_extents (extents);
433 	  }
434 	  break;
435 	  default:
436 	    // TODO: Support other image formats.
437 	    return false;
438 	}
439       }
440 
441       /* Convert to the font units. */
442       extents->x_bearing *= upem / (float) x_ppem;
443       extents->y_bearing *= upem / (float) y_ppem;
444       extents->width *= upem / (float) x_ppem;
445       extents->height *= upem / (float) y_ppem;
446 
447       return true;
448     }
449 
450     private:
451     hb_blob_t *cblc_blob;
452     hb_blob_t *cbdt_blob;
453     const CBLC *cblc;
454     const CBDT *cbdt;
455 
456     unsigned int cbdt_len;
457     unsigned int upem;
458   };
459 
460 
461   protected:
462   FixedVersion<>version;
463   UINT8 dataZ[VAR];
464 
465   public:
466   DEFINE_SIZE_ARRAY(4, dataZ);
467 };
468 
469 } /* namespace OT */
470 
471 #endif /* HB_OT_CBDT_TABLE_HH */
472