1/*
2 * Copyright © 2022 Behdad Esfahbod
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-extents.hh"
30
31#include "hb-draw.h"
32
33#include "hb-machinery.hh"
34
35
36/*
37 * This file implements bounds-extraction as well as boundedness
38 * computation of COLRv1 fonts as described in:
39 *
40 * https://learn.microsoft.com/en-us/typography/opentype/spec/colr#glyph-metrics-and-boundedness
41 */
42
43static void
44hb_paint_extents_push_transform (hb_paint_funcs_t *funcs HB_UNUSED,
45 void *paint_data,
46 float xx, float yx,
47 float xy, float yy,
48 float dx, float dy,
49 void *user_data HB_UNUSED)
50{
51 hb_paint_extents_context_t *c = (hb_paint_extents_context_t *) paint_data;
52
53 c->push_transform (hb_transform_t {xx, yx, xy, yy, dx, dy});
54}
55
56static void
57hb_paint_extents_pop_transform (hb_paint_funcs_t *funcs HB_UNUSED,
58 void *paint_data,
59 void *user_data HB_UNUSED)
60{
61 hb_paint_extents_context_t *c = (hb_paint_extents_context_t *) paint_data;
62
63 c->pop_transform ();
64}
65
66static void
67hb_draw_extents_move_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
68 void *data,
69 hb_draw_state_t *st,
70 float to_x, float to_y,
71 void *user_data HB_UNUSED)
72{
73 hb_extents_t *extents = (hb_extents_t *) data;
74
75 extents->add_point (to_x, to_y);
76}
77
78static void
79hb_draw_extents_line_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
80 void *data,
81 hb_draw_state_t *st,
82 float to_x, float to_y,
83 void *user_data HB_UNUSED)
84{
85 hb_extents_t *extents = (hb_extents_t *) data;
86
87 extents->add_point (to_x, to_y);
88}
89
90static void
91hb_draw_extents_quadratic_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
92 void *data,
93 hb_draw_state_t *st,
94 float control_x, float control_y,
95 float to_x, float to_y,
96 void *user_data HB_UNUSED)
97{
98 hb_extents_t *extents = (hb_extents_t *) data;
99
100 extents->add_point (control_x, control_y);
101 extents->add_point (to_x, to_y);
102}
103
104static void
105hb_draw_extents_cubic_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
106 void *data,
107 hb_draw_state_t *st,
108 float control1_x, float control1_y,
109 float control2_x, float control2_y,
110 float to_x, float to_y,
111 void *user_data HB_UNUSED)
112{
113 hb_extents_t *extents = (hb_extents_t *) data;
114
115 extents->add_point (control1_x, control1_y);
116 extents->add_point (control2_x, control2_y);
117 extents->add_point (to_x, to_y);
118}
119
120static inline void free_static_draw_extents_funcs ();
121
122static struct hb_draw_extents_funcs_lazy_loader_t : hb_draw_funcs_lazy_loader_t<hb_draw_extents_funcs_lazy_loader_t>
123{
124 static hb_draw_funcs_t *create ()
125 {
126 hb_draw_funcs_t *funcs = hb_draw_funcs_create ();
127
128 hb_draw_funcs_set_move_to_func (funcs, hb_draw_extents_move_to, nullptr, nullptr);
129 hb_draw_funcs_set_line_to_func (funcs, hb_draw_extents_line_to, nullptr, nullptr);
130 hb_draw_funcs_set_quadratic_to_func (funcs, hb_draw_extents_quadratic_to, nullptr, nullptr);
131 hb_draw_funcs_set_cubic_to_func (funcs, hb_draw_extents_cubic_to, nullptr, nullptr);
132
133 hb_draw_funcs_make_immutable (funcs);
134
135 hb_atexit (free_static_draw_extents_funcs);
136
137 return funcs;
138 }
139} static_draw_extents_funcs;
140
141static inline
142void free_static_draw_extents_funcs ()
143{
144 static_draw_extents_funcs.free_instance ();
145}
146
147static hb_draw_funcs_t *
148hb_draw_extents_get_funcs ()
149{
150 return static_draw_extents_funcs.get_unconst ();
151}
152
153static void
154hb_paint_extents_push_clip_glyph (hb_paint_funcs_t *funcs HB_UNUSED,
155 void *paint_data,
156 hb_codepoint_t glyph,
157 hb_font_t *font,
158 void *user_data HB_UNUSED)
159{
160 hb_paint_extents_context_t *c = (hb_paint_extents_context_t *) paint_data;
161
162 hb_extents_t extents;
163 hb_draw_funcs_t *draw_extent_funcs = hb_draw_extents_get_funcs ();
164 hb_font_draw_glyph (font, glyph, draw_extent_funcs, &extents);
165 c->push_clip (extents);
166}
167
168static void
169hb_paint_extents_push_clip_rectangle (hb_paint_funcs_t *funcs HB_UNUSED,
170 void *paint_data,
171 float xmin, float ymin, float xmax, float ymax,
172 void *user_data)
173{
174 hb_paint_extents_context_t *c = (hb_paint_extents_context_t *) paint_data;
175
176 hb_extents_t extents = {xmin, ymin, xmax, ymax};
177 c->push_clip (extents);
178}
179
180static void
181hb_paint_extents_pop_clip (hb_paint_funcs_t *funcs HB_UNUSED,
182 void *paint_data,
183 void *user_data HB_UNUSED)
184{
185 hb_paint_extents_context_t *c = (hb_paint_extents_context_t *) paint_data;
186
187 c->pop_clip ();
188}
189
190static void
191hb_paint_extents_push_group (hb_paint_funcs_t *funcs HB_UNUSED,
192 void *paint_data,
193 void *user_data HB_UNUSED)
194{
195 hb_paint_extents_context_t *c = (hb_paint_extents_context_t *) paint_data;
196
197 c->push_group ();
198}
199
200static void
201hb_paint_extents_pop_group (hb_paint_funcs_t *funcs HB_UNUSED,
202 void *paint_data,
203 hb_paint_composite_mode_t mode,
204 void *user_data HB_UNUSED)
205{
206 hb_paint_extents_context_t *c = (hb_paint_extents_context_t *) paint_data;
207
208 c->pop_group (mode);
209}
210
211static hb_bool_t
212hb_paint_extents_paint_image (hb_paint_funcs_t *funcs HB_UNUSED,
213 void *paint_data,
214 hb_blob_t *blob HB_UNUSED,
215 unsigned int width HB_UNUSED,
216 unsigned int height HB_UNUSED,
217 hb_tag_t format HB_UNUSED,
218 float slant HB_UNUSED,
219 hb_glyph_extents_t *glyph_extents,
220 void *user_data HB_UNUSED)
221{
222 hb_paint_extents_context_t *c = (hb_paint_extents_context_t *) paint_data;
223
224 hb_extents_t extents = {(float) glyph_extents->x_bearing,
225 (float) glyph_extents->y_bearing + glyph_extents->height,
226 (float) glyph_extents->x_bearing + glyph_extents->width,
227 (float) glyph_extents->y_bearing};
228 c->push_clip (extents);
229 c->paint ();
230 c->pop_clip ();
231
232 return true;
233}
234
235static void
236hb_paint_extents_paint_color (hb_paint_funcs_t *funcs HB_UNUSED,
237 void *paint_data,
238 hb_bool_t use_foreground HB_UNUSED,
239 hb_color_t color HB_UNUSED,
240 void *user_data HB_UNUSED)
241{
242 hb_paint_extents_context_t *c = (hb_paint_extents_context_t *) paint_data;
243
244 c->paint ();
245}
246
247static void
248hb_paint_extents_paint_linear_gradient (hb_paint_funcs_t *funcs HB_UNUSED,
249 void *paint_data,
250 hb_color_line_t *color_line HB_UNUSED,
251 float x0 HB_UNUSED, float y0 HB_UNUSED,
252 float x1 HB_UNUSED, float y1 HB_UNUSED,
253 float x2 HB_UNUSED, float y2 HB_UNUSED,
254 void *user_data HB_UNUSED)
255{
256 hb_paint_extents_context_t *c = (hb_paint_extents_context_t *) paint_data;
257
258 c->paint ();
259}
260
261static void
262hb_paint_extents_paint_radial_gradient (hb_paint_funcs_t *funcs HB_UNUSED,
263 void *paint_data,
264 hb_color_line_t *color_line HB_UNUSED,
265 float x0 HB_UNUSED, float y0 HB_UNUSED, float r0 HB_UNUSED,
266 float x1 HB_UNUSED, float y1 HB_UNUSED, float r1 HB_UNUSED,
267 void *user_data HB_UNUSED)
268{
269 hb_paint_extents_context_t *c = (hb_paint_extents_context_t *) paint_data;
270
271 c->paint ();
272}
273
274static void
275hb_paint_extents_paint_sweep_gradient (hb_paint_funcs_t *funcs HB_UNUSED,
276 void *paint_data,
277 hb_color_line_t *color_line HB_UNUSED,
278 float cx HB_UNUSED, float cy HB_UNUSED,
279 float start_angle HB_UNUSED,
280 float end_angle HB_UNUSED,
281 void *user_data HB_UNUSED)
282{
283 hb_paint_extents_context_t *c = (hb_paint_extents_context_t *) paint_data;
284
285 c->paint ();
286}
287
288static inline void free_static_paint_extents_funcs ();
289
290static struct hb_paint_extents_funcs_lazy_loader_t : hb_paint_funcs_lazy_loader_t<hb_paint_extents_funcs_lazy_loader_t>
291{
292 static hb_paint_funcs_t *create ()
293 {
294 hb_paint_funcs_t *funcs = hb_paint_funcs_create ();
295
296 hb_paint_funcs_set_push_transform_func (funcs, hb_paint_extents_push_transform, nullptr, nullptr);
297 hb_paint_funcs_set_pop_transform_func (funcs, hb_paint_extents_pop_transform, nullptr, nullptr);
298 hb_paint_funcs_set_push_clip_glyph_func (funcs, hb_paint_extents_push_clip_glyph, nullptr, nullptr);
299 hb_paint_funcs_set_push_clip_rectangle_func (funcs, hb_paint_extents_push_clip_rectangle, nullptr, nullptr);
300 hb_paint_funcs_set_pop_clip_func (funcs, hb_paint_extents_pop_clip, nullptr, nullptr);
301 hb_paint_funcs_set_push_group_func (funcs, hb_paint_extents_push_group, nullptr, nullptr);
302 hb_paint_funcs_set_pop_group_func (funcs, hb_paint_extents_pop_group, nullptr, nullptr);
303 hb_paint_funcs_set_color_func (funcs, hb_paint_extents_paint_color, nullptr, nullptr);
304 hb_paint_funcs_set_image_func (funcs, hb_paint_extents_paint_image, nullptr, nullptr);
305 hb_paint_funcs_set_linear_gradient_func (funcs, hb_paint_extents_paint_linear_gradient, nullptr, nullptr);
306 hb_paint_funcs_set_radial_gradient_func (funcs, hb_paint_extents_paint_radial_gradient, nullptr, nullptr);
307 hb_paint_funcs_set_sweep_gradient_func (funcs, hb_paint_extents_paint_sweep_gradient, nullptr, nullptr);
308
309 hb_paint_funcs_make_immutable (funcs);
310
311 hb_atexit (free_static_paint_extents_funcs);
312
313 return funcs;
314 }
315} static_paint_extents_funcs;
316
317static inline
318void free_static_paint_extents_funcs ()
319{
320 static_paint_extents_funcs.free_instance ();
321}
322
323hb_paint_funcs_t *
324hb_paint_extents_get_funcs ()
325{
326 return static_paint_extents_funcs.get_unconst ();
327}
328
329
330#endif
331