Imported Upstream version 2.3.1
[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.hh"
31
32 /*
33  * CBLC -- Color Bitmap Location
34  * https://docs.microsoft.com/en-us/typography/opentype/spec/cblc
35  * https://docs.microsoft.com/en-us/typography/opentype/spec/eblc
36  * CBDT -- Color Bitmap Data
37  * https://docs.microsoft.com/en-us/typography/opentype/spec/cbdt
38  * https://docs.microsoft.com/en-us/typography/opentype/spec/ebdt
39  */
40 #define HB_OT_TAG_CBLC HB_TAG('C','B','L','C')
41 #define HB_OT_TAG_CBDT HB_TAG('C','B','D','T')
42
43
44 namespace OT {
45
46 struct SmallGlyphMetrics
47 {
48   bool sanitize (hb_sanitize_context_t *c) const
49   {
50     TRACE_SANITIZE (this);
51     return_trace (c->check_struct (this));
52   }
53
54   void get_extents (hb_glyph_extents_t *extents) const
55   {
56     extents->x_bearing = bearingX;
57     extents->y_bearing = bearingY;
58     extents->width = width;
59     extents->height = - (hb_position_t) height;
60   }
61
62   HBUINT8       height;
63   HBUINT8       width;
64   HBINT8        bearingX;
65   HBINT8        bearingY;
66   HBUINT8       advance;
67   public:
68   DEFINE_SIZE_STATIC(5);
69 };
70
71 struct BigGlyphMetrics : SmallGlyphMetrics
72 {
73   HBINT8        vertBearingX;
74   HBINT8        vertBearingY;
75   HBUINT8       vertAdvance;
76   public:
77   DEFINE_SIZE_STATIC(8);
78 };
79
80 struct SBitLineMetrics
81 {
82   bool sanitize (hb_sanitize_context_t *c) const
83   {
84     TRACE_SANITIZE (this);
85     return_trace (c->check_struct (this));
86   }
87
88   HBINT8        ascender;
89   HBINT8        decender;
90   HBUINT8       widthMax;
91   HBINT8        caretSlopeNumerator;
92   HBINT8        caretSlopeDenominator;
93   HBINT8        caretOffset;
94   HBINT8        minOriginSB;
95   HBINT8        minAdvanceSB;
96   HBINT8        maxBeforeBL;
97   HBINT8        minAfterBL;
98   HBINT8        padding1;
99   HBINT8        padding2;
100   public:
101   DEFINE_SIZE_STATIC(12);
102 };
103
104
105 /*
106  * Index Subtables.
107  */
108
109 struct IndexSubtableHeader
110 {
111   bool sanitize (hb_sanitize_context_t *c) const
112   {
113     TRACE_SANITIZE (this);
114     return_trace (c->check_struct (this));
115   }
116
117   HBUINT16      indexFormat;
118   HBUINT16      imageFormat;
119   HBUINT32      imageDataOffset;
120   public:
121   DEFINE_SIZE_STATIC(8);
122 };
123
124 template <typename OffsetType>
125 struct IndexSubtableFormat1Or3
126 {
127   bool sanitize (hb_sanitize_context_t *c, unsigned int glyph_count) const
128   {
129     TRACE_SANITIZE (this);
130     return_trace (c->check_struct (this) &&
131                   offsetArrayZ.sanitize (c, glyph_count + 1));
132   }
133
134   bool get_image_data (unsigned int idx,
135                        unsigned int *offset,
136                        unsigned int *length) const
137   {
138     if (unlikely (offsetArrayZ[idx + 1] <= offsetArrayZ[idx]))
139       return false;
140
141     *offset = header.imageDataOffset + offsetArrayZ[idx];
142     *length = offsetArrayZ[idx + 1] - offsetArrayZ[idx];
143     return true;
144   }
145
146   IndexSubtableHeader   header;
147   UnsizedArrayOf<Offset<OffsetType> >
148                         offsetArrayZ;
149   public:
150   DEFINE_SIZE_ARRAY(8, offsetArrayZ);
151 };
152
153 struct IndexSubtableFormat1 : IndexSubtableFormat1Or3<HBUINT32> {};
154 struct IndexSubtableFormat3 : IndexSubtableFormat1Or3<HBUINT16> {};
155
156 struct IndexSubtable
157 {
158   bool sanitize (hb_sanitize_context_t *c, unsigned int glyph_count) const
159   {
160     TRACE_SANITIZE (this);
161     if (!u.header.sanitize (c)) return_trace (false);
162     switch (u.header.indexFormat) {
163     case 1: return_trace (u.format1.sanitize (c, glyph_count));
164     case 3: return_trace (u.format3.sanitize (c, glyph_count));
165     default:return_trace (true);
166     }
167   }
168
169   bool get_extents (hb_glyph_extents_t *extents HB_UNUSED) const
170   {
171     switch (u.header.indexFormat) {
172     case 2: case 5: /* TODO */
173     case 1: case 3: case 4: /* Variable-metrics formats do not have metrics here. */
174     default:return (false);
175     }
176   }
177
178   bool get_image_data (unsigned int idx,
179                        unsigned int *offset,
180                        unsigned int *length,
181                        unsigned int *format) const
182   {
183     *format = u.header.imageFormat;
184     switch (u.header.indexFormat) {
185     case 1: return u.format1.get_image_data (idx, offset, length);
186     case 3: return u.format3.get_image_data (idx, offset, length);
187     default: return false;
188     }
189   }
190
191   protected:
192   union {
193   IndexSubtableHeader   header;
194   IndexSubtableFormat1  format1;
195   IndexSubtableFormat3  format3;
196   /* TODO: Format 2, 4, 5. */
197   } u;
198   public:
199   DEFINE_SIZE_UNION (8, header);
200 };
201
202 struct IndexSubtableRecord
203 {
204   bool sanitize (hb_sanitize_context_t *c, const void *base) const
205   {
206     TRACE_SANITIZE (this);
207     return_trace (c->check_struct (this) &&
208                   firstGlyphIndex <= lastGlyphIndex &&
209                   offsetToSubtable.sanitize (c, base, lastGlyphIndex - firstGlyphIndex + 1));
210   }
211
212   bool get_extents (hb_glyph_extents_t *extents,
213                     const void *base) const
214   {
215     return (base+offsetToSubtable).get_extents (extents);
216   }
217
218   bool get_image_data (unsigned int  gid,
219                        const void   *base,
220                        unsigned int *offset,
221                        unsigned int *length,
222                        unsigned int *format) const
223   {
224     if (gid < firstGlyphIndex || gid > lastGlyphIndex) return false;
225     return (base+offsetToSubtable).get_image_data (gid - firstGlyphIndex,
226                                                    offset, length, format);
227   }
228
229   GlyphID                       firstGlyphIndex;
230   GlyphID                       lastGlyphIndex;
231   LOffsetTo<IndexSubtable>      offsetToSubtable;
232   public:
233   DEFINE_SIZE_STATIC(8);
234 };
235
236 struct IndexSubtableArray
237 {
238   friend struct CBDT;
239
240   bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
241   {
242     TRACE_SANITIZE (this);
243     return_trace (indexSubtablesZ.sanitize (c, count, this));
244   }
245
246   public:
247   const IndexSubtableRecord* find_table (hb_codepoint_t glyph, unsigned int numTables) const
248   {
249     for (unsigned int i = 0; i < numTables; ++i)
250     {
251       unsigned int firstGlyphIndex = indexSubtablesZ[i].firstGlyphIndex;
252       unsigned int lastGlyphIndex = indexSubtablesZ[i].lastGlyphIndex;
253       if (firstGlyphIndex <= glyph && glyph <= lastGlyphIndex)
254         return &indexSubtablesZ[i];
255     }
256     return nullptr;
257   }
258
259   protected:
260   UnsizedArrayOf<IndexSubtableRecord>   indexSubtablesZ;
261 };
262
263 struct BitmapSizeTable
264 {
265   friend struct CBLC;
266   friend struct CBDT;
267
268   bool sanitize (hb_sanitize_context_t *c, const void *base) const
269   {
270     TRACE_SANITIZE (this);
271     return_trace (c->check_struct (this) &&
272                   indexSubtableArrayOffset.sanitize (c, base, numberOfIndexSubtables) &&
273                   horizontal.sanitize (c) &&
274                   vertical.sanitize (c));
275   }
276
277   const IndexSubtableRecord *find_table (hb_codepoint_t glyph,
278                                          const void *base,
279                                          const void **out_base) const
280   {
281     *out_base = &(base+indexSubtableArrayOffset);
282     return (base+indexSubtableArrayOffset).find_table (glyph, numberOfIndexSubtables);
283   }
284
285   protected:
286   LNNOffsetTo<IndexSubtableArray>
287                         indexSubtableArrayOffset;
288   HBUINT32              indexTablesSize;
289   HBUINT32              numberOfIndexSubtables;
290   HBUINT32              colorRef;
291   SBitLineMetrics       horizontal;
292   SBitLineMetrics       vertical;
293   GlyphID               startGlyphIndex;
294   GlyphID               endGlyphIndex;
295   HBUINT8               ppemX;
296   HBUINT8               ppemY;
297   HBUINT8               bitDepth;
298   HBINT8                flags;
299   public:
300   DEFINE_SIZE_STATIC(48);
301 };
302
303
304 /*
305  * Glyph Bitmap Data Formats.
306  */
307
308 struct GlyphBitmapDataFormat17
309 {
310   SmallGlyphMetrics     glyphMetrics;
311   LArrayOf<HBUINT8>     data;
312   public:
313   DEFINE_SIZE_ARRAY(9, data);
314 };
315
316 struct GlyphBitmapDataFormat18
317 {
318   BigGlyphMetrics       glyphMetrics;
319   LArrayOf<HBUINT8>     data;
320   public:
321   DEFINE_SIZE_ARRAY(12, data);
322 };
323
324 struct GlyphBitmapDataFormat19
325 {
326   LArrayOf<HBUINT8>     data;
327   public:
328   DEFINE_SIZE_ARRAY(4, data);
329 };
330
331 struct CBLC
332 {
333   friend struct CBDT;
334
335   static constexpr hb_tag_t tableTag = HB_OT_TAG_CBLC;
336
337   bool sanitize (hb_sanitize_context_t *c) const
338   {
339     TRACE_SANITIZE (this);
340     return_trace (c->check_struct (this) &&
341                   likely (version.major == 2 || version.major == 3) &&
342                   sizeTables.sanitize (c, this));
343   }
344
345   protected:
346   const BitmapSizeTable &choose_strike (hb_font_t *font) const
347   {
348     unsigned count = sizeTables.len;
349     if (unlikely (!count))
350       return Null(BitmapSizeTable);
351
352     unsigned int requested_ppem = MAX (font->x_ppem, font->y_ppem);
353     if (!requested_ppem)
354       requested_ppem = 1<<30; /* Choose largest strike. */
355     unsigned int best_i = 0;
356     unsigned int best_ppem = MAX (sizeTables[0].ppemX, sizeTables[0].ppemY);
357
358     for (unsigned int i = 1; i < count; i++)
359     {
360       unsigned int ppem = MAX (sizeTables[i].ppemX, sizeTables[i].ppemY);
361       if ((requested_ppem <= ppem && ppem < best_ppem) ||
362           (requested_ppem > best_ppem && ppem > best_ppem))
363       {
364         best_i = i;
365         best_ppem = ppem;
366       }
367     }
368
369     return sizeTables[best_i];
370   }
371
372   protected:
373   FixedVersion<>                version;
374   LArrayOf<BitmapSizeTable>     sizeTables;
375   public:
376   DEFINE_SIZE_ARRAY(8, sizeTables);
377 };
378
379 struct CBDT
380 {
381   static constexpr hb_tag_t tableTag = HB_OT_TAG_CBDT;
382
383   struct accelerator_t
384   {
385     void init (hb_face_t *face)
386     {
387       cblc = hb_sanitize_context_t().reference_table<CBLC> (face);
388       cbdt = hb_sanitize_context_t().reference_table<CBDT> (face);
389
390       upem = hb_face_get_upem (face);
391     }
392
393     void fini ()
394     {
395       this->cblc.destroy ();
396       this->cbdt.destroy ();
397     }
398
399     bool get_extents (hb_font_t *font, hb_codepoint_t glyph,
400                       hb_glyph_extents_t *extents) const
401     {
402       const void *base;
403       const BitmapSizeTable &strike = this->cblc->choose_strike (font);
404       const IndexSubtableRecord *subtable_record = strike.find_table (glyph, cblc, &base);
405       if (!subtable_record || !strike.ppemX || !strike.ppemY)
406         return false;
407
408       if (subtable_record->get_extents (extents, base))
409         return true;
410
411       unsigned int image_offset = 0, image_length = 0, image_format = 0;
412       if (!subtable_record->get_image_data (glyph, base, &image_offset, &image_length, &image_format))
413         return false;
414
415       {
416         unsigned int cbdt_len = cbdt.get_length ();
417         if (unlikely (image_offset > cbdt_len || cbdt_len - image_offset < image_length))
418           return false;
419
420         switch (image_format)
421         {
422           case 17: {
423             if (unlikely (image_length < GlyphBitmapDataFormat17::min_size))
424               return false;
425             const GlyphBitmapDataFormat17& glyphFormat17 =
426                 StructAtOffset<GlyphBitmapDataFormat17> (this->cbdt, image_offset);
427             glyphFormat17.glyphMetrics.get_extents (extents);
428             break;
429           }
430           case 18: {
431             if (unlikely (image_length < GlyphBitmapDataFormat18::min_size))
432               return false;
433             const GlyphBitmapDataFormat18& glyphFormat18 =
434                 StructAtOffset<GlyphBitmapDataFormat18> (this->cbdt, image_offset);
435             glyphFormat18.glyphMetrics.get_extents (extents);
436             break;
437           }
438           default:
439             // TODO: Support other image formats.
440             return false;
441         }
442       }
443
444       /* Convert to font units. */
445       double x_scale = upem / (double) strike.ppemX;
446       double y_scale = upem / (double) strike.ppemY;
447       extents->x_bearing = round (extents->x_bearing * x_scale);
448       extents->y_bearing = round (extents->y_bearing * y_scale);
449       extents->width = round (extents->width * x_scale);
450       extents->height = round (extents->height * y_scale);
451
452       return true;
453     }
454
455     hb_blob_t* reference_png (hb_font_t      *font,
456                                      hb_codepoint_t  glyph) const
457     {
458       const void *base;
459       const BitmapSizeTable &strike = this->cblc->choose_strike (font);
460       const IndexSubtableRecord *subtable_record = strike.find_table (glyph, cblc, &base);
461       if (!subtable_record || !strike.ppemX || !strike.ppemY)
462         return hb_blob_get_empty ();
463
464       unsigned int image_offset = 0, image_length = 0, image_format = 0;
465       if (!subtable_record->get_image_data (glyph, base, &image_offset, &image_length, &image_format))
466         return hb_blob_get_empty ();
467
468       {
469         unsigned int cbdt_len = cbdt.get_length ();
470         if (unlikely (image_offset > cbdt_len || cbdt_len - image_offset < image_length))
471           return hb_blob_get_empty ();
472
473         switch (image_format)
474         {
475           case 17: {
476             if (unlikely (image_length < GlyphBitmapDataFormat17::min_size))
477               return hb_blob_get_empty ();
478             const GlyphBitmapDataFormat17& glyphFormat17 =
479               StructAtOffset<GlyphBitmapDataFormat17> (this->cbdt, image_offset);
480             return hb_blob_create_sub_blob (cbdt.get_blob (),
481                                             image_offset + GlyphBitmapDataFormat17::min_size,
482                                             glyphFormat17.data.len);
483           }
484           case 18: {
485             if (unlikely (image_length < GlyphBitmapDataFormat18::min_size))
486               return hb_blob_get_empty ();
487             const GlyphBitmapDataFormat18& glyphFormat18 =
488               StructAtOffset<GlyphBitmapDataFormat18> (this->cbdt, image_offset);
489             return hb_blob_create_sub_blob (cbdt.get_blob (),
490                                             image_offset + GlyphBitmapDataFormat18::min_size,
491                                             glyphFormat18.data.len);
492           }
493           case 19: {
494             if (unlikely (image_length < GlyphBitmapDataFormat19::min_size))
495               return hb_blob_get_empty ();
496             const GlyphBitmapDataFormat19& glyphFormat19 =
497               StructAtOffset<GlyphBitmapDataFormat19> (this->cbdt, image_offset);
498             return hb_blob_create_sub_blob (cbdt.get_blob (),
499                                             image_offset + GlyphBitmapDataFormat19::min_size,
500                                             glyphFormat19.data.len);
501           }
502         }
503       }
504
505       return hb_blob_get_empty ();
506     }
507
508     bool has_data () const { return cbdt.get_length (); }
509
510     private:
511     hb_blob_ptr_t<CBLC> cblc;
512     hb_blob_ptr_t<CBDT> cbdt;
513
514     unsigned int upem;
515   };
516
517   bool sanitize (hb_sanitize_context_t *c) const
518   {
519     TRACE_SANITIZE (this);
520     return_trace (c->check_struct (this) &&
521                   likely (version.major == 2 || version.major == 3));
522   }
523
524   protected:
525   FixedVersion<>                version;
526   UnsizedArrayOf<HBUINT8>       dataZ;
527   public:
528   DEFINE_SIZE_ARRAY(4, dataZ);
529 };
530
531 struct CBDT_accelerator_t : CBDT::accelerator_t {};
532
533 } /* namespace OT */
534
535 #endif /* HB_OT_COLOR_CBDT_TABLE_HH */