xref: /aosp_15_r20/external/harfbuzz_ng/src/OT/glyf/CompositeGlyph.hh (revision 2d1272b857b1f7575e6e246373e1cb218663db8a)
1 #ifndef OT_GLYF_COMPOSITEGLYPH_HH
2 #define OT_GLYF_COMPOSITEGLYPH_HH
3 
4 
5 #include "../../hb-open-type.hh"
6 #include "composite-iter.hh"
7 
8 
9 namespace OT {
10 namespace glyf_impl {
11 
12 
13 struct CompositeGlyphRecord
14 {
15   protected:
16   enum composite_glyph_flag_t
17   {
18     ARG_1_AND_2_ARE_WORDS	= 0x0001,
19     ARGS_ARE_XY_VALUES		= 0x0002,
20     ROUND_XY_TO_GRID		= 0x0004,
21     WE_HAVE_A_SCALE		= 0x0008,
22     MORE_COMPONENTS		= 0x0020,
23     WE_HAVE_AN_X_AND_Y_SCALE	= 0x0040,
24     WE_HAVE_A_TWO_BY_TWO	= 0x0080,
25     WE_HAVE_INSTRUCTIONS	= 0x0100,
26     USE_MY_METRICS		= 0x0200,
27     OVERLAP_COMPOUND		= 0x0400,
28     SCALED_COMPONENT_OFFSET	= 0x0800,
29     UNSCALED_COMPONENT_OFFSET	= 0x1000,
30 #ifndef HB_NO_BEYOND_64K
31     GID_IS_24BIT		= 0x2000
32 #endif
33   };
34 
35   public:
get_sizeOT::glyf_impl::CompositeGlyphRecord36   unsigned int get_size () const
37   {
38     unsigned int size = min_size;
39     /* glyphIndex is 24bit instead of 16bit */
40 #ifndef HB_NO_BEYOND_64K
41     if (flags & GID_IS_24BIT) size += HBGlyphID24::static_size - HBGlyphID16::static_size;
42 #endif
43     /* arg1 and 2 are int16 */
44     if (flags & ARG_1_AND_2_ARE_WORDS) size += 4;
45     /* arg1 and 2 are int8 */
46     else size += 2;
47 
48     /* One x 16 bit (scale) */
49     if (flags & WE_HAVE_A_SCALE) size += 2;
50     /* Two x 16 bit (xscale, yscale) */
51     else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) size += 4;
52     /* Four x 16 bit (xscale, scale01, scale10, yscale) */
53     else if (flags & WE_HAVE_A_TWO_BY_TWO) size += 8;
54 
55     return size;
56   }
57 
drop_instructions_flagOT::glyf_impl::CompositeGlyphRecord58   void drop_instructions_flag ()  { flags = (uint16_t) flags & ~WE_HAVE_INSTRUCTIONS; }
set_overlaps_flagOT::glyf_impl::CompositeGlyphRecord59   void set_overlaps_flag ()
60   {
61     flags = (uint16_t) flags | OVERLAP_COMPOUND;
62   }
63 
has_instructionsOT::glyf_impl::CompositeGlyphRecord64   bool has_instructions ()  const { return   flags & WE_HAVE_INSTRUCTIONS; }
65 
has_moreOT::glyf_impl::CompositeGlyphRecord66   bool has_more ()          const { return   flags & MORE_COMPONENTS; }
is_use_my_metricsOT::glyf_impl::CompositeGlyphRecord67   bool is_use_my_metrics () const { return   flags & USE_MY_METRICS; }
is_anchoredOT::glyf_impl::CompositeGlyphRecord68   bool is_anchored ()       const { return !(flags & ARGS_ARE_XY_VALUES); }
get_anchor_pointsOT::glyf_impl::CompositeGlyphRecord69   void get_anchor_points (unsigned int &point1, unsigned int &point2) const
70   {
71     const auto *p = &StructAfter<const HBUINT8> (flags);
72 #ifndef HB_NO_BEYOND_64K
73     if (flags & GID_IS_24BIT)
74       p += HBGlyphID24::static_size;
75     else
76 #endif
77       p += HBGlyphID16::static_size;
78     if (flags & ARG_1_AND_2_ARE_WORDS)
79     {
80       point1 = ((const HBUINT16 *) p)[0];
81       point2 = ((const HBUINT16 *) p)[1];
82     }
83     else
84     {
85       point1 = p[0];
86       point2 = p[1];
87     }
88   }
89 
transformOT::glyf_impl::CompositeGlyphRecord90   static void transform (const float (&matrix)[4],
91 			 hb_array_t<contour_point_t> points)
92   {
93     if (matrix[0] != 1.f || matrix[1] != 0.f ||
94 	matrix[2] != 0.f || matrix[3] != 1.f)
95       for (auto &point : points)
96         point.transform (matrix);
97   }
98 
translateOT::glyf_impl::CompositeGlyphRecord99   static void translate (const contour_point_t &trans,
100 			 hb_array_t<contour_point_t> points)
101   {
102     if (HB_OPTIMIZE_SIZE_VAL)
103     {
104       if (trans.x != 0.f || trans.y != 0.f)
105         for (auto &point : points)
106 	  point.translate (trans);
107     }
108     else
109     {
110       if (trans.x != 0.f && trans.y != 0.f)
111         for (auto &point : points)
112 	  point.translate (trans);
113       else
114       {
115 	if (trans.x != 0.f)
116 	  for (auto &point : points)
117 	    point.x += trans.x;
118 	else if (trans.y != 0.f)
119 	  for (auto &point : points)
120 	    point.y += trans.y;
121       }
122     }
123   }
124 
transform_pointsOT::glyf_impl::CompositeGlyphRecord125   void transform_points (hb_array_t<contour_point_t> points,
126 			 const float (&matrix)[4],
127 			 const contour_point_t &trans) const
128   {
129     if (scaled_offsets ())
130     {
131       translate (trans, points);
132       transform (matrix, points);
133     }
134     else
135     {
136       transform (matrix, points);
137       translate (trans, points);
138     }
139   }
140 
get_pointsOT::glyf_impl::CompositeGlyphRecord141   bool get_points (contour_point_vector_t &points) const
142   {
143     float matrix[4];
144     contour_point_t trans;
145     get_transformation (matrix, trans);
146     if (unlikely (!points.alloc (points.length + 4))) return false; // For phantom points
147     points.push (trans);
148     return true;
149   }
150 
compile_with_pointOT::glyf_impl::CompositeGlyphRecord151   unsigned compile_with_point (const contour_point_t &point,
152                                char *out) const
153   {
154     const HBINT8 *p = &StructAfter<const HBINT8> (flags);
155 #ifndef HB_NO_BEYOND_64K
156     if (flags & GID_IS_24BIT)
157       p += HBGlyphID24::static_size;
158     else
159 #endif
160       p += HBGlyphID16::static_size;
161 
162     unsigned len = get_size ();
163     unsigned len_before_val = (const char *)p - (const char *)this;
164     if (flags & ARG_1_AND_2_ARE_WORDS)
165     {
166       // no overflow, copy value
167       hb_memcpy (out, this, len);
168 
169       HBINT16 *o = reinterpret_cast<HBINT16 *> (out + len_before_val);
170       o[0] = roundf (point.x);
171       o[1] = roundf (point.y);
172     }
173     else
174     {
175       int new_x = roundf (point.x);
176       int new_y = roundf (point.y);
177       if (new_x <= 127 && new_x >= -128 &&
178           new_y <= 127 && new_y >= -128)
179       {
180         hb_memcpy (out, this, len);
181         HBINT8 *o = reinterpret_cast<HBINT8 *> (out + len_before_val);
182         o[0] = new_x;
183         o[1] = new_y;
184       }
185       else
186       {
187         // new point value has an int8 overflow
188         hb_memcpy (out, this, len_before_val);
189 
190         //update flags
191         CompositeGlyphRecord *o = reinterpret_cast<CompositeGlyphRecord *> (out);
192         o->flags = flags | ARG_1_AND_2_ARE_WORDS;
193         out += len_before_val;
194 
195         HBINT16 new_value;
196         new_value = new_x;
197         hb_memcpy (out, &new_value, HBINT16::static_size);
198         out += HBINT16::static_size;
199 
200         new_value = new_y;
201         hb_memcpy (out, &new_value, HBINT16::static_size);
202         out += HBINT16::static_size;
203 
204         hb_memcpy (out, p+2, len - len_before_val - 2);
205         len += 2;
206       }
207     }
208     return len;
209   }
210 
211   protected:
scaled_offsetsOT::glyf_impl::CompositeGlyphRecord212   bool scaled_offsets () const
213   { return (flags & (SCALED_COMPONENT_OFFSET | UNSCALED_COMPONENT_OFFSET)) == SCALED_COMPONENT_OFFSET; }
214 
215   public:
get_transformationOT::glyf_impl::CompositeGlyphRecord216   bool get_transformation (float (&matrix)[4], contour_point_t &trans) const
217   {
218     matrix[0] = matrix[3] = 1.f;
219     matrix[1] = matrix[2] = 0.f;
220 
221     const auto *p = &StructAfter<const HBINT8> (flags);
222 #ifndef HB_NO_BEYOND_64K
223     if (flags & GID_IS_24BIT)
224       p += HBGlyphID24::static_size;
225     else
226 #endif
227       p += HBGlyphID16::static_size;
228     int tx, ty;
229     if (flags & ARG_1_AND_2_ARE_WORDS)
230     {
231       tx = *(const HBINT16 *) p;
232       p += HBINT16::static_size;
233       ty = *(const HBINT16 *) p;
234       p += HBINT16::static_size;
235     }
236     else
237     {
238       tx = *p++;
239       ty = *p++;
240     }
241     if (is_anchored ()) tx = ty = 0;
242 
243     /* set is_end_point flag to true, used by IUP delta optimization */
244     trans.init ((float) tx, (float) ty, true);
245 
246     {
247       const F2DOT14 *points = (const F2DOT14 *) p;
248       if (flags & WE_HAVE_A_SCALE)
249       {
250 	matrix[0] = matrix[3] = points[0].to_float ();
251 	return true;
252       }
253       else if (flags & WE_HAVE_AN_X_AND_Y_SCALE)
254       {
255 	matrix[0] = points[0].to_float ();
256 	matrix[3] = points[1].to_float ();
257 	return true;
258       }
259       else if (flags & WE_HAVE_A_TWO_BY_TWO)
260       {
261 	matrix[0] = points[0].to_float ();
262 	matrix[1] = points[1].to_float ();
263 	matrix[2] = points[2].to_float ();
264 	matrix[3] = points[3].to_float ();
265 	return true;
266       }
267     }
268     return tx || ty;
269   }
270 
get_gidOT::glyf_impl::CompositeGlyphRecord271   hb_codepoint_t get_gid () const
272   {
273 #ifndef HB_NO_BEYOND_64K
274     if (flags & GID_IS_24BIT)
275       return StructAfter<const HBGlyphID24> (flags);
276     else
277 #endif
278       return StructAfter<const HBGlyphID16> (flags);
279   }
set_gidOT::glyf_impl::CompositeGlyphRecord280   void set_gid (hb_codepoint_t gid)
281   {
282 #ifndef HB_NO_BEYOND_64K
283     if (flags & GID_IS_24BIT)
284       StructAfter<HBGlyphID24> (flags) = gid;
285     else
286 #endif
287       /* TODO assert? */
288       StructAfter<HBGlyphID16> (flags) = gid;
289   }
290 
291 #ifndef HB_NO_BEYOND_64K
lower_gid_24_to_16OT::glyf_impl::CompositeGlyphRecord292   void lower_gid_24_to_16 ()
293   {
294     hb_codepoint_t gid = get_gid ();
295     if (!(flags & GID_IS_24BIT) || gid > 0xFFFFu)
296       return;
297 
298     /* Lower the flag and move the rest of the struct down. */
299 
300     unsigned size = get_size ();
301     char *end = (char *) this + size;
302     char *p = &StructAfter<char> (flags);
303     p += HBGlyphID24::static_size;
304 
305     flags = flags & ~GID_IS_24BIT;
306     set_gid (gid);
307 
308     memmove (p - HBGlyphID24::static_size + HBGlyphID16::static_size, p, end - p);
309   }
310 #endif
311 
312   protected:
313   HBUINT16	flags;
314   HBUINT24	pad;
315   public:
316   DEFINE_SIZE_MIN (4);
317 };
318 
319 using composite_iter_t = composite_iter_tmpl<CompositeGlyphRecord>;
320 
321 struct CompositeGlyph
322 {
323   const GlyphHeader &header;
324   hb_bytes_t bytes;
CompositeGlyphOT::glyf_impl::CompositeGlyph325   CompositeGlyph (const GlyphHeader &header_, hb_bytes_t bytes_) :
326     header (header_), bytes (bytes_) {}
327 
iterOT::glyf_impl::CompositeGlyph328   composite_iter_t iter () const
329   { return composite_iter_t (bytes, &StructAfter<CompositeGlyphRecord, GlyphHeader> (header)); }
330 
instructions_lengthOT::glyf_impl::CompositeGlyph331   unsigned int instructions_length (hb_bytes_t bytes) const
332   {
333     unsigned int start = bytes.length;
334     unsigned int end = bytes.length;
335     const CompositeGlyphRecord *last = nullptr;
336     for (auto &item : iter ())
337       last = &item;
338     if (unlikely (!last)) return 0;
339 
340     if (last->has_instructions ())
341       start = (char *) last - &bytes + last->get_size ();
342     if (unlikely (start > end)) return 0;
343     return end - start;
344   }
345 
346   /* Trimming for composites not implemented.
347    * If removing hints it falls out of that. */
trim_paddingOT::glyf_impl::CompositeGlyph348   const hb_bytes_t trim_padding () const { return bytes; }
349 
drop_hintsOT::glyf_impl::CompositeGlyph350   void drop_hints ()
351   {
352     for (const auto &_ : iter ())
353       const_cast<CompositeGlyphRecord &> (_).drop_instructions_flag ();
354   }
355 
356   /* Chop instructions off the end */
drop_hints_bytesOT::glyf_impl::CompositeGlyph357   void drop_hints_bytes (hb_bytes_t &dest_start) const
358   { dest_start = bytes.sub_array (0, bytes.length - instructions_length (bytes)); }
359 
set_overlaps_flagOT::glyf_impl::CompositeGlyph360   void set_overlaps_flag ()
361   {
362     CompositeGlyphRecord& glyph_chain = const_cast<CompositeGlyphRecord &> (
363 	StructAfter<CompositeGlyphRecord, GlyphHeader> (header));
364     if (!bytes.check_range(&glyph_chain, CompositeGlyphRecord::min_size))
365       return;
366     glyph_chain.set_overlaps_flag ();
367   }
368 
compile_bytes_with_deltasOT::glyf_impl::CompositeGlyph369   bool compile_bytes_with_deltas (const hb_bytes_t &source_bytes,
370                                   const contour_point_vector_t &points_with_deltas,
371                                   hb_bytes_t &dest_bytes /* OUT */)
372   {
373     if (source_bytes.length <= GlyphHeader::static_size ||
374         header.numberOfContours != -1)
375     {
376       dest_bytes = hb_bytes_t ();
377       return true;
378     }
379 
380     unsigned source_len = source_bytes.length - GlyphHeader::static_size;
381 
382     /* try to allocate more memories than source glyph bytes
383      * in case that there might be an overflow for int8 value
384      * and we would need to use int16 instead */
385     char *o = (char *) hb_calloc (source_len * 2, sizeof (char));
386     if (unlikely (!o)) return false;
387 
388     const CompositeGlyphRecord *c = reinterpret_cast<const CompositeGlyphRecord *> (source_bytes.arrayZ + GlyphHeader::static_size);
389     auto it = composite_iter_t (hb_bytes_t ((const char *)c, source_len), c);
390 
391     char *p = o;
392     unsigned i = 0, source_comp_len = 0;
393     for (const auto &component : it)
394     {
395       /* last 4 points in points_with_deltas are phantom points and should not be included */
396       if (i >= points_with_deltas.length - 4) {
397         hb_free (o);
398         return false;
399       }
400 
401       unsigned comp_len = component.get_size ();
402       if (component.is_anchored ())
403       {
404         hb_memcpy (p, &component, comp_len);
405         p += comp_len;
406       }
407       else
408       {
409         unsigned new_len = component.compile_with_point (points_with_deltas[i], p);
410         p += new_len;
411       }
412       i++;
413       source_comp_len += comp_len;
414     }
415 
416     //copy instructions if any
417     if (source_len > source_comp_len)
418     {
419       unsigned instr_len = source_len - source_comp_len;
420       hb_memcpy (p, (const char *)c + source_comp_len, instr_len);
421       p += instr_len;
422     }
423 
424     unsigned len = p - o;
425     dest_bytes = hb_bytes_t (o, len);
426     return true;
427   }
428 };
429 
430 
431 } /* namespace glyf_impl */
432 } /* namespace OT */
433 
434 
435 #endif /* OT_GLYF_COMPOSITEGLYPH_HH */
436