2 * Copyright © 2022 Matthias Clasen
4 * This is part of HarfBuzz, a text shaping library.
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.
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
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.
29 #include "hb-paint.hh"
34 * @short_description: Glyph painting
37 * Functions for painting glyphs.
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
43 * The #hb_paint_funcs_t struct can be used with hb_font_paint_glyph().
47 hb_paint_push_transform_nil (hb_paint_funcs_t
*funcs
, void *paint_data
,
54 hb_paint_pop_transform_nil (hb_paint_funcs_t
*funcs
, void *paint_data
,
58 hb_paint_color_glyph_nil (hb_paint_funcs_t
*funcs
, void *paint_data
,
61 void *user_data
) { return false; }
64 hb_paint_push_clip_glyph_nil (hb_paint_funcs_t
*funcs
, void *paint_data
,
70 hb_paint_push_clip_rectangle_nil (hb_paint_funcs_t
*funcs
, void *paint_data
,
71 float xmin
, float ymin
, float xmax
, float ymax
,
75 hb_paint_pop_clip_nil (hb_paint_funcs_t
*funcs
, void *paint_data
,
79 hb_paint_color_nil (hb_paint_funcs_t
*funcs
, void *paint_data
,
80 hb_bool_t is_foreground
,
85 hb_paint_image_nil (hb_paint_funcs_t
*funcs
, void *paint_data
,
91 hb_glyph_extents_t
*extents
,
92 void *user_data
) { return false; }
95 hb_paint_linear_gradient_nil (hb_paint_funcs_t
*funcs
, void *paint_data
,
96 hb_color_line_t
*color_line
,
103 hb_paint_radial_gradient_nil (hb_paint_funcs_t
*funcs
, void *paint_data
,
104 hb_color_line_t
*color_line
,
105 float x0
, float y0
, float r0
,
106 float x1
, float y1
, float r1
,
110 hb_paint_sweep_gradient_nil (hb_paint_funcs_t
*funcs
, void *paint_data
,
111 hb_color_line_t
*color_line
,
118 hb_paint_push_group_nil (hb_paint_funcs_t
*funcs
, void *paint_data
,
122 hb_paint_pop_group_nil (hb_paint_funcs_t
*funcs
, void *paint_data
,
123 hb_paint_composite_mode_t mode
,
127 hb_paint_custom_palette_color_nil (hb_paint_funcs_t
*funcs
, void *paint_data
,
128 unsigned int color_index
,
130 void *user_data
) { return false; }
133 _hb_paint_funcs_set_preamble (hb_paint_funcs_t
*funcs
,
136 hb_destroy_func_t
*destroy
)
138 if (hb_object_is_immutable (funcs
))
141 (*destroy
) (*user_data
);
148 (*destroy
) (*user_data
);
150 *user_data
= nullptr;
157 _hb_paint_funcs_set_middle (hb_paint_funcs_t
*funcs
,
159 hb_destroy_func_t destroy
)
161 if (user_data
&& !funcs
->user_data
)
163 funcs
->user_data
= (decltype (funcs
->user_data
)) hb_calloc (1, sizeof (*funcs
->user_data
));
164 if (unlikely (!funcs
->user_data
))
167 if (destroy
&& !funcs
->destroy
)
169 funcs
->destroy
= (decltype (funcs
->destroy
)) hb_calloc (1, sizeof (*funcs
->destroy
));
170 if (unlikely (!funcs
->destroy
))
178 (destroy
) (user_data
);
182 #define HB_PAINT_FUNC_IMPLEMENT(name) \
185 hb_paint_funcs_set_##name##_func (hb_paint_funcs_t *funcs, \
186 hb_paint_##name##_func_t func, \
188 hb_destroy_func_t destroy) \
190 if (!_hb_paint_funcs_set_preamble (funcs, !func, &user_data, &destroy)) \
193 if (funcs->destroy && funcs->destroy->name) \
194 funcs->destroy->name (!funcs->user_data ? nullptr : funcs->user_data->name);\
196 if (!_hb_paint_funcs_set_middle (funcs, user_data, destroy)) \
200 funcs->func.name = func; \
202 funcs->func.name = hb_paint_##name##_nil; \
204 if (funcs->user_data) \
205 funcs->user_data->name = user_data; \
206 if (funcs->destroy) \
207 funcs->destroy->name = destroy; \
210 HB_PAINT_FUNCS_IMPLEMENT_CALLBACKS
211 #undef HB_PAINT_FUNC_IMPLEMENT
214 * hb_paint_funcs_create:
216 * Creates a new #hb_paint_funcs_t structure of paint functions.
218 * The initial reference count of 1 should be released with hb_paint_funcs_destroy()
219 * when you are done using the #hb_paint_funcs_t. This function never returns
220 * `NULL`. If memory cannot be allocated, a special singleton #hb_paint_funcs_t
221 * object will be returned.
223 * Returns value: (transfer full): the paint-functions structure
228 hb_paint_funcs_create ()
230 hb_paint_funcs_t
*funcs
;
231 if (unlikely (!(funcs
= hb_object_create
<hb_paint_funcs_t
> ())))
232 return const_cast<hb_paint_funcs_t
*> (&Null (hb_paint_funcs_t
));
234 funcs
->func
= Null (hb_paint_funcs_t
).func
;
239 DEFINE_NULL_INSTANCE (hb_paint_funcs_t
) =
241 HB_OBJECT_HEADER_STATIC
,
244 #define HB_PAINT_FUNC_IMPLEMENT(name) hb_paint_##name##_nil,
245 HB_PAINT_FUNCS_IMPLEMENT_CALLBACKS
246 #undef HB_PAINT_FUNC_IMPLEMENT
251 * hb_paint_funcs_get_empty:
253 * Fetches the singleton empty paint-functions structure.
255 * Return value: (transfer full): The empty paint-functions structure
260 hb_paint_funcs_get_empty ()
262 return const_cast<hb_paint_funcs_t
*> (&Null (hb_paint_funcs_t
));
266 * hb_paint_funcs_reference: (skip)
267 * @funcs: The paint-functions structure
269 * Increases the reference count on a paint-functions structure.
271 * This prevents @funcs from being destroyed until a matching
272 * call to hb_paint_funcs_destroy() is made.
274 * Return value: The paint-functions structure
279 hb_paint_funcs_reference (hb_paint_funcs_t
*funcs
)
281 return hb_object_reference (funcs
);
285 * hb_paint_funcs_destroy: (skip)
286 * @funcs: The paint-functions structure
288 * Decreases the reference count on a paint-functions structure.
290 * When the reference count reaches zero, the structure
291 * is destroyed, freeing all memory.
296 hb_paint_funcs_destroy (hb_paint_funcs_t
*funcs
)
298 if (!hb_object_destroy (funcs
)) return;
302 #define HB_PAINT_FUNC_IMPLEMENT(name) \
303 if (funcs->destroy->name) funcs->destroy->name (!funcs->user_data ? nullptr : funcs->user_data->name);
304 HB_PAINT_FUNCS_IMPLEMENT_CALLBACKS
305 #undef HB_PAINT_FUNC_IMPLEMENT
308 hb_free (funcs
->destroy
);
309 hb_free (funcs
->user_data
);
314 * hb_paint_funcs_set_user_data: (skip)
315 * @funcs: The paint-functions structure
316 * @key: The user-data key
317 * @data: A pointer to the user data
318 * @destroy: (nullable): A callback to call when @data is not needed anymore
319 * @replace: Whether to replace an existing data with the same key
321 * Attaches a user-data key/data pair to the specified paint-functions structure.
323 * Return value: `true` if success, `false` otherwise
328 hb_paint_funcs_set_user_data (hb_paint_funcs_t
*funcs
,
329 hb_user_data_key_t
*key
,
331 hb_destroy_func_t destroy
,
334 return hb_object_set_user_data (funcs
, key
, data
, destroy
, replace
);
338 * hb_paint_funcs_get_user_data: (skip)
339 * @funcs: The paint-functions structure
340 * @key: The user-data key to query
342 * Fetches the user-data associated with the specified key,
343 * attached to the specified paint-functions structure.
345 * Return value: (transfer none): A pointer to the user data
350 hb_paint_funcs_get_user_data (const hb_paint_funcs_t
*funcs
,
351 hb_user_data_key_t
*key
)
353 return hb_object_get_user_data (funcs
, key
);
357 * hb_paint_funcs_make_immutable:
358 * @funcs: The paint-functions structure
360 * Makes a paint-functions structure immutable.
362 * After this call, all attempts to set one of the callbacks
363 * on @funcs will fail.
368 hb_paint_funcs_make_immutable (hb_paint_funcs_t
*funcs
)
370 if (hb_object_is_immutable (funcs
))
373 hb_object_make_immutable (funcs
);
377 * hb_paint_funcs_is_immutable:
378 * @funcs: The paint-functions structure
380 * Tests whether a paint-functions structure is immutable.
382 * Return value: `true` if @funcs is immutable, `false` otherwise
387 hb_paint_funcs_is_immutable (hb_paint_funcs_t
*funcs
)
389 return hb_object_is_immutable (funcs
);
394 * hb_color_line_get_color_stops:
395 * @color_line: a #hb_color_line_t object
396 * @start: the index of the first color stop to return
397 * @count: (inout) (optional): Input = the maximum number of feature tags to return;
398 * Output = the actual number of feature tags returned (may be zero)
399 * @color_stops: (out) (array length=count) (optional): Array of #hb_color_stop_t to populate
401 * Fetches a list of color stops from the given color line object.
403 * Note that due to variations being applied, the returned color stops
404 * may be out of order. It is the callers responsibility to ensure that
405 * color stops are sorted by their offset before they are used.
407 * Return value: the total number of color stops in @color_line
412 hb_color_line_get_color_stops (hb_color_line_t
*color_line
,
415 hb_color_stop_t
*color_stops
)
417 return color_line
->get_color_stops (color_line
,
421 color_line
->get_color_stops_user_data
);
425 * hb_color_line_get_extend:
426 * @color_line: a #hb_color_line_t object
428 * Fetches the extend mode of the color line object.
430 * Return value: the extend mode of @color_line
435 hb_color_line_get_extend (hb_color_line_t
*color_line
)
437 return color_line
->get_extend (color_line
,
439 color_line
->get_extend_user_data
);
444 * hb_paint_push_transform:
445 * @funcs: paint functions
446 * @paint_data: associated data passed by the caller
447 * @xx: xx component of the transform matrix
448 * @yx: yx component of the transform matrix
449 * @xy: xy component of the transform matrix
450 * @yy: yy component of the transform matrix
451 * @dx: dx component of the transform matrix
452 * @dy: dy component of the transform matrix
454 * Perform a "push-transform" paint operation.
459 hb_paint_push_transform (hb_paint_funcs_t
*funcs
, void *paint_data
,
464 funcs
->push_transform (paint_data
, xx
, yx
, xy
, yy
, dx
, dy
);
468 * hb_paint_pop_transform:
469 * @funcs: paint functions
470 * @paint_data: associated data passed by the caller
472 * Perform a "pop-transform" paint operation.
477 hb_paint_pop_transform (hb_paint_funcs_t
*funcs
, void *paint_data
)
479 funcs
->pop_transform (paint_data
);
483 * hb_paint_color_glyph:
484 * @funcs: paint functions
485 * @paint_data: associated data passed by the caller
486 * @glyph: the glyph ID
489 * Perform a "color-glyph" paint operation.
494 hb_paint_color_glyph (hb_paint_funcs_t
*funcs
, void *paint_data
,
495 hb_codepoint_t glyph
,
498 return funcs
->color_glyph (paint_data
, glyph
, font
);
502 * hb_paint_push_clip_glyph:
503 * @funcs: paint functions
504 * @paint_data: associated data passed by the caller
505 * @glyph: the glyph ID
508 * Perform a "push-clip-glyph" paint operation.
513 hb_paint_push_clip_glyph (hb_paint_funcs_t
*funcs
, void *paint_data
,
514 hb_codepoint_t glyph
,
517 funcs
->push_clip_glyph (paint_data
, glyph
, font
);
521 * hb_paint_push_clip_rectangle:
522 * @funcs: paint functions
523 * @paint_data: associated data passed by the caller
524 * @xmin: min X for the rectangle
525 * @ymin: min Y for the rectangle
526 * @xmax: max X for the rectangle
527 * @ymax: max Y for the rectangle
529 * Perform a "push-clip-rect" paint operation.
534 hb_paint_push_clip_rectangle (hb_paint_funcs_t
*funcs
, void *paint_data
,
535 float xmin
, float ymin
, float xmax
, float ymax
)
537 funcs
->push_clip_rectangle (paint_data
, xmin
, ymin
, xmax
, ymax
);
542 * @funcs: paint functions
543 * @paint_data: associated data passed by the caller
545 * Perform a "pop-clip" paint operation.
550 hb_paint_pop_clip (hb_paint_funcs_t
*funcs
, void *paint_data
)
552 funcs
->pop_clip (paint_data
);
557 * @funcs: paint functions
558 * @paint_data: associated data passed by the caller
559 * @is_foreground: whether the color is the foreground
560 * @color: The color to use
562 * Perform a "color" paint operation.
567 hb_paint_color (hb_paint_funcs_t
*funcs
, void *paint_data
,
568 hb_bool_t is_foreground
,
571 funcs
->color (paint_data
, is_foreground
, color
);
576 * @funcs: paint functions
577 * @paint_data: associated data passed by the caller
579 * @width: width of the raster image in pixels, or 0
580 * @height: height of the raster image in pixels, or 0
581 * @format: the image format as a tag
582 * @slant: the synthetic slant ratio to be applied to the image during rendering
583 * @extents: (nullable): the extents of the glyph
585 * Perform a "image" paint operation.
590 hb_paint_image (hb_paint_funcs_t
*funcs
, void *paint_data
,
596 hb_glyph_extents_t
*extents
)
598 funcs
->image (paint_data
, image
, width
, height
, format
, slant
, extents
);
602 * hb_paint_linear_gradient:
603 * @funcs: paint functions
604 * @paint_data: associated data passed by the caller
605 * @color_line: Color information for the gradient
606 * @x0: X coordinate of the first point
607 * @y0: Y coordinate of the first point
608 * @x1: X coordinate of the second point
609 * @y1: Y coordinate of the second point
610 * @x2: X coordinate of the third point
611 * @y2: Y coordinate of the third point
613 * Perform a "linear-gradient" paint operation.
618 hb_paint_linear_gradient (hb_paint_funcs_t
*funcs
, void *paint_data
,
619 hb_color_line_t
*color_line
,
624 funcs
->linear_gradient (paint_data
, color_line
, x0
, y0
, x1
, y1
, x2
, y2
);
628 * hb_paint_radial_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 first circle's center
633 * @y0: Y coordinate of the first circle's center
634 * @r0: radius of the first circle
635 * @x1: X coordinate of the second circle's center
636 * @y1: Y coordinate of the second circle's center
637 * @r1: radius of the second circle
639 * Perform a "radial-gradient" paint operation.
644 hb_paint_radial_gradient (hb_paint_funcs_t
*funcs
, void *paint_data
,
645 hb_color_line_t
*color_line
,
646 float x0
, float y0
, float r0
,
647 float x1
, float y1
, float r1
)
649 funcs
->radial_gradient (paint_data
, color_line
, x0
, y0
, r0
, y1
, x1
, r1
);
653 * hb_paint_sweep_gradient:
654 * @funcs: paint functions
655 * @paint_data: associated data passed by the caller
656 * @color_line: Color information for the gradient
657 * @x0: X coordinate of the circle's center
658 * @y0: Y coordinate of the circle's center
659 * @start_angle: the start angle
660 * @end_angle: the end angle
662 * Perform a "sweep-gradient" paint operation.
667 hb_paint_sweep_gradient (hb_paint_funcs_t
*funcs
, void *paint_data
,
668 hb_color_line_t
*color_line
,
670 float start_angle
, float end_angle
)
672 funcs
->sweep_gradient (paint_data
, color_line
, x0
, y0
, start_angle
, end_angle
);
676 * hb_paint_push_group:
677 * @funcs: paint functions
678 * @paint_data: associated data passed by the caller
680 * Perform a "push-group" paint operation.
685 hb_paint_push_group (hb_paint_funcs_t
*funcs
, void *paint_data
)
687 funcs
->push_group (paint_data
);
691 * hb_paint_pop_group:
692 * @funcs: paint functions
693 * @paint_data: associated data passed by the caller
694 * @mode: the compositing mode to use
696 * Perform a "pop-group" paint operation.
701 hb_paint_pop_group (hb_paint_funcs_t
*funcs
, void *paint_data
,
702 hb_paint_composite_mode_t mode
)
704 funcs
->pop_group (paint_data
, mode
);
708 * hb_paint_custom_palette_color:
709 * @funcs: paint functions
710 * @paint_data: associated data passed by the caller
711 * @color_index: color index
712 * @color: (out): fetched color
714 * Gets the custom palette color for @color_index.
716 * Return value: `true` if found, `false` otherwise
721 hb_paint_custom_palette_color (hb_paint_funcs_t
*funcs
, void *paint_data
,
722 unsigned int color_index
,
725 return funcs
->custom_palette_color (paint_data
, color_index
, color
);