xref: /aosp_15_r20/external/harfbuzz_ng/src/OT/Var/VARC/VARC.cc (revision 2d1272b857b1f7575e6e246373e1cb218663db8a)
1 #include "VARC.hh"
2 
3 #ifndef HB_NO_VAR_COMPOSITES
4 
5 #include "../../../hb-draw.hh"
6 #include "../../../hb-geometry.hh"
7 #include "../../../hb-ot-layout-common.hh"
8 #include "../../../hb-ot-layout-gdef-table.hh"
9 
10 namespace OT {
11 
12 //namespace Var {
13 
14 
15 struct hb_transforming_pen_context_t
16 {
17   hb_transform_t transform;
18   hb_draw_funcs_t *dfuncs;
19   void *data;
20   hb_draw_state_t *st;
21 };
22 
23 static void
hb_transforming_pen_move_to(hb_draw_funcs_t * dfuncs HB_UNUSED,void * data,hb_draw_state_t * st,float to_x,float to_y,void * user_data HB_UNUSED)24 hb_transforming_pen_move_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
25 			     void *data,
26 			     hb_draw_state_t *st,
27 			     float to_x, float to_y,
28 			     void *user_data HB_UNUSED)
29 {
30   hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data;
31 
32   c->transform.transform_point (to_x, to_y);
33 
34   c->dfuncs->move_to (c->data, *c->st, to_x, to_y);
35 }
36 
37 static void
hb_transforming_pen_line_to(hb_draw_funcs_t * dfuncs HB_UNUSED,void * data,hb_draw_state_t * st,float to_x,float to_y,void * user_data HB_UNUSED)38 hb_transforming_pen_line_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
39 			     void *data,
40 			     hb_draw_state_t *st,
41 			     float to_x, float to_y,
42 			     void *user_data HB_UNUSED)
43 {
44   hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data;
45 
46   c->transform.transform_point (to_x, to_y);
47 
48   c->dfuncs->line_to (c->data, *c->st, to_x, to_y);
49 }
50 
51 static void
hb_transforming_pen_quadratic_to(hb_draw_funcs_t * dfuncs HB_UNUSED,void * data,hb_draw_state_t * st,float control_x,float control_y,float to_x,float to_y,void * user_data HB_UNUSED)52 hb_transforming_pen_quadratic_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
53 				  void *data,
54 				  hb_draw_state_t *st,
55 				  float control_x, float control_y,
56 				  float to_x, float to_y,
57 				  void *user_data HB_UNUSED)
58 {
59   hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data;
60 
61   c->transform.transform_point (control_x, control_y);
62   c->transform.transform_point (to_x, to_y);
63 
64   c->dfuncs->quadratic_to (c->data, *c->st, control_x, control_y, to_x, to_y);
65 }
66 
67 static void
hb_transforming_pen_cubic_to(hb_draw_funcs_t * dfuncs HB_UNUSED,void * data,hb_draw_state_t * st,float control1_x,float control1_y,float control2_x,float control2_y,float to_x,float to_y,void * user_data HB_UNUSED)68 hb_transforming_pen_cubic_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
69 			      void *data,
70 			      hb_draw_state_t *st,
71 			      float control1_x, float control1_y,
72 			      float control2_x, float control2_y,
73 			      float to_x, float to_y,
74 			      void *user_data HB_UNUSED)
75 {
76   hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data;
77 
78   c->transform.transform_point (control1_x, control1_y);
79   c->transform.transform_point (control2_x, control2_y);
80   c->transform.transform_point (to_x, to_y);
81 
82   c->dfuncs->cubic_to (c->data, *c->st, control1_x, control1_y, control2_x, control2_y, to_x, to_y);
83 }
84 
85 static void
hb_transforming_pen_close_path(hb_draw_funcs_t * dfuncs HB_UNUSED,void * data,hb_draw_state_t * st,void * user_data HB_UNUSED)86 hb_transforming_pen_close_path (hb_draw_funcs_t *dfuncs HB_UNUSED,
87 				void *data,
88 				hb_draw_state_t *st,
89 				void *user_data HB_UNUSED)
90 {
91   hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data;
92 
93   c->dfuncs->close_path (c->data, *c->st);
94 }
95 
96 static inline void free_static_transforming_pen_funcs ();
97 
98 static struct hb_transforming_pen_funcs_lazy_loader_t : hb_draw_funcs_lazy_loader_t<hb_transforming_pen_funcs_lazy_loader_t>
99 {
createOT::hb_transforming_pen_funcs_lazy_loader_t100   static hb_draw_funcs_t *create ()
101   {
102     hb_draw_funcs_t *funcs = hb_draw_funcs_create ();
103 
104     hb_draw_funcs_set_move_to_func (funcs, hb_transforming_pen_move_to, nullptr, nullptr);
105     hb_draw_funcs_set_line_to_func (funcs, hb_transforming_pen_line_to, nullptr, nullptr);
106     hb_draw_funcs_set_quadratic_to_func (funcs, hb_transforming_pen_quadratic_to, nullptr, nullptr);
107     hb_draw_funcs_set_cubic_to_func (funcs, hb_transforming_pen_cubic_to, nullptr, nullptr);
108     hb_draw_funcs_set_close_path_func (funcs, hb_transforming_pen_close_path, nullptr, nullptr);
109 
110     hb_draw_funcs_make_immutable (funcs);
111 
112     hb_atexit (free_static_transforming_pen_funcs);
113 
114     return funcs;
115   }
116 } static_transforming_pen_funcs;
117 
118 static inline
free_static_transforming_pen_funcs()119 void free_static_transforming_pen_funcs ()
120 {
121   static_transforming_pen_funcs.free_instance ();
122 }
123 
124 static hb_draw_funcs_t *
hb_transforming_pen_get_funcs()125 hb_transforming_pen_get_funcs ()
126 {
127   return static_transforming_pen_funcs.get_unconst ();
128 }
129 
130 
131 hb_ubytes_t
get_path_at(hb_font_t * font,hb_codepoint_t parent_gid,hb_draw_session_t & draw_session,hb_array_t<const int> coords,hb_ubytes_t total_record,hb_set_t * visited,signed * edges_left,signed depth_left,VarRegionList::cache_t * cache) const132 VarComponent::get_path_at (hb_font_t *font,
133 			   hb_codepoint_t parent_gid,
134 			   hb_draw_session_t &draw_session,
135 			   hb_array_t<const int> coords,
136 			   hb_ubytes_t total_record,
137 			   hb_set_t *visited,
138 			   signed *edges_left,
139 			   signed depth_left,
140 			   VarRegionList::cache_t *cache) const
141 {
142   const unsigned char *end = total_record.arrayZ + total_record.length;
143   const unsigned char *record = total_record.arrayZ;
144 
145   auto &VARC = *font->face->table.VARC;
146   auto &varStore = &VARC+VARC.varStore;
147   auto instancer = MultiItemVarStoreInstancer(&varStore, nullptr, coords, cache);
148 
149 #define READ_UINT32VAR(name) \
150   HB_STMT_START { \
151     if (unlikely (unsigned (end - record) < HBUINT32VAR::min_size)) return hb_ubytes_t (); \
152     hb_barrier (); \
153     auto &varint = * (const HBUINT32VAR *) record; \
154     unsigned size = varint.get_size (); \
155     if (unlikely (unsigned (end - record) < size)) return hb_ubytes_t (); \
156     name = (uint32_t) varint; \
157     record += size; \
158   } HB_STMT_END
159 
160   uint32_t flags;
161   READ_UINT32VAR (flags);
162 
163   // gid
164 
165   hb_codepoint_t gid = 0;
166   if (flags & (unsigned) flags_t::GID_IS_24BIT)
167   {
168     if (unlikely (unsigned (end - record) < HBGlyphID24::static_size))
169       return hb_ubytes_t ();
170     hb_barrier ();
171     gid = * (const HBGlyphID24 *) record;
172     record += HBGlyphID24::static_size;
173   }
174   else
175   {
176     if (unlikely (unsigned (end - record) < HBGlyphID16::static_size))
177       return hb_ubytes_t ();
178     hb_barrier ();
179     gid = * (const HBGlyphID16 *) record;
180     record += HBGlyphID16::static_size;
181   }
182 
183   // Condition
184   bool show = true;
185   if (flags & (unsigned) flags_t::HAVE_CONDITION)
186   {
187     unsigned conditionIndex;
188     READ_UINT32VAR (conditionIndex);
189     const auto &condition = (&VARC+VARC.conditionList)[conditionIndex];
190     show = condition.evaluate (coords.arrayZ, coords.length, &instancer);
191   }
192 
193   // Axis values
194 
195   hb_vector_t<unsigned> axisIndices;
196   hb_vector_t<float> axisValues;
197   if (flags & (unsigned) flags_t::HAVE_AXES)
198   {
199     unsigned axisIndicesIndex;
200     READ_UINT32VAR (axisIndicesIndex);
201     axisIndices = (&VARC+VARC.axisIndicesList)[axisIndicesIndex];
202     axisValues.resize (axisIndices.length);
203     const HBUINT8 *p = (const HBUINT8 *) record;
204     TupleValues::decompile (p, axisValues, (const HBUINT8 *) end);
205     record += (const unsigned char *) p - record;
206   }
207 
208   // Apply variations if any
209   if (flags & (unsigned) flags_t::AXIS_VALUES_HAVE_VARIATION)
210   {
211     uint32_t axisValuesVarIdx;
212     READ_UINT32VAR (axisValuesVarIdx);
213     if (show && coords && !axisValues.in_error ())
214       varStore.get_delta (axisValuesVarIdx, coords, axisValues.as_array (), cache);
215   }
216 
217   auto component_coords = coords;
218   /* Copying coords is expensive; so we have put an arbitrary
219    * limit on the max number of coords for now. */
220   if ((flags & (unsigned) flags_t::RESET_UNSPECIFIED_AXES) ||
221       coords.length > HB_VAR_COMPOSITE_MAX_AXES)
222     component_coords = hb_array<int> (font->coords, font->num_coords);
223 
224   // Transform
225 
226   uint32_t transformVarIdx = VarIdx::NO_VARIATION;
227   if (flags & (unsigned) flags_t::TRANSFORM_HAS_VARIATION)
228     READ_UINT32VAR (transformVarIdx);
229 
230 #define PROCESS_TRANSFORM_COMPONENTS \
231 	HB_STMT_START { \
232 	PROCESS_TRANSFORM_COMPONENT (FWORD, HAVE_TRANSLATE_X, translateX); \
233 	PROCESS_TRANSFORM_COMPONENT (FWORD, HAVE_TRANSLATE_Y, translateY); \
234 	PROCESS_TRANSFORM_COMPONENT (F4DOT12, HAVE_ROTATION, rotation); \
235 	PROCESS_TRANSFORM_COMPONENT (F6DOT10, HAVE_SCALE_X, scaleX); \
236 	PROCESS_TRANSFORM_COMPONENT (F6DOT10, HAVE_SCALE_Y, scaleY); \
237 	PROCESS_TRANSFORM_COMPONENT (F4DOT12, HAVE_SKEW_X, skewX); \
238 	PROCESS_TRANSFORM_COMPONENT (F4DOT12, HAVE_SKEW_Y, skewY); \
239 	PROCESS_TRANSFORM_COMPONENT (FWORD, HAVE_TCENTER_X, tCenterX); \
240 	PROCESS_TRANSFORM_COMPONENT (FWORD, HAVE_TCENTER_Y, tCenterY); \
241 	} HB_STMT_END
242 
243   hb_transform_decomposed_t transform;
244 
245   // Read transform components
246 #define PROCESS_TRANSFORM_COMPONENT(type, flag, name) \
247 	if (flags & (unsigned) flags_t::flag) \
248 	{ \
249 	  static_assert (type::static_size == HBINT16::static_size, ""); \
250 	  if (unlikely (unsigned (end - record) < HBINT16::static_size)) \
251 	    return hb_ubytes_t (); \
252 	  hb_barrier (); \
253 	  transform.name = * (const HBINT16 *) record; \
254 	  record += HBINT16::static_size; \
255 	}
256   PROCESS_TRANSFORM_COMPONENTS;
257 #undef PROCESS_TRANSFORM_COMPONENT
258 
259   // Read reserved records
260   unsigned i = flags & (unsigned) flags_t::RESERVED_MASK;
261   while (i)
262   {
263     HB_UNUSED uint32_t discard;
264     READ_UINT32VAR (discard);
265     i &= i - 1;
266   }
267 
268   /* Parsing is over now. */
269 
270   if (show)
271   {
272     // Only use coord_setter if there's actually any axis overrides.
273     coord_setter_t coord_setter (axisIndices ? component_coords : hb_array<int> ());
274     // Go backwards, to reduce coord_setter vector reallocations.
275     for (unsigned i = axisIndices.length; i; i--)
276       coord_setter[axisIndices[i - 1]] = axisValues[i - 1];
277     if (axisIndices)
278       component_coords = coord_setter.get_coords ();
279 
280     // Apply transform variations if any
281     if (transformVarIdx != VarIdx::NO_VARIATION && coords)
282     {
283       float transformValues[9];
284       unsigned numTransformValues = 0;
285 #define PROCESS_TRANSFORM_COMPONENT(type, flag, name) \
286 	  if (flags & (unsigned) flags_t::flag) \
287 	    transformValues[numTransformValues++] = transform.name;
288       PROCESS_TRANSFORM_COMPONENTS;
289 #undef PROCESS_TRANSFORM_COMPONENT
290       varStore.get_delta (transformVarIdx, coords, hb_array (transformValues, numTransformValues), cache);
291       numTransformValues = 0;
292 #define PROCESS_TRANSFORM_COMPONENT(type, flag, name) \
293 	  if (flags & (unsigned) flags_t::flag) \
294 	    transform.name = transformValues[numTransformValues++];
295       PROCESS_TRANSFORM_COMPONENTS;
296 #undef PROCESS_TRANSFORM_COMPONENT
297     }
298 
299     // Divide them by their divisors
300 #define PROCESS_TRANSFORM_COMPONENT(type, flag, name) \
301 	  if (flags & (unsigned) flags_t::flag) \
302 	  { \
303 	    HBINT16 int_v; \
304 	    int_v = roundf (transform.name); \
305 	    type typed_v = * (const type *) &int_v; \
306 	    float float_v = (float) typed_v; \
307 	    transform.name = float_v; \
308 	  }
309     PROCESS_TRANSFORM_COMPONENTS;
310 #undef PROCESS_TRANSFORM_COMPONENT
311 
312     if (!(flags & (unsigned) flags_t::HAVE_SCALE_Y))
313       transform.scaleY = transform.scaleX;
314 
315     // Scale the transform by the font's scale
316     float x_scale = font->x_multf;
317     float y_scale = font->y_multf;
318     transform.translateX *= x_scale;
319     transform.translateY *= y_scale;
320     transform.tCenterX *= x_scale;
321     transform.tCenterY *= y_scale;
322 
323     // Build a transforming pen to apply the transform.
324     hb_draw_funcs_t *transformer_funcs = hb_transforming_pen_get_funcs ();
325     hb_transforming_pen_context_t context {transform.to_transform (),
326 					   draw_session.funcs,
327 					   draw_session.draw_data,
328 					   &draw_session.st};
329     hb_draw_session_t transformer_session {transformer_funcs, &context};
330 
331     VARC.get_path_at (font, gid,
332 		      transformer_session, component_coords,
333 		      parent_gid,
334 		      visited, edges_left, depth_left - 1);
335   }
336 
337 #undef PROCESS_TRANSFORM_COMPONENTS
338 #undef READ_UINT32VAR
339 
340   return hb_ubytes_t (record, end - record);
341 }
342 
343 //} // namespace Var
344 } // namespace OT
345 
346 #endif
347