1/*
2 * Copyright © 2022 Matthias Clasen
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_PAINT
28
29#include "hb-paint.hh"
30
31/**
32 * SECTION: hb-paint
33 * @title: hb-paint
34 * @short_description: Glyph painting
35 * @include: hb.h
36 *
37 * Functions for painting glyphs.
38 *
39 * The main purpose of these functions is to paint (extract) color glyph layers
40 * from the COLRv1 table, but the API works for drawing ordinary outlines and
41 * images as well.
42 *
43 * The #hb_paint_funcs_t struct can be used with hb_font_paint_glyph().
44 **/
45
46static void
47hb_paint_push_transform_nil (hb_paint_funcs_t *funcs, void *paint_data,
48 float xx, float yx,
49 float xy, float yy,
50 float dx, float dy,
51 void *user_data) {}
52
53static void
54hb_paint_pop_transform_nil (hb_paint_funcs_t *funcs, void *paint_data,
55 void *user_data) {}
56
57static void
58hb_paint_push_clip_glyph_nil (hb_paint_funcs_t *funcs, void *paint_data,
59 hb_codepoint_t glyph,
60 hb_font_t *font,
61 void *user_data) {}
62
63static void
64hb_paint_push_clip_rectangle_nil (hb_paint_funcs_t *funcs, void *paint_data,
65 float xmin, float ymin, float xmax, float ymax,
66 void *user_data) {}
67
68static void
69hb_paint_pop_clip_nil (hb_paint_funcs_t *funcs, void *paint_data,
70 void *user_data) {}
71
72static void
73hb_paint_color_nil (hb_paint_funcs_t *funcs, void *paint_data,
74 hb_bool_t is_foreground,
75 hb_color_t color,
76 void *user_data) {}
77
78static hb_bool_t
79hb_paint_image_nil (hb_paint_funcs_t *funcs, void *paint_data,
80 hb_blob_t *image,
81 unsigned int width,
82 unsigned int height,
83 hb_tag_t format,
84 float slant_xy,
85 hb_glyph_extents_t *extents,
86 void *user_data) { return false; }
87
88static void
89hb_paint_linear_gradient_nil (hb_paint_funcs_t *funcs, void *paint_data,
90 hb_color_line_t *color_line,
91 float x0, float y0,
92 float x1, float y1,
93 float x2, float y2,
94 void *user_data) {}
95
96static void
97hb_paint_radial_gradient_nil (hb_paint_funcs_t *funcs, void *paint_data,
98 hb_color_line_t *color_line,
99 float x0, float y0, float r0,
100 float x1, float y1, float r1,
101 void *user_data) {}
102
103static void
104hb_paint_sweep_gradient_nil (hb_paint_funcs_t *funcs, void *paint_data,
105 hb_color_line_t *color_line,
106 float x0, float y0,
107 float start_angle,
108 float end_angle,
109 void *user_data) {}
110
111static void
112hb_paint_push_group_nil (hb_paint_funcs_t *funcs, void *paint_data,
113 void *user_data) {}
114
115static void
116hb_paint_pop_group_nil (hb_paint_funcs_t *funcs, void *paint_data,
117 hb_paint_composite_mode_t mode,
118 void *user_data) {}
119
120static hb_bool_t
121hb_paint_custom_palette_color_nil (hb_paint_funcs_t *funcs, void *paint_data,
122 unsigned int color_index,
123 hb_color_t *color,
124 void *user_data) { return false; }
125
126static bool
127_hb_paint_funcs_set_preamble (hb_paint_funcs_t *funcs,
128 bool func_is_null,
129 void **user_data,
130 hb_destroy_func_t *destroy)
131{
132 if (hb_object_is_immutable (funcs))
133 {
134 if (*destroy)
135 (*destroy) (*user_data);
136 return false;
137 }
138
139 if (func_is_null)
140 {
141 if (*destroy)
142 (*destroy) (*user_data);
143 *destroy = nullptr;
144 *user_data = nullptr;
145 }
146
147 return true;
148}
149
150static bool
151_hb_paint_funcs_set_middle (hb_paint_funcs_t *funcs,
152 void *user_data,
153 hb_destroy_func_t destroy)
154{
155 if (user_data && !funcs->user_data)
156 {
157 funcs->user_data = (decltype (funcs->user_data)) hb_calloc (1, sizeof (*funcs->user_data));
158 if (unlikely (!funcs->user_data))
159 goto fail;
160 }
161 if (destroy && !funcs->destroy)
162 {
163 funcs->destroy = (decltype (funcs->destroy)) hb_calloc (1, sizeof (*funcs->destroy));
164 if (unlikely (!funcs->destroy))
165 goto fail;
166 }
167
168 return true;
169
170fail:
171 if (destroy)
172 (destroy) (user_data);
173 return false;
174}
175
176#define HB_PAINT_FUNC_IMPLEMENT(name) \
177 \
178void \
179hb_paint_funcs_set_##name##_func (hb_paint_funcs_t *funcs, \
180 hb_paint_##name##_func_t func, \
181 void *user_data, \
182 hb_destroy_func_t destroy) \
183{ \
184 if (!_hb_paint_funcs_set_preamble (funcs, !func, &user_data, &destroy)) \
185 return; \
186 \
187 if (funcs->destroy && funcs->destroy->name) \
188 funcs->destroy->name (!funcs->user_data ? nullptr : funcs->user_data->name);\
189 \
190 if (!_hb_paint_funcs_set_middle (funcs, user_data, destroy)) \
191 return; \
192 \
193 if (func) \
194 funcs->func.name = func; \
195 else \
196 funcs->func.name = hb_paint_##name##_nil; \
197 \
198 if (funcs->user_data) \
199 funcs->user_data->name = user_data; \
200 if (funcs->destroy) \
201 funcs->destroy->name = destroy; \
202}
203
204HB_PAINT_FUNCS_IMPLEMENT_CALLBACKS
205#undef HB_PAINT_FUNC_IMPLEMENT
206
207/**
208 * hb_paint_funcs_create:
209 *
210 * Creates a new #hb_paint_funcs_t structure of paint functions.
211 *
212 * The initial reference count of 1 should be released with hb_paint_funcs_destroy()
213 * when you are done using the #hb_paint_funcs_t. This function never returns
214 * `NULL`. If memory cannot be allocated, a special singleton #hb_paint_funcs_t
215 * object will be returned.
216 *
217 * Returns value: (transfer full): the paint-functions structure
218 *
219 * Since: 7.0.0
220 */
221hb_paint_funcs_t *
222hb_paint_funcs_create ()
223{
224 hb_paint_funcs_t *funcs;
225 if (unlikely (!(funcs = hb_object_create<hb_paint_funcs_t> ())))
226 return const_cast<hb_paint_funcs_t *> (&Null (hb_paint_funcs_t));
227
228 funcs->func = Null (hb_paint_funcs_t).func;
229
230 return funcs;
231}
232
233DEFINE_NULL_INSTANCE (hb_paint_funcs_t) =
234{
235 HB_OBJECT_HEADER_STATIC,
236
237 {
238#define HB_PAINT_FUNC_IMPLEMENT(name) hb_paint_##name##_nil,
239 HB_PAINT_FUNCS_IMPLEMENT_CALLBACKS
240#undef HB_PAINT_FUNC_IMPLEMENT
241 }
242};
243
244/**
245 * hb_paint_funcs_get_empty:
246 *
247 * Fetches the singleton empty paint-functions structure.
248 *
249 * Return value: (transfer full): The empty paint-functions structure
250 *
251 * Since: 7.0.0
252 **/
253hb_paint_funcs_t *
254hb_paint_funcs_get_empty ()
255{
256 return const_cast<hb_paint_funcs_t *> (&Null (hb_paint_funcs_t));
257}
258
259/**
260 * hb_paint_funcs_reference: (skip)
261 * @funcs: The paint-functions structure
262 *
263 * Increases the reference count on a paint-functions structure.
264 *
265 * This prevents @funcs from being destroyed until a matching
266 * call to hb_paint_funcs_destroy() is made.
267 *
268 * Return value: The paint-functions structure
269 *
270 * Since: 7.0.0
271 */
272hb_paint_funcs_t *
273hb_paint_funcs_reference (hb_paint_funcs_t *funcs)
274{
275 return hb_object_reference (funcs);
276}
277
278/**
279 * hb_paint_funcs_destroy: (skip)
280 * @funcs: The paint-functions structure
281 *
282 * Decreases the reference count on a paint-functions structure.
283 *
284 * When the reference count reaches zero, the structure
285 * is destroyed, freeing all memory.
286 *
287 * Since: 7.0.0
288 */
289void
290hb_paint_funcs_destroy (hb_paint_funcs_t *funcs)
291{
292 if (!hb_object_destroy (funcs)) return;
293
294 if (funcs->destroy)
295 {
296#define HB_PAINT_FUNC_IMPLEMENT(name) \
297 if (funcs->destroy->name) funcs->destroy->name (!funcs->user_data ? nullptr : funcs->user_data->name);
298 HB_PAINT_FUNCS_IMPLEMENT_CALLBACKS
299#undef HB_PAINT_FUNC_IMPLEMENT
300 }
301
302 hb_free (funcs->destroy);
303 hb_free (funcs->user_data);
304 hb_free (funcs);
305}
306
307/**
308 * hb_paint_funcs_set_user_data: (skip)
309 * @funcs: The paint-functions structure
310 * @key: The user-data key
311 * @data: A pointer to the user data
312 * @destroy: (nullable): A callback to call when @data is not needed anymore
313 * @replace: Whether to replace an existing data with the same key
314 *
315 * Attaches a user-data key/data pair to the specified paint-functions structure.
316 *
317 * Return value: `true` if success, `false` otherwise
318 *
319 * Since: 7.0.0
320 **/
321hb_bool_t
322hb_paint_funcs_set_user_data (hb_paint_funcs_t *funcs,
323 hb_user_data_key_t *key,
324 void * data,
325 hb_destroy_func_t destroy,
326 hb_bool_t replace)
327{
328 return hb_object_set_user_data (funcs, key, data, destroy, replace);
329}
330
331/**
332 * hb_paint_funcs_get_user_data: (skip)
333 * @funcs: The paint-functions structure
334 * @key: The user-data key to query
335 *
336 * Fetches the user-data associated with the specified key,
337 * attached to the specified paint-functions structure.
338 *
339 * Return value: (transfer none): A pointer to the user data
340 *
341 * Since: 7.0.0
342 **/
343void *
344hb_paint_funcs_get_user_data (const hb_paint_funcs_t *funcs,
345 hb_user_data_key_t *key)
346{
347 return hb_object_get_user_data (funcs, key);
348}
349
350/**
351 * hb_paint_funcs_make_immutable:
352 * @funcs: The paint-functions structure
353 *
354 * Makes a paint-functions structure immutable.
355 *
356 * After this call, all attempts to set one of the callbacks
357 * on @funcs will fail.
358 *
359 * Since: 7.0.0
360 */
361void
362hb_paint_funcs_make_immutable (hb_paint_funcs_t *funcs)
363{
364 if (hb_object_is_immutable (funcs))
365 return;
366
367 hb_object_make_immutable (funcs);
368}
369
370/**
371 * hb_paint_funcs_is_immutable:
372 * @funcs: The paint-functions structure
373 *
374 * Tests whether a paint-functions structure is immutable.
375 *
376 * Return value: `true` if @funcs is immutable, `false` otherwise
377 *
378 * Since: 7.0.0
379 */
380hb_bool_t
381hb_paint_funcs_is_immutable (hb_paint_funcs_t *funcs)
382{
383 return hb_object_is_immutable (funcs);
384}
385
386
387/**
388 * hb_color_line_get_color_stops:
389 * @color_line: a #hb_color_line_t object
390 * @start: the index of the first color stop to return
391 * @count: (inout) (optional): Input = the maximum number of feature tags to return;
392 * Output = the actual number of feature tags returned (may be zero)
393 * @color_stops: (out) (array length=count) (optional): Array of #hb_color_stop_t to populate
394 *
395 * Fetches a list of color stops from the given color line object.
396 *
397 * Note that due to variations being applied, the returned color stops
398 * may be out of order. It is the callers responsibility to ensure that
399 * color stops are sorted by their offset before they are used.
400 *
401 * Return value: the total number of color stops in @color_line
402 *
403 * Since: 7.0.0
404 */
405unsigned int
406hb_color_line_get_color_stops (hb_color_line_t *color_line,
407 unsigned int start,
408 unsigned int *count,
409 hb_color_stop_t *color_stops)
410{
411 return color_line->get_color_stops (color_line,
412 color_line->data,
413 start, count,
414 color_stops,
415 color_line->get_color_stops_user_data);
416}
417
418/**
419 * hb_color_line_get_extend:
420 * @color_line: a #hb_color_line_t object
421 *
422 * Fetches the extend mode of the color line object.
423 *
424 * Return value: the extend mode of @color_line
425 *
426 * Since: 7.0.0
427 */
428hb_paint_extend_t
429hb_color_line_get_extend (hb_color_line_t *color_line)
430{
431 return color_line->get_extend (color_line,
432 color_line->data,
433 color_line->get_extend_user_data);
434}
435
436
437/**
438 * hb_paint_push_transform:
439 * @funcs: paint functions
440 * @paint_data: associated data passed by the caller
441 * @xx: xx component of the transform matrix
442 * @yx: yx component of the transform matrix
443 * @xy: xy component of the transform matrix
444 * @yy: yy component of the transform matrix
445 * @dx: dx component of the transform matrix
446 * @dy: dy component of the transform matrix
447 *
448 * Perform a "push-transform" paint operation.
449 *
450 * Since: 7.0.0
451 */
452void
453hb_paint_push_transform (hb_paint_funcs_t *funcs, void *paint_data,
454 float xx, float yx,
455 float xy, float yy,
456 float dx, float dy)
457{
458 funcs->push_transform (paint_data, xx, yx, xy, yy, dx, dy);
459}
460
461/**
462 * hb_paint_pop_transform:
463 * @funcs: paint functions
464 * @paint_data: associated data passed by the caller
465 *
466 * Perform a "pop-transform" paint operation.
467 *
468 * Since: 7.0.0
469 */
470void
471hb_paint_pop_transform (hb_paint_funcs_t *funcs, void *paint_data)
472{
473 funcs->pop_transform (paint_data);
474}
475
476/**
477 * hb_paint_push_clip_glyph:
478 * @funcs: paint functions
479 * @paint_data: associated data passed by the caller
480 * @glyph: the glyph ID
481 * @font: the font
482 *
483 * Perform a "push-clip-glyph" paint operation.
484 *
485 * Since: 7.0.0
486 */
487void
488hb_paint_push_clip_glyph (hb_paint_funcs_t *funcs, void *paint_data,
489 hb_codepoint_t glyph,
490 hb_font_t *font)
491{
492 funcs->push_clip_glyph (paint_data, glyph, font);
493}
494
495/**
496 * hb_paint_push_clip_rectangle:
497 * @funcs: paint functions
498 * @paint_data: associated data passed by the caller
499 * @xmin: min X for the rectangle
500 * @ymin: min Y for the rectangle
501 * @xmax: max X for the rectangle
502 * @ymax: max Y for the rectangle
503 *
504 * Perform a "push-clip-rect" paint operation.
505 *
506 * Since: 7.0.0
507 */
508void
509hb_paint_push_clip_rectangle (hb_paint_funcs_t *funcs, void *paint_data,
510 float xmin, float ymin, float xmax, float ymax)
511{
512 funcs->push_clip_rectangle (paint_data, xmin, ymin, xmax, ymax);
513}
514
515/**
516 * hb_paint_pop_clip:
517 * @funcs: paint functions
518 * @paint_data: associated data passed by the caller
519 *
520 * Perform a "pop-clip" paint operation.
521 *
522 * Since: 7.0.0
523 */
524void
525hb_paint_pop_clip (hb_paint_funcs_t *funcs, void *paint_data)
526{
527 funcs->pop_clip (paint_data);
528}
529
530/**
531 * hb_paint_color:
532 * @funcs: paint functions
533 * @paint_data: associated data passed by the caller
534 * @is_foreground: whether the color is the foreground
535 * @color: The color to use
536 *
537 * Perform a "color" paint operation.
538 *
539 * Since: 7.0.0
540 */
541void
542hb_paint_color (hb_paint_funcs_t *funcs, void *paint_data,
543 hb_bool_t is_foreground,
544 hb_color_t color)
545{
546 funcs->color (paint_data, is_foreground, color);
547}
548
549/**
550 * hb_paint_image:
551 * @funcs: paint functions
552 * @paint_data: associated data passed by the caller
553 * @image: image data
554 * @width: width of the raster image in pixels, or 0
555 * @height: height of the raster image in pixels, or 0
556 * @format: the image format as a tag
557 * @slant: the synthetic slant ratio to be applied to the image during rendering
558 * @extents: (nullable): the extents of the glyph
559 *
560 * Perform a "image" paint operation.
561 *
562 * Since: 7.0.0
563 */
564void
565hb_paint_image (hb_paint_funcs_t *funcs, void *paint_data,
566 hb_blob_t *image,
567 unsigned int width,
568 unsigned int height,
569 hb_tag_t format,
570 float slant,
571 hb_glyph_extents_t *extents)
572{
573 funcs->image (paint_data, image, width, height, format, slant, extents);
574}
575
576/**
577 * hb_paint_linear_gradient:
578 * @funcs: paint functions
579 * @paint_data: associated data passed by the caller
580 * @color_line: Color information for the gradient
581 * @x0: X coordinate of the first point
582 * @y0: Y coordinate of the first point
583 * @x1: X coordinate of the second point
584 * @y1: Y coordinate of the second point
585 * @x2: X coordinate of the third point
586 * @y2: Y coordinate of the third point
587 *
588 * Perform a "linear-gradient" paint operation.
589 *
590 * Since: 7.0.0
591 */
592void
593hb_paint_linear_gradient (hb_paint_funcs_t *funcs, void *paint_data,
594 hb_color_line_t *color_line,
595 float x0, float y0,
596 float x1, float y1,
597 float x2, float y2)
598{
599 funcs->linear_gradient (paint_data, color_line, x0, y0, x1, y1, x2, y2);
600}
601
602/**
603 * hb_paint_radial_gradient:
604 * @funcs: paint functions
605 * @paint_data: associated data passed by the caller
606 * @color_line: Color information for the gradient
607 * @x0: X coordinate of the first circle's center
608 * @y0: Y coordinate of the first circle's center
609 * @r0: radius of the first circle
610 * @x1: X coordinate of the second circle's center
611 * @y1: Y coordinate of the second circle's center
612 * @r1: radius of the second circle
613 *
614 * Perform a "radial-gradient" paint operation.
615 *
616 * Since: 7.0.0
617 */
618void
619hb_paint_radial_gradient (hb_paint_funcs_t *funcs, void *paint_data,
620 hb_color_line_t *color_line,
621 float x0, float y0, float r0,
622 float x1, float y1, float r1)
623{
624 funcs->radial_gradient (paint_data, color_line, x0, y0, r0, y1, x1, r1);
625}
626
627/**
628 * hb_paint_sweep_gradient:
629 * @funcs: paint functions
630 * @paint_data: associated data passed by the caller
631 * @color_line: Color information for the gradient
632 * @x0: X coordinate of the circle's center
633 * @y0: Y coordinate of the circle's center
634 * @start_angle: the start angle
635 * @end_angle: the end angle
636 *
637 * Perform a "sweep-gradient" paint operation.
638 *
639 * Since: 7.0.0
640 */
641void
642hb_paint_sweep_gradient (hb_paint_funcs_t *funcs, void *paint_data,
643 hb_color_line_t *color_line,
644 float x0, float y0,
645 float start_angle, float end_angle)
646{
647 funcs->sweep_gradient (paint_data, color_line, x0, y0, start_angle, end_angle);
648}
649
650/**
651 * hb_paint_push_group:
652 * @funcs: paint functions
653 * @paint_data: associated data passed by the caller
654 *
655 * Perform a "push-group" paint operation.
656 *
657 * Since: 7.0.0
658 */
659void
660hb_paint_push_group (hb_paint_funcs_t *funcs, void *paint_data)
661{
662 funcs->push_group (paint_data);
663}
664
665/**
666 * hb_paint_pop_group:
667 * @funcs: paint functions
668 * @paint_data: associated data passed by the caller
669 * @mode: the compositing mode to use
670 *
671 * Perform a "pop-group" paint operation.
672 *
673 * Since: 7.0.0
674 */
675void
676hb_paint_pop_group (hb_paint_funcs_t *funcs, void *paint_data,
677 hb_paint_composite_mode_t mode)
678{
679 funcs->pop_group (paint_data, mode);
680}
681
682/**
683 * hb_paint_custom_palette_color:
684 * @funcs: paint functions
685 * @paint_data: associated data passed by the caller
686 * @color_index: color index
687 * @color: (out): fetched color
688 *
689 * Gets the custom palette color for @color_index.
690 *
691 * Return value: `true` if found, `false` otherwise
692 *
693 * Since: 7.0.0
694 */
695hb_bool_t
696hb_paint_custom_palette_color (hb_paint_funcs_t *funcs, void *paint_data,
697 unsigned int color_index,
698 hb_color_t *color)
699{
700 return funcs->custom_palette_color (paint_data, color_index, color);
701}
702
703#endif
704