1 /*
2 * Copyright © 2019-2020 Ebrahim Byagowi
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
25 #include "hb.hh"
26
27 #ifndef HB_NO_DRAW
28
29 #include "hb-draw.hh"
30
31 /**
32 * SECTION:hb-draw
33 * @title: hb-draw
34 * @short_description: Glyph drawing
35 * @include: hb.h
36 *
37 * Functions for drawing (extracting) glyph shapes.
38 **/
39
40 static void
hb_draw_move_to_nil(hb_draw_funcs_t * dfuncs HB_UNUSED,void * draw_data HB_UNUSED,hb_draw_state_t * st HB_UNUSED,float to_x HB_UNUSED,float to_y HB_UNUSED,void * user_data HB_UNUSED)41 hb_draw_move_to_nil (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data HB_UNUSED,
42 hb_draw_state_t *st HB_UNUSED,
43 float to_x HB_UNUSED, float to_y HB_UNUSED,
44 void *user_data HB_UNUSED) {}
45
46 static void
hb_draw_line_to_nil(hb_draw_funcs_t * dfuncs HB_UNUSED,void * draw_data HB_UNUSED,hb_draw_state_t * st HB_UNUSED,float to_x HB_UNUSED,float to_y HB_UNUSED,void * user_data HB_UNUSED)47 hb_draw_line_to_nil (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data HB_UNUSED,
48 hb_draw_state_t *st HB_UNUSED,
49 float to_x HB_UNUSED, float to_y HB_UNUSED,
50 void *user_data HB_UNUSED) {}
51
52 static void
hb_draw_quadratic_to_nil(hb_draw_funcs_t * dfuncs,void * draw_data,hb_draw_state_t * st,float control_x,float control_y,float to_x,float to_y,void * user_data HB_UNUSED)53 hb_draw_quadratic_to_nil (hb_draw_funcs_t *dfuncs, void *draw_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 #define HB_ONE_THIRD 0.33333333f
60 dfuncs->emit_cubic_to (draw_data, *st,
61 (st->current_x + 2.f * control_x) * HB_ONE_THIRD,
62 (st->current_y + 2.f * control_y) * HB_ONE_THIRD,
63 (to_x + 2.f * control_x) * HB_ONE_THIRD,
64 (to_y + 2.f * control_y) * HB_ONE_THIRD,
65 to_x, to_y);
66 #undef HB_ONE_THIRD
67 }
68
69 static void
hb_draw_cubic_to_nil(hb_draw_funcs_t * dfuncs HB_UNUSED,void * draw_data HB_UNUSED,hb_draw_state_t * st HB_UNUSED,float control1_x HB_UNUSED,float control1_y HB_UNUSED,float control2_x HB_UNUSED,float control2_y HB_UNUSED,float to_x HB_UNUSED,float to_y HB_UNUSED,void * user_data HB_UNUSED)70 hb_draw_cubic_to_nil (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data HB_UNUSED,
71 hb_draw_state_t *st HB_UNUSED,
72 float control1_x HB_UNUSED, float control1_y HB_UNUSED,
73 float control2_x HB_UNUSED, float control2_y HB_UNUSED,
74 float to_x HB_UNUSED, float to_y HB_UNUSED,
75 void *user_data HB_UNUSED) {}
76
77 static void
hb_draw_close_path_nil(hb_draw_funcs_t * dfuncs HB_UNUSED,void * draw_data HB_UNUSED,hb_draw_state_t * st HB_UNUSED,void * user_data HB_UNUSED)78 hb_draw_close_path_nil (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data HB_UNUSED,
79 hb_draw_state_t *st HB_UNUSED,
80 void *user_data HB_UNUSED) {}
81
82
83 static bool
_hb_draw_funcs_set_preamble(hb_draw_funcs_t * dfuncs,bool func_is_null,void ** user_data,hb_destroy_func_t * destroy)84 _hb_draw_funcs_set_preamble (hb_draw_funcs_t *dfuncs,
85 bool func_is_null,
86 void **user_data,
87 hb_destroy_func_t *destroy)
88 {
89 if (hb_object_is_immutable (dfuncs))
90 {
91 if (*destroy)
92 (*destroy) (*user_data);
93 return false;
94 }
95
96 if (func_is_null)
97 {
98 if (*destroy)
99 (*destroy) (*user_data);
100 *destroy = nullptr;
101 *user_data = nullptr;
102 }
103
104 return true;
105 }
106
107 static bool
_hb_draw_funcs_set_middle(hb_draw_funcs_t * dfuncs,void * user_data,hb_destroy_func_t destroy)108 _hb_draw_funcs_set_middle (hb_draw_funcs_t *dfuncs,
109 void *user_data,
110 hb_destroy_func_t destroy)
111 {
112 if (user_data && !dfuncs->user_data)
113 {
114 dfuncs->user_data = (decltype (dfuncs->user_data)) hb_calloc (1, sizeof (*dfuncs->user_data));
115 if (unlikely (!dfuncs->user_data))
116 goto fail;
117 }
118 if (destroy && !dfuncs->destroy)
119 {
120 dfuncs->destroy = (decltype (dfuncs->destroy)) hb_calloc (1, sizeof (*dfuncs->destroy));
121 if (unlikely (!dfuncs->destroy))
122 goto fail;
123 }
124
125 return true;
126
127 fail:
128 if (destroy)
129 (destroy) (user_data);
130 return false;
131 }
132
133 #define HB_DRAW_FUNC_IMPLEMENT(name) \
134 \
135 void \
136 hb_draw_funcs_set_##name##_func (hb_draw_funcs_t *dfuncs, \
137 hb_draw_##name##_func_t func, \
138 void *user_data, \
139 hb_destroy_func_t destroy) \
140 { \
141 if (!_hb_draw_funcs_set_preamble (dfuncs, !func, &user_data, &destroy))\
142 return; \
143 \
144 if (dfuncs->destroy && dfuncs->destroy->name) \
145 dfuncs->destroy->name (!dfuncs->user_data ? nullptr : dfuncs->user_data->name); \
146 \
147 if (!_hb_draw_funcs_set_middle (dfuncs, user_data, destroy)) \
148 return; \
149 \
150 if (func) \
151 dfuncs->func.name = func; \
152 else \
153 dfuncs->func.name = hb_draw_##name##_nil; \
154 \
155 if (dfuncs->user_data) \
156 dfuncs->user_data->name = user_data; \
157 if (dfuncs->destroy) \
158 dfuncs->destroy->name = destroy; \
159 }
160
161 HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS
162 #undef HB_DRAW_FUNC_IMPLEMENT
163
164 /**
165 * hb_draw_funcs_create:
166 *
167 * Creates a new draw callbacks object.
168 *
169 * Return value: (transfer full):
170 * A newly allocated #hb_draw_funcs_t with a reference count of 1. The initial
171 * reference count should be released with hb_draw_funcs_destroy when you are
172 * done using the #hb_draw_funcs_t. This function never returns `NULL`. If
173 * memory cannot be allocated, a special singleton #hb_draw_funcs_t object will
174 * be returned.
175 *
176 * Since: 4.0.0
177 **/
178 hb_draw_funcs_t *
hb_draw_funcs_create()179 hb_draw_funcs_create ()
180 {
181 hb_draw_funcs_t *dfuncs;
182 if (unlikely (!(dfuncs = hb_object_create<hb_draw_funcs_t> ())))
183 return const_cast<hb_draw_funcs_t *> (&Null (hb_draw_funcs_t));
184
185 dfuncs->func = Null (hb_draw_funcs_t).func;
186
187 return dfuncs;
188 }
189
190 DEFINE_NULL_INSTANCE (hb_draw_funcs_t) =
191 {
192 HB_OBJECT_HEADER_STATIC,
193
194 {
195 #define HB_DRAW_FUNC_IMPLEMENT(name) hb_draw_##name##_nil,
196 HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS
197 #undef HB_DRAW_FUNC_IMPLEMENT
198 }
199 };
200
201
202 /**
203 * hb_draw_funcs_reference: (skip)
204 * @dfuncs: draw functions
205 *
206 * Increases the reference count on @dfuncs by one. This prevents @buffer from
207 * being destroyed until a matching call to hb_draw_funcs_destroy() is made.
208 *
209 * Return value: (transfer full):
210 * The referenced #hb_draw_funcs_t.
211 *
212 * Since: 4.0.0
213 **/
214 hb_draw_funcs_t *
hb_draw_funcs_reference(hb_draw_funcs_t * dfuncs)215 hb_draw_funcs_reference (hb_draw_funcs_t *dfuncs)
216 {
217 return hb_object_reference (dfuncs);
218 }
219
220 /**
221 * hb_draw_funcs_destroy: (skip)
222 * @dfuncs: draw functions
223 *
224 * Deallocate the @dfuncs.
225 * Decreases the reference count on @dfuncs by one. If the result is zero, then
226 * @dfuncs and all associated resources are freed. See hb_draw_funcs_reference().
227 *
228 * Since: 4.0.0
229 **/
230 void
hb_draw_funcs_destroy(hb_draw_funcs_t * dfuncs)231 hb_draw_funcs_destroy (hb_draw_funcs_t *dfuncs)
232 {
233 if (!hb_object_destroy (dfuncs)) return;
234
235 if (dfuncs->destroy)
236 {
237 #define HB_DRAW_FUNC_IMPLEMENT(name) \
238 if (dfuncs->destroy->name) dfuncs->destroy->name (!dfuncs->user_data ? nullptr : dfuncs->user_data->name);
239 HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS
240 #undef HB_DRAW_FUNC_IMPLEMENT
241 }
242
243 hb_free (dfuncs->destroy);
244 hb_free (dfuncs->user_data);
245
246 hb_free (dfuncs);
247 }
248
249 /**
250 * hb_draw_funcs_make_immutable:
251 * @dfuncs: draw functions
252 *
253 * Makes @dfuncs object immutable.
254 *
255 * Since: 4.0.0
256 **/
257 void
hb_draw_funcs_make_immutable(hb_draw_funcs_t * dfuncs)258 hb_draw_funcs_make_immutable (hb_draw_funcs_t *dfuncs)
259 {
260 if (hb_object_is_immutable (dfuncs))
261 return;
262
263 hb_object_make_immutable (dfuncs);
264 }
265
266 /**
267 * hb_draw_funcs_is_immutable:
268 * @dfuncs: draw functions
269 *
270 * Checks whether @dfuncs is immutable.
271 *
272 * Return value: `true` if @dfuncs is immutable, `false` otherwise
273 *
274 * Since: 4.0.0
275 **/
276 hb_bool_t
hb_draw_funcs_is_immutable(hb_draw_funcs_t * dfuncs)277 hb_draw_funcs_is_immutable (hb_draw_funcs_t *dfuncs)
278 {
279 return hb_object_is_immutable (dfuncs);
280 }
281
282
283 /**
284 * hb_draw_move_to:
285 * @dfuncs: draw functions
286 * @draw_data: associated draw data passed by the caller
287 * @st: current draw state
288 * @to_x: X component of target point
289 * @to_y: Y component of target point
290 *
291 * Perform a "move-to" draw operation.
292 *
293 * Since: 4.0.0
294 **/
295 void
hb_draw_move_to(hb_draw_funcs_t * dfuncs,void * draw_data,hb_draw_state_t * st,float to_x,float to_y)296 hb_draw_move_to (hb_draw_funcs_t *dfuncs, void *draw_data,
297 hb_draw_state_t *st,
298 float to_x, float to_y)
299 {
300 dfuncs->move_to (draw_data, *st,
301 to_x, to_y);
302 }
303
304 /**
305 * hb_draw_line_to:
306 * @dfuncs: draw functions
307 * @draw_data: associated draw data passed by the caller
308 * @st: current draw state
309 * @to_x: X component of target point
310 * @to_y: Y component of target point
311 *
312 * Perform a "line-to" draw operation.
313 *
314 * Since: 4.0.0
315 **/
316 void
hb_draw_line_to(hb_draw_funcs_t * dfuncs,void * draw_data,hb_draw_state_t * st,float to_x,float to_y)317 hb_draw_line_to (hb_draw_funcs_t *dfuncs, void *draw_data,
318 hb_draw_state_t *st,
319 float to_x, float to_y)
320 {
321 dfuncs->line_to (draw_data, *st,
322 to_x, to_y);
323 }
324
325 /**
326 * hb_draw_quadratic_to:
327 * @dfuncs: draw functions
328 * @draw_data: associated draw data passed by the caller
329 * @st: current draw state
330 * @control_x: X component of control point
331 * @control_y: Y component of control point
332 * @to_x: X component of target point
333 * @to_y: Y component of target point
334 *
335 * Perform a "quadratic-to" draw operation.
336 *
337 * Since: 4.0.0
338 **/
339 void
hb_draw_quadratic_to(hb_draw_funcs_t * dfuncs,void * draw_data,hb_draw_state_t * st,float control_x,float control_y,float to_x,float to_y)340 hb_draw_quadratic_to (hb_draw_funcs_t *dfuncs, void *draw_data,
341 hb_draw_state_t *st,
342 float control_x, float control_y,
343 float to_x, float to_y)
344 {
345 dfuncs->quadratic_to (draw_data, *st,
346 control_x, control_y,
347 to_x, to_y);
348 }
349
350 /**
351 * hb_draw_cubic_to:
352 * @dfuncs: draw functions
353 * @draw_data: associated draw data passed by the caller
354 * @st: current draw state
355 * @control1_x: X component of first control point
356 * @control1_y: Y component of first control point
357 * @control2_x: X component of second control point
358 * @control2_y: Y component of second control point
359 * @to_x: X component of target point
360 * @to_y: Y component of target point
361 *
362 * Perform a "cubic-to" draw operation.
363 *
364 * Since: 4.0.0
365 **/
366 void
hb_draw_cubic_to(hb_draw_funcs_t * dfuncs,void * draw_data,hb_draw_state_t * st,float control1_x,float control1_y,float control2_x,float control2_y,float to_x,float to_y)367 hb_draw_cubic_to (hb_draw_funcs_t *dfuncs, void *draw_data,
368 hb_draw_state_t *st,
369 float control1_x, float control1_y,
370 float control2_x, float control2_y,
371 float to_x, float to_y)
372 {
373 dfuncs->cubic_to (draw_data, *st,
374 control1_x, control1_y,
375 control2_x, control2_y,
376 to_x, to_y);
377 }
378
379 /**
380 * hb_draw_close_path:
381 * @dfuncs: draw functions
382 * @draw_data: associated draw data passed by the caller
383 * @st: current draw state
384 *
385 * Perform a "close-path" draw operation.
386 *
387 * Since: 4.0.0
388 **/
389 void
hb_draw_close_path(hb_draw_funcs_t * dfuncs,void * draw_data,hb_draw_state_t * st)390 hb_draw_close_path (hb_draw_funcs_t *dfuncs, void *draw_data,
391 hb_draw_state_t *st)
392 {
393 dfuncs->close_path (draw_data, *st);
394 }
395
396
397 #endif
398