89c867dfa52ba1ab088a0a90d69a80dd550031e7
[platform/upstream/harfbuzz.git] / src / hb-ot-glyf-table.hh
1 /*
2  * Copyright © 2015  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): Behdad Esfahbod
25  */
26
27 #ifndef HB_OT_GLYF_TABLE_HH
28 #define HB_OT_GLYF_TABLE_HH
29
30 #include "hb-open-type-private.hh"
31 #include "hb-ot-head-table.hh"
32 #include "hb-subset-glyf.hh"
33 #include "hb-subset-plan.hh"
34 #include "hb-subset-private.hh"
35
36 namespace OT {
37
38
39 /*
40  * loca -- Index to Location
41  * https://docs.microsoft.com/en-us/typography/opentype/spec/loca
42  */
43 #define HB_OT_TAG_loca HB_TAG('l','o','c','a')
44
45
46 struct loca
47 {
48   friend struct glyf;
49
50   static const hb_tag_t tableTag = HB_OT_TAG_loca;
51
52   inline bool sanitize (hb_sanitize_context_t *c) const
53   {
54     TRACE_SANITIZE (this);
55     return_trace (true);
56   }
57
58   protected:
59   HBUINT8               dataZ[VAR];             /* Location data. */
60   DEFINE_SIZE_ARRAY (0, dataZ);
61 };
62
63
64 /*
65  * glyf -- TrueType Glyph Data
66  * https://docs.microsoft.com/en-us/typography/opentype/spec/glyf
67  */
68 #define HB_OT_TAG_glyf HB_TAG('g','l','y','f')
69
70
71 struct glyf
72 {
73   static const hb_tag_t tableTag = HB_OT_TAG_glyf;
74
75   inline bool sanitize (hb_sanitize_context_t *c) const
76   {
77     TRACE_SANITIZE (this);
78     /* We don't check for anything specific here.  The users of the
79      * struct do all the hard work... */
80     return_trace (true);
81   }
82
83   inline bool subset (hb_subset_plan_t *plan) const
84   {
85     hb_blob_t *glyf_prime = nullptr;
86     hb_blob_t *loca_prime = nullptr;
87
88     bool success = true;
89     bool use_short_loca = false;
90     if (hb_subset_glyf_and_loca (plan, &use_short_loca, &glyf_prime, &loca_prime)) {
91       success = success && plan->add_table (HB_OT_TAG_glyf, glyf_prime);
92       success = success && plan->add_table (HB_OT_TAG_loca, loca_prime);
93       success = success && _add_head_and_set_loca_version (plan, use_short_loca);
94     } else {
95       success = false;
96     }
97     hb_blob_destroy (loca_prime);
98     hb_blob_destroy (glyf_prime);
99
100     return success;
101   }
102
103   static bool
104   _add_head_and_set_loca_version (hb_subset_plan_t *plan, bool use_short_loca)
105   {
106     hb_blob_t *head_blob = OT::Sanitizer<OT::head>().sanitize (hb_face_reference_table (plan->source, HB_OT_TAG_head));
107     hb_blob_t *head_prime_blob = hb_blob_copy_writable_or_fail (head_blob);
108     hb_blob_destroy (head_blob);
109
110     if (unlikely (!head_prime_blob))
111       return false;
112
113     OT::head *head_prime = (OT::head *) hb_blob_get_data_writable (head_prime_blob, nullptr);
114     head_prime->indexToLocFormat.set (use_short_loca ? 0 : 1);
115     bool success = plan->add_table (HB_OT_TAG_head, head_prime_blob);
116
117     hb_blob_destroy (head_prime_blob);
118     return success;
119   }
120
121   struct GlyphHeader
122   {
123     HBINT16             numberOfContours;       /* If the number of contours is
124                                                  * greater than or equal to zero,
125                                                  * this is a simple glyph; if negative,
126                                                  * this is a composite glyph. */
127     FWORD               xMin;                   /* Minimum x for coordinate data. */
128     FWORD               yMin;                   /* Minimum y for coordinate data. */
129     FWORD               xMax;                   /* Maximum x for coordinate data. */
130     FWORD               yMax;                   /* Maximum y for coordinate data. */
131
132     DEFINE_SIZE_STATIC (10);
133   };
134
135   struct CompositeGlyphHeader
136   {
137     enum composite_glyph_flag_t {
138       ARG_1_AND_2_ARE_WORDS =      0x0001,
139       ARGS_ARE_XY_VALUES =         0x0002,
140       ROUND_XY_TO_GRID =           0x0004,
141       WE_HAVE_A_SCALE =            0x0008,
142       MORE_COMPONENTS =            0x0020,
143       WE_HAVE_AN_X_AND_Y_SCALE =   0x0040,
144       WE_HAVE_A_TWO_BY_TWO =       0x0080,
145       WE_HAVE_INSTRUCTIONS =       0x0100,
146       USE_MY_METRICS =             0x0200,
147       OVERLAP_COMPOUND =           0x0400,
148       SCALED_COMPONENT_OFFSET =    0x0800,
149       UNSCALED_COMPONENT_OFFSET =  0x1000
150     };
151
152     HBUINT16 flags;
153     HBUINT16 glyphIndex;
154
155     inline unsigned int get_size (void) const
156     {
157       unsigned int size = min_size;
158       if (flags & ARG_1_AND_2_ARE_WORDS) {
159         // arg1 and 2 are int16
160         size += 4;
161       } else {
162         // arg1 and 2 are int8
163         size += 2;
164       }
165       if (flags & WE_HAVE_A_SCALE) {
166         // One x 16 bit (scale)
167         size += 2;
168       } else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) {
169         // Two x 16 bit (xscale, yscale)
170         size += 4;
171       } else if (flags & WE_HAVE_A_TWO_BY_TWO) {
172         // Four x 16 bit (xscale, scale01, scale10, yscale)
173         size += 8;
174       }
175       return size;
176     }
177
178     struct Iterator
179     {
180       const char *glyph_start;
181       const char *glyph_end;
182       const CompositeGlyphHeader *current;
183
184       inline bool move_to_next ()
185       {
186         if (current->flags & CompositeGlyphHeader::MORE_COMPONENTS)
187         {
188           const CompositeGlyphHeader *possible =
189             &StructAfter<CompositeGlyphHeader, CompositeGlyphHeader> (*current);
190           if (!in_range (possible))
191             return false;
192           current = possible;
193           return true;
194         }
195         return false;
196       }
197
198       inline bool in_range (const CompositeGlyphHeader *composite) const
199       {
200         return (const char *) composite >= glyph_start
201           && ((const char *) composite + CompositeGlyphHeader::min_size) <= glyph_end
202           && ((const char *) composite + composite->get_size()) <= glyph_end;
203       }
204     };
205
206     static inline bool get_iterator (const char * glyph_data,
207                                      unsigned int length,
208                                      CompositeGlyphHeader::Iterator *iterator /* OUT */)
209     {
210       if (length < GlyphHeader::static_size)
211         return false; /* Empty glyph; zero extents. */
212
213       const GlyphHeader &glyph_header = StructAtOffset<GlyphHeader> (glyph_data, 0);
214       if (glyph_header.numberOfContours < 0)
215       {
216         const CompositeGlyphHeader *possible =
217           &StructAfter<CompositeGlyphHeader, GlyphHeader> (glyph_header);
218
219         iterator->glyph_start = glyph_data;
220         iterator->glyph_end = (const char *) glyph_data + length;
221         if (!iterator->in_range (possible))
222           return false;
223         iterator->current = possible;
224         return true;
225       }
226
227       return false;
228     }
229
230     DEFINE_SIZE_MIN (4);
231   };
232
233   struct accelerator_t
234   {
235     inline void init (hb_face_t *face)
236     {
237       memset (this, 0, sizeof (accelerator_t));
238
239       hb_blob_t *head_blob = Sanitizer<head>().sanitize (face->reference_table (HB_OT_TAG_head));
240       const head *head_table = head_blob->as<head> ();
241       if (head_table == &Null(head) || (unsigned int) head_table->indexToLocFormat > 1 || head_table->glyphDataFormat != 0)
242       {
243         /* head table is not present, or in an unknown format.  Leave num_glyphs=0, that takes care of disabling us. */
244         hb_blob_destroy (head_blob);
245         return;
246       }
247       short_offset = 0 == head_table->indexToLocFormat;
248       hb_blob_destroy (head_blob);
249
250       loca_blob = Sanitizer<loca>().sanitize (face->reference_table (HB_OT_TAG_loca));
251       loca_table = loca_blob->as<loca> ();
252       glyf_blob = Sanitizer<glyf>().sanitize (face->reference_table (HB_OT_TAG_glyf));
253       glyf_table = glyf_blob->as<glyf> ();
254
255       num_glyphs = MAX (1u, hb_blob_get_length (loca_blob) / (short_offset ? 2 : 4)) - 1;
256       glyf_len = hb_blob_get_length (glyf_blob);
257     }
258
259     inline void fini (void)
260     {
261       hb_blob_destroy (loca_blob);
262       hb_blob_destroy (glyf_blob);
263     }
264
265     /*
266      * Returns true if the referenced glyph is a valid glyph and a composite glyph.
267      * If true is returned a pointer to the composite glyph will be written into
268      * composite.
269      */
270     inline bool get_composite (hb_codepoint_t glyph,
271                                CompositeGlyphHeader::Iterator *composite /* OUT */) const
272     {
273       if (this->glyf_table == &Null(glyf) || !num_glyphs)
274         return false;
275
276       unsigned int start_offset, end_offset;
277       if (!get_offsets (glyph, &start_offset, &end_offset))
278         return false; /* glyph not found */
279
280       return CompositeGlyphHeader::get_iterator ((const char*) this->glyf_table + start_offset,
281                                                  end_offset - start_offset,
282                                                  composite);
283     }
284
285     enum simple_glyph_flag_t {
286       FLAG_X_SHORT = 0x02,
287       FLAG_Y_SHORT = 0x04,
288       FLAG_REPEAT = 0x08,
289       FLAG_X_SAME = 0x10,
290       FLAG_Y_SAME = 0x20
291     };
292
293     /* based on FontTools _g_l_y_f.py::trim */
294     inline bool remove_padding(unsigned int start_offset,
295                                unsigned int *end_offset) const
296     {
297       if (*end_offset - start_offset < GlyphHeader::static_size)
298         return true;
299
300       const char *glyph = ((const char *) glyf_table) + start_offset;
301       const char * const glyph_end = glyph + (*end_offset - start_offset);
302       const GlyphHeader &glyph_header = StructAtOffset<GlyphHeader> (glyph, 0);
303       int16_t num_contours = (int16_t) glyph_header.numberOfContours;
304
305       if (num_contours < 0)
306         /* Trimming for composites not implemented.
307          * If removing hints it falls out of that. */
308         return true;
309       else if (num_contours > 0)
310       {
311         /* simple glyph w/contours, possibly trimmable */
312         glyph += GlyphHeader::static_size + 2 * num_contours;
313
314         if (unlikely (glyph + 2 >= glyph_end)) return false;
315         uint16_t nCoordinates = (uint16_t) StructAtOffset<HBUINT16>(glyph - 2, 0) + 1;
316         uint16_t nInstructions = (uint16_t) StructAtOffset<HBUINT16>(glyph, 0);
317
318         glyph += 2 + nInstructions;
319         if (unlikely (glyph + 2 >= glyph_end)) return false;
320
321         unsigned int coordBytes = 0;
322         unsigned int coordsWithFlags = 0;
323         while (glyph < glyph_end)
324         {
325           uint8_t flag = (uint8_t) *glyph;
326           glyph++;
327
328           unsigned int repeat = 1;
329           if (flag & FLAG_REPEAT)
330           {
331             if (glyph >= glyph_end)
332             {
333               DEBUG_MSG(SUBSET, nullptr, "Bad flag");
334               return false;
335             }
336             repeat = ((uint8_t) *glyph) + 1;
337             glyph++;
338           }
339
340           unsigned int xBytes, yBytes;
341           xBytes = yBytes = 0;
342           if (flag & FLAG_X_SHORT)
343             xBytes = 1;
344           else if ((flag & FLAG_X_SAME) == 0)
345             xBytes = 2;
346
347           if (flag & FLAG_Y_SHORT)
348             yBytes = 1;
349           else if ((flag & FLAG_Y_SAME) == 0)
350             yBytes = 2;
351
352           coordBytes += (xBytes + yBytes) * repeat;
353           coordsWithFlags += repeat;
354           if (coordsWithFlags >= nCoordinates)
355             break;
356         }
357
358         if (coordsWithFlags != nCoordinates)
359         {
360           DEBUG_MSG(SUBSET, nullptr, "Expect %d coords to have flags, got flags for %d", nCoordinates, coordsWithFlags);
361           return false;
362         }
363         glyph += coordBytes;
364
365         if (glyph < glyph_end)
366           *end_offset -= glyph_end - glyph;
367       }
368       return true;
369     }
370
371     inline bool get_offsets (hb_codepoint_t  glyph,
372                              unsigned int   *start_offset /* OUT */,
373                              unsigned int   *end_offset   /* OUT */) const
374     {
375       if (unlikely (glyph >= num_glyphs))
376         return false;
377
378       if (short_offset)
379       {
380         const HBUINT16 *offsets = (const HBUINT16 *) loca_table->dataZ;
381         *start_offset = 2 * offsets[glyph];
382         *end_offset   = 2 * offsets[glyph + 1];
383       }
384       else
385       {
386         const HBUINT32 *offsets = (const HBUINT32 *) loca_table->dataZ;
387
388         *start_offset = offsets[glyph];
389         *end_offset   = offsets[glyph + 1];
390       }
391
392       if (*start_offset > *end_offset || *end_offset > glyf_len)
393         return false;
394
395       return true;
396     }
397
398     inline bool get_instruction_offsets(unsigned int start_offset,
399                                         unsigned int end_offset,
400                                         unsigned int *instruction_start /* OUT */,
401                                         unsigned int *instruction_end /* OUT */) const
402     {
403       if (end_offset - start_offset < GlyphHeader::static_size)
404       {
405         *instruction_start = 0;
406         *instruction_end = 0;
407         return true; /* Empty glyph; no instructions. */
408       }
409       const GlyphHeader &glyph_header = StructAtOffset<GlyphHeader> (glyf_table, start_offset);
410       int16_t num_contours = (int16_t) glyph_header.numberOfContours;
411       if (num_contours < 0)
412       {
413         CompositeGlyphHeader::Iterator composite_it;
414         if (unlikely (!CompositeGlyphHeader::get_iterator (
415             (const char*) this->glyf_table + start_offset,
416              end_offset - start_offset, &composite_it))) return false;
417         const CompositeGlyphHeader *last;
418         do {
419           last = composite_it.current;
420         } while (composite_it.move_to_next());
421
422         if ( (uint16_t) last->flags & CompositeGlyphHeader::WE_HAVE_INSTRUCTIONS)
423           *instruction_start = ((char *) last - (char *) glyf_table->dataZ) + last->get_size();
424         else
425           *instruction_start = end_offset;
426         *instruction_end = end_offset;
427         if (unlikely (*instruction_start > *instruction_end))
428         {
429           DEBUG_MSG(SUBSET, nullptr, "Invalid instruction offset, %d is outside [%d, %d]", *instruction_start, start_offset, end_offset);
430           return false;
431         }
432       }
433       else
434       {
435         unsigned int instruction_length_offset = start_offset + GlyphHeader::static_size + 2 * num_contours;
436         if (unlikely (instruction_length_offset + 2 > end_offset))
437         {
438           DEBUG_MSG(SUBSET, nullptr, "Glyph size is too short, missing field instructionLength.");
439           return false;
440         }
441
442         const HBUINT16 &instruction_length = StructAtOffset<HBUINT16> (glyf_table, instruction_length_offset);
443         unsigned int start = instruction_length_offset + 2;
444         unsigned int end = start + (uint16_t) instruction_length;
445         if (unlikely (end > end_offset)) // Out of bounds of the current glyph
446         {
447           DEBUG_MSG(SUBSET, nullptr, "The instructions array overruns the glyph's boundaries.");
448           return false;
449         }
450
451         *instruction_start = start;
452         *instruction_end = end;
453       }
454       return true;
455     }
456
457     inline bool get_extents (hb_codepoint_t glyph,
458                              hb_glyph_extents_t *extents) const
459     {
460       unsigned int start_offset, end_offset;
461       if (!get_offsets (glyph, &start_offset, &end_offset))
462         return false;
463
464       if (end_offset - start_offset < GlyphHeader::static_size)
465         return true; /* Empty glyph; zero extents. */
466
467       const GlyphHeader &glyph_header = StructAtOffset<GlyphHeader> (glyf_table, start_offset);
468
469       extents->x_bearing = MIN (glyph_header.xMin, glyph_header.xMax);
470       extents->y_bearing = MAX (glyph_header.yMin, glyph_header.yMax);
471       extents->width     = MAX (glyph_header.xMin, glyph_header.xMax) - extents->x_bearing;
472       extents->height    = MIN (glyph_header.yMin, glyph_header.yMax) - extents->y_bearing;
473
474       return true;
475     }
476
477     private:
478     bool short_offset;
479     unsigned int num_glyphs;
480     const loca *loca_table;
481     const glyf *glyf_table;
482     hb_blob_t *loca_blob;
483     hb_blob_t *glyf_blob;
484     unsigned int glyf_len;
485   };
486
487   protected:
488   HBUINT8               dataZ[VAR];             /* Glyphs data. */
489
490   DEFINE_SIZE_ARRAY (0, dataZ);
491 };
492
493 } /* namespace OT */
494
495
496 #endif /* HB_OT_GLYF_TABLE_HH */