• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #ifndef OT_GLYF_SIMPLEGLYPH_HH
2 #define OT_GLYF_SIMPLEGLYPH_HH
3 
4 
5 #include "../../hb-open-type.hh"
6 
7 
8 namespace OT {
9 namespace glyf_impl {
10 
11 
12 struct SimpleGlyph
13 {
14   enum simple_glyph_flag_t
15   {
16     FLAG_ON_CURVE       = 0x01,
17     FLAG_X_SHORT        = 0x02,
18     FLAG_Y_SHORT        = 0x04,
19     FLAG_REPEAT         = 0x08,
20     FLAG_X_SAME         = 0x10,
21     FLAG_Y_SAME         = 0x20,
22     FLAG_OVERLAP_SIMPLE = 0x40,
23     FLAG_RESERVED2      = 0x80
24   };
25 
26   const GlyphHeader &header;
27   hb_bytes_t bytes;
SimpleGlyphOT::glyf_impl::SimpleGlyph28   SimpleGlyph (const GlyphHeader &header_, hb_bytes_t bytes_) :
29     header (header_), bytes (bytes_) {}
30 
instruction_len_offsetOT::glyf_impl::SimpleGlyph31   unsigned int instruction_len_offset () const
32   { return GlyphHeader::static_size + 2 * header.numberOfContours; }
33 
lengthOT::glyf_impl::SimpleGlyph34   unsigned int length (unsigned int instruction_len) const
35   { return instruction_len_offset () + 2 + instruction_len; }
36 
instructions_lengthOT::glyf_impl::SimpleGlyph37   unsigned int instructions_length () const
38   {
39     unsigned int instruction_length_offset = instruction_len_offset ();
40     if (unlikely (instruction_length_offset + 2 > bytes.length)) return 0;
41 
42     const HBUINT16 &instructionLength = StructAtOffset<HBUINT16> (&bytes, instruction_length_offset);
43     /* Out of bounds of the current glyph */
44     if (unlikely (length (instructionLength) > bytes.length)) return 0;
45     return instructionLength;
46   }
47 
trim_paddingOT::glyf_impl::SimpleGlyph48   const hb_bytes_t trim_padding () const
49   {
50     /* based on FontTools _g_l_y_f.py::trim */
51     const uint8_t *glyph = (uint8_t*) bytes.arrayZ;
52     const uint8_t *glyph_end = glyph + bytes.length;
53     /* simple glyph w/contours, possibly trimmable */
54     glyph += instruction_len_offset ();
55 
56     if (unlikely (glyph + 2 >= glyph_end)) return hb_bytes_t ();
57     unsigned int num_coordinates = StructAtOffset<HBUINT16> (glyph - 2, 0) + 1;
58     unsigned int num_instructions = StructAtOffset<HBUINT16> (glyph, 0);
59 
60     glyph += 2 + num_instructions;
61 
62     unsigned int coord_bytes = 0;
63     unsigned int coords_with_flags = 0;
64     while (glyph < glyph_end)
65     {
66       uint8_t flag = *glyph;
67       glyph++;
68 
69       unsigned int repeat = 1;
70       if (flag & FLAG_REPEAT)
71       {
72 	if (unlikely (glyph >= glyph_end)) return hb_bytes_t ();
73 	repeat = *glyph + 1;
74 	glyph++;
75       }
76 
77       unsigned int xBytes, yBytes;
78       xBytes = yBytes = 0;
79       if (flag & FLAG_X_SHORT) xBytes = 1;
80       else if ((flag & FLAG_X_SAME) == 0) xBytes = 2;
81 
82       if (flag & FLAG_Y_SHORT) yBytes = 1;
83       else if ((flag & FLAG_Y_SAME) == 0) yBytes = 2;
84 
85       coord_bytes += (xBytes + yBytes) * repeat;
86       coords_with_flags += repeat;
87       if (coords_with_flags >= num_coordinates) break;
88     }
89 
90     if (unlikely (coords_with_flags != num_coordinates)) return hb_bytes_t ();
91     return bytes.sub_array (0, bytes.length + coord_bytes - (glyph_end - glyph));
92   }
93 
94   /* zero instruction length */
drop_hintsOT::glyf_impl::SimpleGlyph95   void drop_hints ()
96   {
97     GlyphHeader &glyph_header = const_cast<GlyphHeader &> (header);
98     (HBUINT16 &) StructAtOffset<HBUINT16> (&glyph_header, instruction_len_offset ()) = 0;
99   }
100 
drop_hints_bytesOT::glyf_impl::SimpleGlyph101   void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const
102   {
103     unsigned int instructions_len = instructions_length ();
104     unsigned int glyph_length = length (instructions_len);
105     dest_start = bytes.sub_array (0, glyph_length - instructions_len);
106     dest_end = bytes.sub_array (glyph_length, bytes.length - glyph_length);
107   }
108 
set_overlaps_flagOT::glyf_impl::SimpleGlyph109   void set_overlaps_flag ()
110   {
111     if (unlikely (!header.numberOfContours)) return;
112 
113     unsigned flags_offset = length (instructions_length ());
114     if (unlikely (flags_offset + 1 > bytes.length)) return;
115 
116     HBUINT8 &first_flag = (HBUINT8 &) StructAtOffset<HBUINT16> (&bytes, flags_offset);
117     first_flag = (uint8_t) first_flag | FLAG_OVERLAP_SIMPLE;
118   }
119 
read_flagsOT::glyf_impl::SimpleGlyph120   static bool read_flags (const HBUINT8 *&p /* IN/OUT */,
121 			  contour_point_vector_t &points_ /* IN/OUT */,
122 			  const HBUINT8 *end)
123   {
124     unsigned count = points_.length;
125     for (unsigned int i = 0; i < count;)
126     {
127       if (unlikely (p + 1 > end)) return false;
128       uint8_t flag = *p++;
129       points_.arrayZ[i++].flag = flag;
130       if (flag & FLAG_REPEAT)
131       {
132 	if (unlikely (p + 1 > end)) return false;
133 	unsigned int repeat_count = *p++;
134 	unsigned stop = hb_min (i + repeat_count, count);
135 	for (; i < stop; i++)
136 	  points_.arrayZ[i].flag = flag;
137       }
138     }
139     return true;
140   }
141 
read_pointsOT::glyf_impl::SimpleGlyph142   static bool read_points (const HBUINT8 *&p /* IN/OUT */,
143 			   contour_point_vector_t &points_ /* IN/OUT */,
144 			   const HBUINT8 *end,
145 			   float contour_point_t::*m,
146 			   const simple_glyph_flag_t short_flag,
147 			   const simple_glyph_flag_t same_flag)
148   {
149     int v = 0;
150 
151     unsigned count = points_.length;
152     for (unsigned i = 0; i < count; i++)
153     {
154       unsigned flag = points_[i].flag;
155       if (flag & short_flag)
156       {
157 	if (unlikely (p + 1 > end)) return false;
158 	if (flag & same_flag)
159 	  v += *p++;
160 	else
161 	  v -= *p++;
162       }
163       else
164       {
165 	if (!(flag & same_flag))
166 	{
167 	  if (unlikely (p + HBINT16::static_size > end)) return false;
168 	  v += *(const HBINT16 *) p;
169 	  p += HBINT16::static_size;
170 	}
171       }
172       points_.arrayZ[i].*m = v;
173     }
174     return true;
175   }
176 
get_contour_pointsOT::glyf_impl::SimpleGlyph177   bool get_contour_points (contour_point_vector_t &points_ /* OUT */,
178 			   bool phantom_only = false) const
179   {
180     const HBUINT16 *endPtsOfContours = &StructAfter<HBUINT16> (header);
181     int num_contours = header.numberOfContours;
182     assert (num_contours);
183     /* One extra item at the end, for the instruction-count below. */
184     if (unlikely (!bytes.check_range (&endPtsOfContours[num_contours]))) return false;
185     unsigned int num_points = endPtsOfContours[num_contours - 1] + 1;
186 
187     points_.alloc (num_points + 4); // Allocate for phantom points, to avoid a possible copy
188     if (!points_.resize (num_points)) return false;
189     if (phantom_only) return true;
190 
191     for (int i = 0; i < num_contours; i++)
192       points_[endPtsOfContours[i]].is_end_point = true;
193 
194     /* Skip instructions */
195     const HBUINT8 *p = &StructAtOffset<HBUINT8> (&endPtsOfContours[num_contours + 1],
196 						 endPtsOfContours[num_contours]);
197 
198     if (unlikely ((const char *) p < bytes.arrayZ)) return false; /* Unlikely overflow */
199     const HBUINT8 *end = (const HBUINT8 *) (bytes.arrayZ + bytes.length);
200     if (unlikely (p >= end)) return false;
201 
202     /* Read x & y coordinates */
203     return read_flags (p, points_, end)
204         && read_points (p, points_, end, &contour_point_t::x,
205 			FLAG_X_SHORT, FLAG_X_SAME)
206 	&& read_points (p, points_, end, &contour_point_t::y,
207 			FLAG_Y_SHORT, FLAG_Y_SAME);
208   }
209 
encode_coordOT::glyf_impl::SimpleGlyph210   static void encode_coord (int value,
211                             uint8_t &flag,
212                             const simple_glyph_flag_t short_flag,
213                             const simple_glyph_flag_t same_flag,
214                             hb_vector_t<uint8_t> &coords /* OUT */)
215   {
216     if (value == 0)
217     {
218       flag |= same_flag;
219     }
220     else if (value >= -255 && value <= 255)
221     {
222       flag |= short_flag;
223       if (value > 0) flag |= same_flag;
224       else value = -value;
225 
226       coords.arrayZ[coords.length++] = (uint8_t) value;
227     }
228     else
229     {
230       int16_t val = value;
231       coords.arrayZ[coords.length++] = val >> 8;
232       coords.arrayZ[coords.length++] = val & 0xff;
233     }
234   }
235 
encode_flagOT::glyf_impl::SimpleGlyph236   static void encode_flag (uint8_t &flag,
237                            uint8_t &repeat,
238                            uint8_t lastflag,
239                            hb_vector_t<uint8_t> &flags /* OUT */)
240   {
241     if (flag == lastflag && repeat != 255)
242     {
243       repeat++;
244       if (repeat == 1)
245       {
246         /* We know there's room. */
247         flags.arrayZ[flags.length++] = flag;
248       }
249       else
250       {
251         unsigned len = flags.length;
252         flags.arrayZ[len-2] = flag | FLAG_REPEAT;
253         flags.arrayZ[len-1] = repeat;
254       }
255     }
256     else
257     {
258       repeat = 0;
259       flags.push (flag);
260     }
261   }
262 
compile_bytes_with_deltasOT::glyf_impl::SimpleGlyph263   bool compile_bytes_with_deltas (const contour_point_vector_t &all_points,
264                                   bool no_hinting,
265                                   hb_bytes_t &dest_bytes /* OUT */)
266   {
267     if (header.numberOfContours == 0 || all_points.length <= 4)
268     {
269       dest_bytes = hb_bytes_t ();
270       return true;
271     }
272     unsigned num_points = all_points.length - 4;
273 
274     hb_vector_t<uint8_t> flags, x_coords, y_coords;
275     if (unlikely (!flags.alloc (num_points))) return false;
276     if (unlikely (!x_coords.alloc (2*num_points))) return false;
277     if (unlikely (!y_coords.alloc (2*num_points))) return false;
278 
279     uint8_t lastflag = 255, repeat = 0;
280     int prev_x = 0, prev_y = 0;
281 
282     for (unsigned i = 0; i < num_points; i++)
283     {
284       uint8_t flag = all_points.arrayZ[i].flag;
285       flag &= FLAG_ON_CURVE + FLAG_OVERLAP_SIMPLE;
286 
287       int cur_x = roundf (all_points.arrayZ[i].x);
288       int cur_y = roundf (all_points.arrayZ[i].y);
289       encode_coord (cur_x - prev_x, flag, FLAG_X_SHORT, FLAG_X_SAME, x_coords);
290       encode_coord (cur_y - prev_y, flag, FLAG_Y_SHORT, FLAG_Y_SAME, y_coords);
291       encode_flag (flag, repeat, lastflag, flags);
292 
293       prev_x = cur_x;
294       prev_y = cur_y;
295       lastflag = flag;
296     }
297 
298     unsigned len_before_instrs = 2 * header.numberOfContours + 2;
299     unsigned len_instrs = instructions_length ();
300     unsigned total_len = len_before_instrs + flags.length + x_coords.length + y_coords.length;
301 
302     if (!no_hinting)
303       total_len += len_instrs;
304 
305     char *p = (char *) hb_malloc (total_len);
306     if (unlikely (!p)) return false;
307 
308     const char *src = bytes.arrayZ + GlyphHeader::static_size;
309     char *cur = p;
310     hb_memcpy (p, src, len_before_instrs);
311 
312     cur += len_before_instrs;
313     src += len_before_instrs;
314 
315     if (!no_hinting)
316     {
317       hb_memcpy (cur, src, len_instrs);
318       cur += len_instrs;
319     }
320 
321     hb_memcpy (cur, flags.arrayZ, flags.length);
322     cur += flags.length;
323 
324     hb_memcpy (cur, x_coords.arrayZ, x_coords.length);
325     cur += x_coords.length;
326 
327     hb_memcpy (cur, y_coords.arrayZ, y_coords.length);
328 
329     dest_bytes = hb_bytes_t (p, total_len);
330     return true;
331   }
332 };
333 
334 
335 } /* namespace glyf_impl */
336 } /* namespace OT */
337 
338 
339 #endif /* OT_GLYF_SIMPLEGLYPH_HH */
340