Imported Upstream version 1.7.6
[platform/upstream/harfbuzz.git] / src / hb-ot-color-cbdt-table.hh
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_COLOR_CBDT_TABLE_HH
28 #define HB_OT_COLOR_CBDT_TABLE_HH
29
30 #include "hb-open-type-private.hh"
31
32 namespace OT {
33
34 struct 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   HBUINT8 height;
51   HBUINT8 width;
52   HBINT8 bearingX;
53   HBINT8 bearingY;
54   HBUINT8 advance;
55
56   DEFINE_SIZE_STATIC(5);
57 };
58
59 struct BigGlyphMetrics : SmallGlyphMetrics
60 {
61   HBINT8 vertBearingX;
62   HBINT8 vertBearingY;
63   HBUINT8 vertAdvance;
64
65   DEFINE_SIZE_STATIC(8);
66 };
67
68 struct 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   HBINT8 ascender;
77   HBINT8 decender;
78   HBUINT8 widthMax;
79   HBINT8 caretSlopeNumerator;
80   HBINT8 caretSlopeDenominator;
81   HBINT8 caretOffset;
82   HBINT8 minOriginSB;
83   HBINT8 minAdvanceSB;
84   HBINT8 maxBeforeBL;
85   HBINT8 minAfterBL;
86   HBINT8 padding1;
87   HBINT8 padding2;
88
89   DEFINE_SIZE_STATIC(12);
90 };
91
92
93 /*
94  * Index Subtables.
95  */
96
97 struct 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   HBUINT16 indexFormat;
106   HBUINT16 imageFormat;
107   HBUINT32 imageDataOffset;
108
109   DEFINE_SIZE_STATIC(8);
110 };
111
112 template <typename OffsetType>
113 struct 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
140 struct IndexSubtableFormat1 : IndexSubtableFormat1Or3<HBUINT32> {};
141 struct IndexSubtableFormat3 : IndexSubtableFormat1Or3<HBUINT16> {};
142
143 struct 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
189 struct 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   HBUINT16 firstGlyphIndex;
218   HBUINT16 lastGlyphIndex;
219   LOffsetTo<IndexSubtable> offsetToSubtable;
220
221   DEFINE_SIZE_STATIC(8);
222 };
223
224 struct 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 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
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   LOffsetTo<IndexSubtableArray> indexSubtableArrayOffset;
279   HBUINT32 indexTablesSize;
280   HBUINT32 numberOfIndexSubtables;
281   HBUINT32 colorRef;
282   SBitLineMetrics horizontal;
283   SBitLineMetrics vertical;
284   HBUINT16 startGlyphIndex;
285   HBUINT16 endGlyphIndex;
286   HBUINT8 ppemX;
287   HBUINT8 ppemY;
288   HBUINT8 bitDepth;
289   HBINT8 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   HBUINT32 dataLen;
304   HBUINT8 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
322   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:
331   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
369   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   {
378     inline void init (hb_face_t *face)
379     {
380       upem = hb_face_get_upem (face);
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
396     inline void fini (void)
397     {
398       hb_blob_destroy (this->cblc_blob);
399       hb_blob_destroy (this->cbdt_blob);
400     }
401
402     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   HBUINT8 dataZ[VAR];
464
465   public:
466   DEFINE_SIZE_ARRAY(4, dataZ);
467 };
468
469 } /* namespace OT */
470
471 #endif /* HB_OT_COLOR_CBDT_TABLE_HH */