/work/workdir/UnpackedTarball/harfbuzz/src/hb-paint.cc
Line | Count | Source |
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 | | |
46 | | static void |
47 | | hb_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 | 0 | void *user_data) {} |
52 | | |
53 | | static void |
54 | | hb_paint_pop_transform_nil (hb_paint_funcs_t *funcs, void *paint_data, |
55 | 0 | void *user_data) {} |
56 | | |
57 | | static hb_bool_t |
58 | | hb_paint_color_glyph_nil (hb_paint_funcs_t *funcs, void *paint_data, |
59 | | hb_codepoint_t glyph, |
60 | | hb_font_t *font, |
61 | 0 | void *user_data) { return false; } |
62 | | |
63 | | static void |
64 | | hb_paint_push_clip_glyph_nil (hb_paint_funcs_t *funcs, void *paint_data, |
65 | | hb_codepoint_t glyph, |
66 | | hb_font_t *font, |
67 | 0 | void *user_data) {} |
68 | | |
69 | | static void |
70 | | hb_paint_push_clip_rectangle_nil (hb_paint_funcs_t *funcs, void *paint_data, |
71 | | float xmin, float ymin, float xmax, float ymax, |
72 | 0 | void *user_data) {} |
73 | | |
74 | | static hb_draw_funcs_t * |
75 | | hb_paint_push_clip_path_start_nil (hb_paint_funcs_t *funcs, void *paint_data, |
76 | | void **draw_data, |
77 | 0 | void *user_data) { if (draw_data) *draw_data = nullptr; return nullptr; } |
78 | | |
79 | | static void |
80 | | hb_paint_push_clip_path_end_nil (hb_paint_funcs_t *funcs, void *paint_data, |
81 | 0 | void *user_data) {} |
82 | | |
83 | | static void |
84 | | hb_paint_pop_clip_nil (hb_paint_funcs_t *funcs, void *paint_data, |
85 | 0 | void *user_data) {} |
86 | | |
87 | | static void |
88 | | hb_paint_color_nil (hb_paint_funcs_t *funcs, void *paint_data, |
89 | | hb_bool_t is_foreground, |
90 | | hb_color_t color, |
91 | 0 | void *user_data) {} |
92 | | |
93 | | static hb_bool_t |
94 | | hb_paint_image_nil (hb_paint_funcs_t *funcs, void *paint_data, |
95 | | hb_blob_t *image, |
96 | | unsigned int width, |
97 | | unsigned int height, |
98 | | hb_tag_t format, |
99 | | float slant_xy_deprecated, |
100 | | hb_glyph_extents_t *extents, |
101 | 0 | void *user_data) { return false; } |
102 | | |
103 | | static void |
104 | | hb_paint_linear_gradient_nil (hb_paint_funcs_t *funcs, void *paint_data, |
105 | | hb_color_line_t *color_line, |
106 | | float x0, float y0, |
107 | | float x1, float y1, |
108 | | float x2, float y2, |
109 | 0 | void *user_data) {} |
110 | | |
111 | | static void |
112 | | hb_paint_radial_gradient_nil (hb_paint_funcs_t *funcs, void *paint_data, |
113 | | hb_color_line_t *color_line, |
114 | | float x0, float y0, float r0, |
115 | | float x1, float y1, float r1, |
116 | 0 | void *user_data) {} |
117 | | |
118 | | static void |
119 | | hb_paint_sweep_gradient_nil (hb_paint_funcs_t *funcs, void *paint_data, |
120 | | hb_color_line_t *color_line, |
121 | | float x0, float y0, |
122 | | float start_angle, |
123 | | float end_angle, |
124 | 0 | void *user_data) {} |
125 | | |
126 | | static void |
127 | | hb_paint_push_group_nil (hb_paint_funcs_t *funcs, void *paint_data, |
128 | 0 | void *user_data) {} |
129 | | |
130 | | static void |
131 | | hb_paint_push_group_for_nil (hb_paint_funcs_t *funcs, void *paint_data, |
132 | | hb_paint_composite_mode_t mode, |
133 | | void *user_data) |
134 | 0 | { |
135 | 0 | hb_paint_push_group (funcs, paint_data); |
136 | 0 | } |
137 | | |
138 | | static void |
139 | | hb_paint_pop_group_nil (hb_paint_funcs_t *funcs, void *paint_data, |
140 | | hb_paint_composite_mode_t mode, |
141 | 0 | void *user_data) {} |
142 | | |
143 | | static hb_bool_t |
144 | | hb_paint_custom_palette_color_nil (hb_paint_funcs_t *funcs, void *paint_data, |
145 | | unsigned int color_index, |
146 | | hb_color_t *color, |
147 | 0 | void *user_data) { return false; } |
148 | | |
149 | | static bool |
150 | | _hb_paint_funcs_set_preamble (hb_paint_funcs_t *funcs, |
151 | | bool func_is_null, |
152 | | void **user_data, |
153 | | hb_destroy_func_t *destroy) |
154 | 0 | { |
155 | 0 | if (hb_object_is_immutable (funcs)) |
156 | 0 | { |
157 | 0 | if (*destroy) |
158 | 0 | (*destroy) (*user_data); |
159 | 0 | return false; |
160 | 0 | } |
161 | | |
162 | 0 | if (func_is_null) |
163 | 0 | { |
164 | 0 | if (*destroy) |
165 | 0 | (*destroy) (*user_data); |
166 | 0 | *destroy = nullptr; |
167 | 0 | *user_data = nullptr; |
168 | 0 | } |
169 | |
|
170 | 0 | return true; |
171 | 0 | } |
172 | | |
173 | | static bool |
174 | | _hb_paint_funcs_set_middle (hb_paint_funcs_t *funcs, |
175 | | void *user_data, |
176 | | hb_destroy_func_t destroy) |
177 | 0 | { |
178 | 0 | auto destroy_guard = hb_make_scope_guard ([&]() { |
179 | 0 | if (destroy) destroy (user_data); |
180 | 0 | }); |
181 | |
|
182 | 0 | if (user_data && !funcs->user_data) |
183 | 0 | { |
184 | 0 | funcs->user_data = (decltype (funcs->user_data)) hb_calloc (1, sizeof (*funcs->user_data)); |
185 | 0 | if (unlikely (!funcs->user_data)) |
186 | 0 | return false; |
187 | 0 | } |
188 | 0 | if (destroy && !funcs->destroy) |
189 | 0 | { |
190 | 0 | funcs->destroy = (decltype (funcs->destroy)) hb_calloc (1, sizeof (*funcs->destroy)); |
191 | 0 | if (unlikely (!funcs->destroy)) |
192 | 0 | return false; |
193 | 0 | } |
194 | | |
195 | 0 | destroy_guard.release (); |
196 | 0 | return true; |
197 | 0 | } |
198 | | |
199 | | #define HB_PAINT_FUNC_IMPLEMENT(name) \ |
200 | | \ |
201 | | void \ |
202 | | hb_paint_funcs_set_##name##_func (hb_paint_funcs_t *funcs, \ |
203 | | hb_paint_##name##_func_t func, \ |
204 | | void *user_data, \ |
205 | 0 | hb_destroy_func_t destroy) \ |
206 | 0 | { \ |
207 | 0 | if (!_hb_paint_funcs_set_preamble (funcs, !func, &user_data, &destroy)) \ |
208 | 0 | return; \ |
209 | 0 | \ |
210 | 0 | if (funcs->destroy && funcs->destroy->name) \ |
211 | 0 | funcs->destroy->name (!funcs->user_data ? nullptr : funcs->user_data->name);\ |
212 | 0 | \ |
213 | 0 | if (!_hb_paint_funcs_set_middle (funcs, user_data, destroy)) \ |
214 | 0 | return; \ |
215 | 0 | \ |
216 | 0 | if (func) \ |
217 | 0 | funcs->func.name = func; \ |
218 | 0 | else \ |
219 | 0 | funcs->func.name = hb_paint_##name##_nil; \ |
220 | 0 | \ |
221 | 0 | if (funcs->user_data) \ |
222 | 0 | funcs->user_data->name = user_data; \ |
223 | 0 | if (funcs->destroy) \ |
224 | 0 | funcs->destroy->name = destroy; \ |
225 | 0 | } Unexecuted instantiation: hb_paint_funcs_set_push_transform_func Unexecuted instantiation: hb_paint_funcs_set_pop_transform_func Unexecuted instantiation: hb_paint_funcs_set_color_glyph_func Unexecuted instantiation: hb_paint_funcs_set_push_clip_glyph_func Unexecuted instantiation: hb_paint_funcs_set_push_clip_rectangle_func Unexecuted instantiation: hb_paint_funcs_set_push_clip_path_start_func Unexecuted instantiation: hb_paint_funcs_set_push_clip_path_end_func Unexecuted instantiation: hb_paint_funcs_set_pop_clip_func Unexecuted instantiation: hb_paint_funcs_set_color_func Unexecuted instantiation: hb_paint_funcs_set_image_func Unexecuted instantiation: hb_paint_funcs_set_linear_gradient_func Unexecuted instantiation: hb_paint_funcs_set_radial_gradient_func Unexecuted instantiation: hb_paint_funcs_set_sweep_gradient_func Unexecuted instantiation: hb_paint_funcs_set_push_group_func Unexecuted instantiation: hb_paint_funcs_set_push_group_for_func Unexecuted instantiation: hb_paint_funcs_set_pop_group_func Unexecuted instantiation: hb_paint_funcs_set_custom_palette_color_func |
226 | | |
227 | | HB_PAINT_FUNCS_IMPLEMENT_CALLBACKS |
228 | | #undef HB_PAINT_FUNC_IMPLEMENT |
229 | | |
230 | | /** |
231 | | * hb_paint_funcs_create: |
232 | | * |
233 | | * Creates a new #hb_paint_funcs_t structure of paint functions. |
234 | | * |
235 | | * The initial reference count of 1 should be released with hb_paint_funcs_destroy() |
236 | | * when you are done using the #hb_paint_funcs_t. This function never returns |
237 | | * `NULL`. If memory cannot be allocated, a special singleton #hb_paint_funcs_t |
238 | | * object will be returned. |
239 | | * |
240 | | * Returns value: (transfer full): the paint-functions structure |
241 | | * |
242 | | * Since: 7.0.0 |
243 | | */ |
244 | | hb_paint_funcs_t * |
245 | | hb_paint_funcs_create () |
246 | 0 | { |
247 | 0 | hb_paint_funcs_t *funcs; |
248 | 0 | if (unlikely (!(funcs = hb_object_create<hb_paint_funcs_t> ()))) |
249 | 0 | return const_cast<hb_paint_funcs_t *> (&Null (hb_paint_funcs_t)); |
250 | | |
251 | 0 | funcs->func = Null (hb_paint_funcs_t).func; |
252 | |
|
253 | 0 | return funcs; |
254 | 0 | } |
255 | | |
256 | | DEFINE_NULL_INSTANCE (hb_paint_funcs_t) = |
257 | | { |
258 | | HB_OBJECT_HEADER_STATIC, |
259 | | |
260 | | { |
261 | | #define HB_PAINT_FUNC_IMPLEMENT(name) hb_paint_##name##_nil, |
262 | | HB_PAINT_FUNCS_IMPLEMENT_CALLBACKS |
263 | | #undef HB_PAINT_FUNC_IMPLEMENT |
264 | | } |
265 | | }; |
266 | | |
267 | | /** |
268 | | * hb_paint_funcs_get_empty: |
269 | | * |
270 | | * Fetches the singleton empty paint-functions structure. |
271 | | * |
272 | | * Return value: (transfer full): The empty paint-functions structure |
273 | | * |
274 | | * Since: 7.0.0 |
275 | | **/ |
276 | | hb_paint_funcs_t * |
277 | | hb_paint_funcs_get_empty () |
278 | 0 | { |
279 | 0 | return const_cast<hb_paint_funcs_t *> (&Null (hb_paint_funcs_t)); |
280 | 0 | } |
281 | | |
282 | | /** |
283 | | * hb_paint_funcs_reference: (skip) |
284 | | * @funcs: The paint-functions structure |
285 | | * |
286 | | * Increases the reference count on a paint-functions structure. |
287 | | * |
288 | | * This prevents @funcs from being destroyed until a matching |
289 | | * call to hb_paint_funcs_destroy() is made. |
290 | | * |
291 | | * Return value: The paint-functions structure |
292 | | * |
293 | | * Since: 7.0.0 |
294 | | */ |
295 | | hb_paint_funcs_t * |
296 | | hb_paint_funcs_reference (hb_paint_funcs_t *funcs) |
297 | 0 | { |
298 | 0 | return hb_object_reference (funcs); |
299 | 0 | } |
300 | | |
301 | | /** |
302 | | * hb_paint_funcs_destroy: (skip) |
303 | | * @funcs: The paint-functions structure |
304 | | * |
305 | | * Decreases the reference count on a paint-functions structure. |
306 | | * |
307 | | * When the reference count reaches zero, the structure |
308 | | * is destroyed, freeing all memory. |
309 | | * |
310 | | * Since: 7.0.0 |
311 | | */ |
312 | | void |
313 | | hb_paint_funcs_destroy (hb_paint_funcs_t *funcs) |
314 | 0 | { |
315 | 0 | if (!hb_object_destroy (funcs)) return; |
316 | | |
317 | 0 | if (funcs->destroy) |
318 | 0 | { |
319 | 0 | #define HB_PAINT_FUNC_IMPLEMENT(name) \ |
320 | 0 | if (funcs->destroy->name) funcs->destroy->name (!funcs->user_data ? nullptr : funcs->user_data->name); |
321 | 0 | HB_PAINT_FUNCS_IMPLEMENT_CALLBACKS |
322 | 0 | #undef HB_PAINT_FUNC_IMPLEMENT |
323 | 0 | } |
324 | |
|
325 | 0 | hb_free (funcs->destroy); |
326 | 0 | hb_free (funcs->user_data); |
327 | 0 | hb_free (funcs); |
328 | 0 | } |
329 | | |
330 | | /** |
331 | | * hb_paint_funcs_set_user_data: (skip) |
332 | | * @funcs: The paint-functions structure |
333 | | * @key: The user-data key |
334 | | * @data: A pointer to the user data |
335 | | * @destroy: (nullable): A callback to call when @data is not needed anymore |
336 | | * @replace: Whether to replace an existing data with the same key |
337 | | * |
338 | | * Attaches a user-data key/data pair to the specified paint-functions structure. |
339 | | * |
340 | | * Return value: `true` if success, `false` otherwise |
341 | | * |
342 | | * Since: 7.0.0 |
343 | | **/ |
344 | | hb_bool_t |
345 | | hb_paint_funcs_set_user_data (hb_paint_funcs_t *funcs, |
346 | | hb_user_data_key_t *key, |
347 | | void * data, |
348 | | hb_destroy_func_t destroy, |
349 | | hb_bool_t replace) |
350 | 0 | { |
351 | 0 | return hb_object_set_user_data (funcs, key, data, destroy, replace); |
352 | 0 | } |
353 | | |
354 | | /** |
355 | | * hb_paint_funcs_get_user_data: (skip) |
356 | | * @funcs: The paint-functions structure |
357 | | * @key: The user-data key to query |
358 | | * |
359 | | * Fetches the user-data associated with the specified key, |
360 | | * attached to the specified paint-functions structure. |
361 | | * |
362 | | * Return value: (transfer none): A pointer to the user data |
363 | | * |
364 | | * Since: 7.0.0 |
365 | | **/ |
366 | | void * |
367 | | hb_paint_funcs_get_user_data (const hb_paint_funcs_t *funcs, |
368 | | hb_user_data_key_t *key) |
369 | 0 | { |
370 | 0 | return hb_object_get_user_data (funcs, key); |
371 | 0 | } |
372 | | |
373 | | /** |
374 | | * hb_paint_funcs_make_immutable: |
375 | | * @funcs: The paint-functions structure |
376 | | * |
377 | | * Makes a paint-functions structure immutable. |
378 | | * |
379 | | * After this call, all attempts to set one of the callbacks |
380 | | * on @funcs will fail. |
381 | | * |
382 | | * Since: 7.0.0 |
383 | | */ |
384 | | void |
385 | | hb_paint_funcs_make_immutable (hb_paint_funcs_t *funcs) |
386 | 0 | { |
387 | 0 | if (hb_object_is_immutable (funcs)) |
388 | 0 | return; |
389 | | |
390 | 0 | hb_object_make_immutable (funcs); |
391 | 0 | } |
392 | | |
393 | | /** |
394 | | * hb_paint_funcs_is_immutable: |
395 | | * @funcs: The paint-functions structure |
396 | | * |
397 | | * Tests whether a paint-functions structure is immutable. |
398 | | * |
399 | | * Return value: `true` if @funcs is immutable, `false` otherwise |
400 | | * |
401 | | * Since: 7.0.0 |
402 | | */ |
403 | | hb_bool_t |
404 | | hb_paint_funcs_is_immutable (hb_paint_funcs_t *funcs) |
405 | 0 | { |
406 | 0 | return hb_object_is_immutable (funcs); |
407 | 0 | } |
408 | | |
409 | | |
410 | | /** |
411 | | * hb_color_line_get_color_stops: |
412 | | * @color_line: a #hb_color_line_t object |
413 | | * @start: the index of the first color stop to return |
414 | | * @count: (inout) (optional): Input = the maximum number of feature tags to return; |
415 | | * Output = the actual number of feature tags returned (may be zero) |
416 | | * @color_stops: (out) (array length=count) (optional): Array of #hb_color_stop_t to populate |
417 | | * |
418 | | * Fetches a list of color stops from the given color line object. |
419 | | * |
420 | | * Note that due to variations being applied, the returned color stops |
421 | | * may be out of order. It is the callers responsibility to ensure that |
422 | | * color stops are sorted by their offset before they are used. |
423 | | * |
424 | | * Return value: the total number of color stops in @color_line |
425 | | * |
426 | | * Since: 7.0.0 |
427 | | */ |
428 | | unsigned int |
429 | | hb_color_line_get_color_stops (hb_color_line_t *color_line, |
430 | | unsigned int start, |
431 | | unsigned int *count, |
432 | | hb_color_stop_t *color_stops) |
433 | 0 | { |
434 | 0 | return color_line->get_color_stops (color_line, |
435 | 0 | color_line->data, |
436 | 0 | start, count, |
437 | 0 | color_stops, |
438 | 0 | color_line->get_color_stops_user_data); |
439 | 0 | } |
440 | | |
441 | | /** |
442 | | * hb_color_line_get_extend: |
443 | | * @color_line: a #hb_color_line_t object |
444 | | * |
445 | | * Fetches the extend mode of the color line object. |
446 | | * |
447 | | * Return value: the extend mode of @color_line |
448 | | * |
449 | | * Since: 7.0.0 |
450 | | */ |
451 | | hb_paint_extend_t |
452 | | hb_color_line_get_extend (hb_color_line_t *color_line) |
453 | 0 | { |
454 | 0 | return color_line->get_extend (color_line, |
455 | 0 | color_line->data, |
456 | 0 | color_line->get_extend_user_data); |
457 | 0 | } |
458 | | |
459 | | |
460 | | /** |
461 | | * hb_paint_push_transform: |
462 | | * @funcs: paint functions |
463 | | * @paint_data: associated data passed by the caller |
464 | | * @xx: xx component of the transform matrix |
465 | | * @yx: yx component of the transform matrix |
466 | | * @xy: xy component of the transform matrix |
467 | | * @yy: yy component of the transform matrix |
468 | | * @dx: dx component of the transform matrix |
469 | | * @dy: dy component of the transform matrix |
470 | | * |
471 | | * Perform a "push-transform" paint operation. |
472 | | * |
473 | | * Since: 7.0.0 |
474 | | */ |
475 | | void |
476 | | hb_paint_push_transform (hb_paint_funcs_t *funcs, void *paint_data, |
477 | | float xx, float yx, |
478 | | float xy, float yy, |
479 | | float dx, float dy) |
480 | 0 | { |
481 | 0 | funcs->push_transform (paint_data, xx, yx, xy, yy, dx, dy); |
482 | 0 | } |
483 | | |
484 | | /** |
485 | | * hb_paint_push_font_transform: |
486 | | * @funcs: paint functions |
487 | | * @paint_data: associated data passed by the caller |
488 | | * @font: a font |
489 | | * |
490 | | * Push the transform reflecting the font's scale and slant |
491 | | * settings onto the paint functions. |
492 | | * |
493 | | * Since: 11.0.0 |
494 | | */ |
495 | | void |
496 | | hb_paint_push_font_transform (hb_paint_funcs_t *funcs, void *paint_data, |
497 | | const hb_font_t *font) |
498 | 0 | { |
499 | 0 | funcs->push_font_transform (paint_data, font); |
500 | 0 | } |
501 | | |
502 | | /** |
503 | | * hb_paint_push_inverse_font_transform: |
504 | | * @funcs: paint functions |
505 | | * @paint_data: associated data passed by the caller |
506 | | * @font: a font |
507 | | * |
508 | | * Push the inverse of the transform reflecting the font's |
509 | | * scale and slant settings onto the paint functions. |
510 | | * |
511 | | * Since: 11.0.0 |
512 | | */ |
513 | | void |
514 | | hb_paint_push_inverse_font_transform (hb_paint_funcs_t *funcs, void *paint_data, |
515 | | const hb_font_t *font) |
516 | 0 | { |
517 | 0 | funcs->push_inverse_font_transform (paint_data, font); |
518 | 0 | } |
519 | | |
520 | | /** |
521 | | * hb_paint_pop_transform: |
522 | | * @funcs: paint functions |
523 | | * @paint_data: associated data passed by the caller |
524 | | * |
525 | | * Perform a "pop-transform" paint operation. |
526 | | * |
527 | | * Since: 7.0.0 |
528 | | */ |
529 | | void |
530 | | hb_paint_pop_transform (hb_paint_funcs_t *funcs, void *paint_data) |
531 | 0 | { |
532 | 0 | funcs->pop_transform (paint_data); |
533 | 0 | } |
534 | | |
535 | | /** |
536 | | * hb_paint_color_glyph: |
537 | | * @funcs: paint functions |
538 | | * @paint_data: associated data passed by the caller |
539 | | * @glyph: the glyph ID |
540 | | * @font: the font |
541 | | * |
542 | | * Perform a "color-glyph" paint operation. |
543 | | * |
544 | | * Since: 8.2.0 |
545 | | */ |
546 | | hb_bool_t |
547 | | hb_paint_color_glyph (hb_paint_funcs_t *funcs, void *paint_data, |
548 | | hb_codepoint_t glyph, |
549 | | hb_font_t *font) |
550 | 0 | { |
551 | 0 | return funcs->color_glyph (paint_data, glyph, font); |
552 | 0 | } |
553 | | |
554 | | /** |
555 | | * hb_paint_push_clip_glyph: |
556 | | * @funcs: paint functions |
557 | | * @paint_data: associated data passed by the caller |
558 | | * @glyph: the glyph ID |
559 | | * @font: the font |
560 | | * |
561 | | * Perform a "push-clip-glyph" paint operation. |
562 | | * |
563 | | * Since: 7.0.0 |
564 | | */ |
565 | | void |
566 | | hb_paint_push_clip_glyph (hb_paint_funcs_t *funcs, void *paint_data, |
567 | | hb_codepoint_t glyph, |
568 | | hb_font_t *font) |
569 | 0 | { |
570 | 0 | funcs->push_clip_glyph (paint_data, glyph, font); |
571 | 0 | } |
572 | | |
573 | | /** |
574 | | * hb_paint_push_clip_rectangle: |
575 | | * @funcs: paint functions |
576 | | * @paint_data: associated data passed by the caller |
577 | | * @xmin: min X for the rectangle |
578 | | * @ymin: min Y for the rectangle |
579 | | * @xmax: max X for the rectangle |
580 | | * @ymax: max Y for the rectangle |
581 | | * |
582 | | * Perform a "push-clip-rect" paint operation. |
583 | | * |
584 | | * Since: 7.0.0 |
585 | | */ |
586 | | void |
587 | | hb_paint_push_clip_rectangle (hb_paint_funcs_t *funcs, void *paint_data, |
588 | | float xmin, float ymin, float xmax, float ymax) |
589 | 0 | { |
590 | 0 | funcs->push_clip_rectangle (paint_data, xmin, ymin, xmax, ymax); |
591 | 0 | } |
592 | | |
593 | | /** |
594 | | * hb_paint_push_clip_path_start: |
595 | | * @funcs: paint functions |
596 | | * @paint_data: associated data passed by the caller |
597 | | * @draw_data: (out) (nullable): location to receive the draw data |
598 | | * the caller should pass alongside the returned draw funcs. |
599 | | * |
600 | | * Begin clipping to an arbitrary path. Returns an |
601 | | * #hb_draw_funcs_t owned by the backend (the caller must not |
602 | | * free it) that the caller uses to emit the clip outline via |
603 | | * hb_draw_*() calls, using the returned @draw_data as the |
604 | | * draw data. The returned draw funcs and draw data are only |
605 | | * valid until the matching hb_paint_push_clip_path_end() call; |
606 | | * no other paint calls should be made between start and end |
607 | | * except hb_draw_*() on the returned funcs. Finish the path |
608 | | * with hb_paint_push_clip_path_end(); pop the clip later |
609 | | * with hb_paint_pop_clip(). |
610 | | * |
611 | | * Usage: |
612 | | * |
613 | | * |[<!-- language="plain" --> |
614 | | * hb_draw_funcs_t *df = hb_paint_push_clip_path_start (pf, pd, &dd); |
615 | | * hb_draw_move_to (df, dd, NULL, ...); |
616 | | * hb_draw_line_to (df, dd, NULL, ...); |
617 | | * ... |
618 | | * hb_draw_close_path (df, dd, NULL); |
619 | | * hb_paint_push_clip_path_end (pf, pd); |
620 | | * /* paint ops here are clipped to the emitted path */ |
621 | | * hb_paint_pop_clip (pf, pd); |
622 | | * ]| |
623 | | * |
624 | | * Return value: (transfer none): draw funcs that accumulate |
625 | | * the clip path, or `NULL` if the backend does not implement |
626 | | * arbitrary-path clipping. |
627 | | * |
628 | | * Since: 14.2.0 |
629 | | */ |
630 | | hb_draw_funcs_t * |
631 | | hb_paint_push_clip_path_start (hb_paint_funcs_t *funcs, |
632 | | void *paint_data, |
633 | | void **draw_data) |
634 | 0 | { |
635 | 0 | void *scratch = nullptr; |
636 | 0 | if (!draw_data) draw_data = &scratch; |
637 | 0 | return funcs->push_clip_path_start (paint_data, draw_data); |
638 | 0 | } |
639 | | |
640 | | /** |
641 | | * hb_paint_push_clip_path_end: |
642 | | * @funcs: paint functions |
643 | | * @paint_data: associated data passed by the caller |
644 | | * |
645 | | * Signal that the arbitrary-clip path started by |
646 | | * hb_paint_push_clip_path_start() is fully drawn. The |
647 | | * accumulated path now acts as a clip on the paint context |
648 | | * until a matching hb_paint_pop_clip() call. |
649 | | * |
650 | | * Since: 14.2.0 |
651 | | */ |
652 | | void |
653 | | hb_paint_push_clip_path_end (hb_paint_funcs_t *funcs, void *paint_data) |
654 | 0 | { |
655 | 0 | funcs->push_clip_path_end (paint_data); |
656 | 0 | } |
657 | | |
658 | | /** |
659 | | * hb_paint_pop_clip: |
660 | | * @funcs: paint functions |
661 | | * @paint_data: associated data passed by the caller |
662 | | * |
663 | | * Perform a "pop-clip" paint operation. |
664 | | * |
665 | | * Since: 7.0.0 |
666 | | */ |
667 | | void |
668 | | hb_paint_pop_clip (hb_paint_funcs_t *funcs, void *paint_data) |
669 | 0 | { |
670 | 0 | funcs->pop_clip (paint_data); |
671 | 0 | } |
672 | | |
673 | | /** |
674 | | * hb_paint_color: |
675 | | * @funcs: paint functions |
676 | | * @paint_data: associated data passed by the caller |
677 | | * @is_foreground: whether the color is the foreground |
678 | | * @color: The color to use |
679 | | * |
680 | | * Perform a "color" paint operation. |
681 | | * |
682 | | * Since: 7.0.0 |
683 | | */ |
684 | | void |
685 | | hb_paint_color (hb_paint_funcs_t *funcs, void *paint_data, |
686 | | hb_bool_t is_foreground, |
687 | | hb_color_t color) |
688 | 0 | { |
689 | 0 | funcs->color (paint_data, is_foreground, color); |
690 | 0 | } |
691 | | |
692 | | /** |
693 | | * hb_paint_image: |
694 | | * @funcs: paint functions |
695 | | * @paint_data: associated data passed by the caller |
696 | | * @image: image data |
697 | | * @width: width of the raster image in pixels, or 0 |
698 | | * @height: height of the raster image in pixels, or 0 |
699 | | * @format: the image format as a tag |
700 | | * @slant: Deprecated. set to 0.0 |
701 | | * @extents: (nullable): the extents of the glyph |
702 | | * |
703 | | * Perform a "image" paint operation. |
704 | | * |
705 | | * Since: 7.0.0 |
706 | | */ |
707 | | void |
708 | | hb_paint_image (hb_paint_funcs_t *funcs, void *paint_data, |
709 | | hb_blob_t *image, |
710 | | unsigned int width, |
711 | | unsigned int height, |
712 | | hb_tag_t format, |
713 | | HB_UNUSED float slant, |
714 | | hb_glyph_extents_t *extents) |
715 | 0 | { |
716 | 0 | funcs->image (paint_data, image, width, height, format, 0.f, extents); |
717 | 0 | } |
718 | | |
719 | | /** |
720 | | * hb_paint_linear_gradient: |
721 | | * @funcs: paint functions |
722 | | * @paint_data: associated data passed by the caller |
723 | | * @color_line: Color information for the gradient |
724 | | * @x0: X coordinate of the first point |
725 | | * @y0: Y coordinate of the first point |
726 | | * @x1: X coordinate of the second point |
727 | | * @y1: Y coordinate of the second point |
728 | | * @x2: X coordinate of the third point |
729 | | * @y2: Y coordinate of the third point |
730 | | * |
731 | | * Perform a "linear-gradient" paint operation. |
732 | | * |
733 | | * Since: 7.0.0 |
734 | | */ |
735 | | void |
736 | | hb_paint_linear_gradient (hb_paint_funcs_t *funcs, void *paint_data, |
737 | | hb_color_line_t *color_line, |
738 | | float x0, float y0, |
739 | | float x1, float y1, |
740 | | float x2, float y2) |
741 | 0 | { |
742 | 0 | funcs->linear_gradient (paint_data, color_line, x0, y0, x1, y1, x2, y2); |
743 | 0 | } |
744 | | |
745 | | /** |
746 | | * hb_paint_radial_gradient: |
747 | | * @funcs: paint functions |
748 | | * @paint_data: associated data passed by the caller |
749 | | * @color_line: Color information for the gradient |
750 | | * @x0: X coordinate of the first circle's center |
751 | | * @y0: Y coordinate of the first circle's center |
752 | | * @r0: radius of the first circle |
753 | | * @x1: X coordinate of the second circle's center |
754 | | * @y1: Y coordinate of the second circle's center |
755 | | * @r1: radius of the second circle |
756 | | * |
757 | | * Perform a "radial-gradient" paint operation. |
758 | | * |
759 | | * Since: 7.0.0 |
760 | | */ |
761 | | void |
762 | | hb_paint_radial_gradient (hb_paint_funcs_t *funcs, void *paint_data, |
763 | | hb_color_line_t *color_line, |
764 | | float x0, float y0, float r0, |
765 | | float x1, float y1, float r1) |
766 | 0 | { |
767 | 0 | funcs->radial_gradient (paint_data, color_line, x0, y0, r0, x1, y1, r1); |
768 | 0 | } |
769 | | |
770 | | /** |
771 | | * hb_paint_sweep_gradient: |
772 | | * @funcs: paint functions |
773 | | * @paint_data: associated data passed by the caller |
774 | | * @color_line: Color information for the gradient |
775 | | * @x0: X coordinate of the circle's center |
776 | | * @y0: Y coordinate of the circle's center |
777 | | * @start_angle: the start angle |
778 | | * @end_angle: the end angle |
779 | | * |
780 | | * Perform a "sweep-gradient" paint operation. |
781 | | * |
782 | | * Since: 7.0.0 |
783 | | */ |
784 | | void |
785 | | hb_paint_sweep_gradient (hb_paint_funcs_t *funcs, void *paint_data, |
786 | | hb_color_line_t *color_line, |
787 | | float x0, float y0, |
788 | | float start_angle, float end_angle) |
789 | 0 | { |
790 | 0 | funcs->sweep_gradient (paint_data, color_line, x0, y0, start_angle, end_angle); |
791 | 0 | } |
792 | | |
793 | | /** |
794 | | * hb_paint_push_group: |
795 | | * @funcs: paint functions |
796 | | * @paint_data: associated data passed by the caller |
797 | | * |
798 | | * Perform a "push-group" paint operation. |
799 | | * |
800 | | * Since: 7.0.0 |
801 | | */ |
802 | | void |
803 | | hb_paint_push_group (hb_paint_funcs_t *funcs, void *paint_data) |
804 | 0 | { |
805 | 0 | funcs->push_group (paint_data); |
806 | 0 | } |
807 | | |
808 | | /** |
809 | | * hb_paint_push_group_for: |
810 | | * @funcs: paint functions |
811 | | * @paint_data: associated data passed by the caller |
812 | | * @mode: the compositing mode that will be used when the group is popped |
813 | | * |
814 | | * Perform a "push-group" paint operation, with the compositing |
815 | | * mode known in advance. By default, this calls |
816 | | * hb_paint_push_group(). |
817 | | * |
818 | | * Since: 14.2.0 |
819 | | */ |
820 | | void |
821 | | hb_paint_push_group_for (hb_paint_funcs_t *funcs, void *paint_data, |
822 | | hb_paint_composite_mode_t mode) |
823 | 0 | { |
824 | 0 | funcs->push_group_for (paint_data, mode); |
825 | 0 | } |
826 | | |
827 | | /** |
828 | | * hb_paint_pop_group: |
829 | | * @funcs: paint functions |
830 | | * @paint_data: associated data passed by the caller |
831 | | * @mode: the compositing mode to use |
832 | | * |
833 | | * Perform a "pop-group" paint operation. |
834 | | * |
835 | | * Since: 7.0.0 |
836 | | */ |
837 | | void |
838 | | hb_paint_pop_group (hb_paint_funcs_t *funcs, void *paint_data, |
839 | | hb_paint_composite_mode_t mode) |
840 | 0 | { |
841 | 0 | funcs->pop_group (paint_data, mode); |
842 | 0 | } |
843 | | |
844 | | /** |
845 | | * hb_paint_custom_palette_color: |
846 | | * @funcs: paint functions. |
847 | | * @paint_data: associated data passed by the caller. |
848 | | * @color_index: color index to fetch. |
849 | | * @color: (out): fetched color. |
850 | | * |
851 | | * Gets the custom palette override color for @color_index. |
852 | | * |
853 | | * Return value: `true` if a custom color is provided, `false` otherwise. |
854 | | * |
855 | | * Since: 7.0.0 |
856 | | */ |
857 | | hb_bool_t |
858 | | hb_paint_custom_palette_color (hb_paint_funcs_t *funcs, void *paint_data, |
859 | | unsigned int color_index, |
860 | | hb_color_t *color) |
861 | 0 | { |
862 | 0 | return funcs->custom_palette_color (paint_data, color_index, color); |
863 | 0 | } |
864 | | |
865 | | |
866 | | /** |
867 | | * hb_paint_reduce_linear_anchors: |
868 | | * @x0: x coordinate of P0 (color stop 0). |
869 | | * @y0: y coordinate of P0 (color stop 0). |
870 | | * @x1: x coordinate of P1 (color stop 1). |
871 | | * @y1: y coordinate of P1 (color stop 1). |
872 | | * @x2: x coordinate of P2 (rotation reference). |
873 | | * @y2: y coordinate of P2 (rotation reference). |
874 | | * @xx0: (out): x coordinate of the resulting axis start. |
875 | | * @yy0: (out): y coordinate of the resulting axis start. |
876 | | * @xx1: (out): x coordinate of the resulting axis end. |
877 | | * @yy1: (out): y coordinate of the resulting axis end. |
878 | | * |
879 | | * Reduces a COLRv1 linear gradient's 3-anchor spec (P0=color |
880 | | * stop 0, P1=color stop 1, P2=rotation reference) to the |
881 | | * 2-point axis (P0, P1') used by SVG / cairo / most software |
882 | | * renderers. P1' is the foot of P1 on the line through P0 |
883 | | * perpendicular to (P2 - P0); the resulting axis is the |
884 | | * gradient's actual direction (perpendicular to the rotation |
885 | | * line). Degenerate (P0 == P2) passes through unchanged. |
886 | | * |
887 | | * Since: 14.2.0 |
888 | | **/ |
889 | | void |
890 | | hb_paint_reduce_linear_anchors (float x0, float y0, |
891 | | float x1, float y1, |
892 | | float x2, float y2, |
893 | | float *xx0, float *yy0, |
894 | | float *xx1, float *yy1) |
895 | 0 | { |
896 | 0 | float q2x = x2 - x0, q2y = y2 - y0; |
897 | 0 | float s = q2x * q2x + q2y * q2y; |
898 | 0 | if (s < 1e-6f) |
899 | 0 | { |
900 | 0 | *xx0 = x0; *yy0 = y0; |
901 | 0 | *xx1 = x1; *yy1 = y1; |
902 | 0 | return; |
903 | 0 | } |
904 | 0 | float q1x = x1 - x0, q1y = y1 - y0; |
905 | 0 | float k = (q2x * q1x + q2y * q1y) / s; |
906 | 0 | *xx0 = x0; |
907 | 0 | *yy0 = y0; |
908 | 0 | *xx1 = x1 - k * q2x; |
909 | 0 | *yy1 = y1 - k * q2y; |
910 | 0 | } |
911 | | |
912 | | /** |
913 | | * hb_paint_normalize_color_line: |
914 | | * @stops: (array length=len) (inout): color stops. |
915 | | * @len: number of stops. |
916 | | * @min: (out): original minimum offset. |
917 | | * @max: (out): original maximum offset. |
918 | | * |
919 | | * Sorts @stops by offset and rescales offsets into [0, 1] in |
920 | | * place. Writes the original (min, max) to @min / @max so the |
921 | | * caller can shift the gradient geometry (axis endpoints for |
922 | | * linear, centers+radii for radial, start+end angles for sweep) |
923 | | * to keep the rendered gradient visually unchanged after the |
924 | | * rescale. Empty input is safe: both out-parameters set to 0. |
925 | | * |
926 | | * Since: 14.2.0 |
927 | | **/ |
928 | | void |
929 | | hb_paint_normalize_color_line (hb_color_stop_t *stops, |
930 | | unsigned int len, |
931 | | float *min, |
932 | | float *max) |
933 | 0 | { |
934 | 0 | if (unlikely (!len)) |
935 | 0 | { |
936 | 0 | *min = *max = 0.f; |
937 | 0 | return; |
938 | 0 | } |
939 | | |
940 | 0 | hb_array_t<hb_color_stop_t> (stops, len) |
941 | 0 | .qsort ([] (const hb_color_stop_t &a, const hb_color_stop_t &b) { |
942 | 0 | return a.offset < b.offset; |
943 | 0 | }); |
944 | |
|
945 | 0 | float mn = stops[0].offset, mx = stops[0].offset; |
946 | 0 | for (unsigned i = 1; i < len; i++) |
947 | 0 | { |
948 | 0 | mn = hb_min (mn, stops[i].offset); |
949 | 0 | mx = hb_max (mx, stops[i].offset); |
950 | 0 | } |
951 | 0 | if (mn != mx) |
952 | 0 | for (unsigned i = 0; i < len; i++) |
953 | 0 | stops[i].offset = (stops[i].offset - mn) / (mx - mn); |
954 | |
|
955 | 0 | *min = mn; |
956 | 0 | *max = mx; |
957 | 0 | } |
958 | | |
959 | | /** |
960 | | * hb_paint_sweep_gradient_tiles: |
961 | | * @stops: (array length=n_stops) (inout): color stops (sorted, offsets in [0,1]). |
962 | | * @n_stops: number of stops. |
963 | | * @extend: extend mode. |
964 | | * @start_angle: sweep start angle, in radians. |
965 | | * @end_angle: sweep end angle, in radians. |
966 | | * @emit_patch: (scope call): callback invoked once per tile. |
967 | | * @user_data: data passed to @emit_patch. |
968 | | * |
969 | | * Iterates the full 0..2π sweep produced by a color-stop list, |
970 | | * invoking @emit_patch once per (start, end) angular segment. |
971 | | * Handles #HB_PAINT_EXTEND_PAD, #HB_PAINT_EXTEND_REPEAT, and |
972 | | * #HB_PAINT_EXTEND_REFLECT. Stops must be pre-sorted by |
973 | | * offset; use hb_paint_normalize_color_line() first if they |
974 | | * aren't. |
975 | | * |
976 | | * Since: 14.2.0 |
977 | | **/ |
978 | | void |
979 | | hb_paint_sweep_gradient_tiles (hb_color_stop_t *stops, |
980 | | unsigned int n_stops, |
981 | | hb_paint_extend_t extend, |
982 | | float start_angle, |
983 | | float end_angle, |
984 | | hb_paint_sweep_gradient_tile_func_t emit_patch, |
985 | | void *user_data) |
986 | 0 | { |
987 | 0 | if (!n_stops) return; |
988 | | |
989 | 0 | if (start_angle == end_angle) |
990 | 0 | { |
991 | 0 | if (extend == HB_PAINT_EXTEND_PAD) |
992 | 0 | { |
993 | 0 | if (start_angle > 0.f) |
994 | 0 | emit_patch (0.f, stops[0].color, start_angle, stops[0].color, user_data); |
995 | 0 | if (end_angle < HB_2_PI) |
996 | 0 | emit_patch (end_angle, stops[n_stops - 1].color, HB_2_PI, stops[n_stops - 1].color, user_data); |
997 | 0 | } |
998 | 0 | return; |
999 | 0 | } |
1000 | | |
1001 | 0 | if (end_angle < start_angle) |
1002 | 0 | { |
1003 | 0 | float tmp = start_angle; start_angle = end_angle; end_angle = tmp; |
1004 | 0 | for (unsigned i = 0; i < n_stops - 1 - i; i++) |
1005 | 0 | { |
1006 | 0 | hb_color_stop_t t = stops[i]; |
1007 | 0 | stops[i] = stops[n_stops - 1 - i]; |
1008 | 0 | stops[n_stops - 1 - i] = t; |
1009 | 0 | } |
1010 | 0 | for (unsigned i = 0; i < n_stops; i++) |
1011 | 0 | stops[i].offset = 1.f - stops[i].offset; |
1012 | 0 | } |
1013 | | |
1014 | | /* Map stop offsets to angles. */ |
1015 | 0 | float angles_buf[16]; |
1016 | 0 | hb_color_t colors_buf[16]; |
1017 | 0 | float *angles = angles_buf; |
1018 | 0 | hb_color_t *colors = colors_buf; |
1019 | 0 | bool dynamic = false; |
1020 | |
|
1021 | 0 | if (n_stops > 16) |
1022 | 0 | { |
1023 | 0 | angles = (float *) hb_malloc (sizeof (float) * n_stops); |
1024 | 0 | colors = (hb_color_t *) hb_malloc (sizeof (hb_color_t) * n_stops); |
1025 | 0 | if (!angles || !colors) |
1026 | 0 | { |
1027 | 0 | hb_free (angles); |
1028 | 0 | hb_free (colors); |
1029 | 0 | return; |
1030 | 0 | } |
1031 | 0 | dynamic = true; |
1032 | 0 | } |
1033 | | |
1034 | 0 | for (unsigned i = 0; i < n_stops; i++) |
1035 | 0 | { |
1036 | 0 | angles[i] = start_angle + stops[i].offset * (end_angle - start_angle); |
1037 | 0 | colors[i] = stops[i].color; |
1038 | 0 | } |
1039 | |
|
1040 | 0 | if (extend == HB_PAINT_EXTEND_PAD) |
1041 | 0 | { |
1042 | 0 | unsigned pos; |
1043 | 0 | hb_color_t color0 = colors[0]; |
1044 | 0 | for (pos = 0; pos < n_stops; pos++) |
1045 | 0 | { |
1046 | 0 | if (angles[pos] >= 0) |
1047 | 0 | { |
1048 | 0 | if (pos > 0) |
1049 | 0 | { |
1050 | 0 | float f = (0.f - angles[pos - 1]) / (angles[pos] - angles[pos - 1]); |
1051 | 0 | color0 = hb_color_lerp (colors[pos - 1], colors[pos], f); |
1052 | 0 | } |
1053 | 0 | break; |
1054 | 0 | } |
1055 | 0 | } |
1056 | 0 | if (pos == n_stops) |
1057 | 0 | { |
1058 | 0 | color0 = colors[n_stops - 1]; |
1059 | 0 | emit_patch (0.f, color0, HB_2_PI, color0, user_data); |
1060 | 0 | goto done; |
1061 | 0 | } |
1062 | 0 | emit_patch (0.f, color0, angles[pos], colors[pos], user_data); |
1063 | 0 | for (pos++; pos < n_stops; pos++) |
1064 | 0 | { |
1065 | 0 | if (angles[pos] <= HB_2_PI) |
1066 | 0 | emit_patch (angles[pos - 1], colors[pos - 1], angles[pos], colors[pos], user_data); |
1067 | 0 | else |
1068 | 0 | { |
1069 | 0 | float f = (HB_2_PI - angles[pos - 1]) / (angles[pos] - angles[pos - 1]); |
1070 | 0 | hb_color_t color1 = hb_color_lerp (colors[pos - 1], colors[pos], f); |
1071 | 0 | emit_patch (angles[pos - 1], colors[pos - 1], HB_2_PI, color1, user_data); |
1072 | 0 | break; |
1073 | 0 | } |
1074 | 0 | } |
1075 | 0 | if (pos == n_stops) |
1076 | 0 | { |
1077 | 0 | color0 = colors[n_stops - 1]; |
1078 | 0 | emit_patch (angles[n_stops - 1], color0, HB_2_PI, color0, user_data); |
1079 | 0 | goto done; |
1080 | 0 | } |
1081 | 0 | } |
1082 | 0 | else |
1083 | 0 | { |
1084 | 0 | float span = angles[n_stops - 1] - angles[0]; |
1085 | 0 | if (fabsf (span) < 1e-6f) |
1086 | 0 | goto done; |
1087 | | |
1088 | 0 | int k = 0; |
1089 | 0 | if (angles[0] >= 0) |
1090 | 0 | { |
1091 | 0 | float ss = angles[0]; |
1092 | 0 | while (ss > 0) |
1093 | 0 | { |
1094 | 0 | if (span > 0) { ss -= span; k--; } |
1095 | 0 | else { ss += span; k++; } |
1096 | 0 | } |
1097 | 0 | } |
1098 | 0 | else |
1099 | 0 | { |
1100 | 0 | float ee = angles[n_stops - 1]; |
1101 | 0 | while (ee < 0) |
1102 | 0 | { |
1103 | 0 | if (span > 0) { ee += span; k++; } |
1104 | 0 | else { ee -= span; k--; } |
1105 | 0 | } |
1106 | 0 | } |
1107 | |
|
1108 | 0 | span = fabsf (span); |
1109 | 0 | for (int l = k; l < 1000; l++) |
1110 | 0 | { |
1111 | 0 | for (unsigned i = 1; i < n_stops; i++) |
1112 | 0 | { |
1113 | 0 | float a0_l, a1_l; |
1114 | 0 | hb_color_t col0, col1; |
1115 | 0 | if ((l % 2 != 0) && (extend == HB_PAINT_EXTEND_REFLECT)) |
1116 | 0 | { |
1117 | 0 | a0_l = angles[0] + angles[n_stops - 1] - angles[n_stops - i] + l * span; |
1118 | 0 | a1_l = angles[0] + angles[n_stops - 1] - angles[n_stops - 1 - i] + l * span; |
1119 | 0 | col0 = colors[n_stops - i]; |
1120 | 0 | col1 = colors[n_stops - 1 - i]; |
1121 | 0 | } |
1122 | 0 | else |
1123 | 0 | { |
1124 | 0 | a0_l = angles[i - 1] + l * span; |
1125 | 0 | a1_l = angles[i] + l * span; |
1126 | 0 | col0 = colors[i - 1]; |
1127 | 0 | col1 = colors[i]; |
1128 | 0 | } |
1129 | |
|
1130 | 0 | if (a1_l < 0.f) continue; |
1131 | 0 | if (a0_l < 0.f) |
1132 | 0 | { |
1133 | 0 | float f = (0.f - a0_l) / (a1_l - a0_l); |
1134 | 0 | hb_color_t c = hb_color_lerp (col0, col1, f); |
1135 | 0 | emit_patch (0.f, c, a1_l, col1, user_data); |
1136 | 0 | } |
1137 | 0 | else if (a1_l >= HB_2_PI) |
1138 | 0 | { |
1139 | 0 | float f = (HB_2_PI - a0_l) / (a1_l - a0_l); |
1140 | 0 | hb_color_t c = hb_color_lerp (col0, col1, f); |
1141 | 0 | emit_patch (a0_l, col0, HB_2_PI, c, user_data); |
1142 | 0 | goto done; |
1143 | 0 | } |
1144 | 0 | else |
1145 | 0 | emit_patch (a0_l, col0, a1_l, col1, user_data); |
1146 | 0 | } |
1147 | 0 | } |
1148 | 0 | } |
1149 | | |
1150 | 0 | done: |
1151 | 0 | if (dynamic) |
1152 | 0 | { |
1153 | 0 | hb_free (angles); |
1154 | 0 | hb_free (colors); |
1155 | 0 | } |
1156 | 0 | } |
1157 | | |
1158 | | #endif |