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