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
43 static void
hb_paint_extents_push_transform(hb_paint_funcs_t * funcs HB_UNUSED,void * paint_data,float xx,float yx,float xy,float yy,float dx,float dy,void * user_data HB_UNUSED)44 hb_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
56 static void
hb_paint_extents_pop_transform(hb_paint_funcs_t * funcs HB_UNUSED,void * paint_data,void * user_data HB_UNUSED)57 hb_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
66 static void
hb_draw_extents_move_to(hb_draw_funcs_t * dfuncs HB_UNUSED,void * data,hb_draw_state_t * st,float to_x,float to_y,void * user_data HB_UNUSED)67 hb_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
78 static void
hb_draw_extents_line_to(hb_draw_funcs_t * dfuncs HB_UNUSED,void * data,hb_draw_state_t * st,float to_x,float to_y,void * user_data HB_UNUSED)79 hb_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
90 static void
hb_draw_extents_quadratic_to(hb_draw_funcs_t * dfuncs HB_UNUSED,void * data,hb_draw_state_t * st,float control_x,float control_y,float to_x,float to_y,void * user_data HB_UNUSED)91 hb_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
104 static void
hb_draw_extents_cubic_to(hb_draw_funcs_t * dfuncs HB_UNUSED,void * data,hb_draw_state_t * st,float control1_x,float control1_y,float control2_x,float control2_y,float to_x,float to_y,void * user_data HB_UNUSED)105 hb_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
120 static inline void free_static_draw_extents_funcs ();
121
122 static struct hb_draw_extents_funcs_lazy_loader_t : hb_draw_funcs_lazy_loader_t<hb_draw_extents_funcs_lazy_loader_t>
123 {
createhb_draw_extents_funcs_lazy_loader_t124 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
141 static inline
free_static_draw_extents_funcs()142 void free_static_draw_extents_funcs ()
143 {
144 static_draw_extents_funcs.free_instance ();
145 }
146
147 static hb_draw_funcs_t *
hb_draw_extents_get_funcs()148 hb_draw_extents_get_funcs ()
149 {
150 return static_draw_extents_funcs.get_unconst ();
151 }
152
153 static void
hb_paint_extents_push_clip_glyph(hb_paint_funcs_t * funcs HB_UNUSED,void * paint_data,hb_codepoint_t glyph,hb_font_t * font,void * user_data HB_UNUSED)154 hb_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
168 static void
hb_paint_extents_push_clip_rectangle(hb_paint_funcs_t * funcs HB_UNUSED,void * paint_data,float xmin,float ymin,float xmax,float ymax,void * user_data)169 hb_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
180 static void
hb_paint_extents_pop_clip(hb_paint_funcs_t * funcs HB_UNUSED,void * paint_data,void * user_data HB_UNUSED)181 hb_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
190 static void
hb_paint_extents_push_group(hb_paint_funcs_t * funcs HB_UNUSED,void * paint_data,void * user_data HB_UNUSED)191 hb_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
200 static void
hb_paint_extents_pop_group(hb_paint_funcs_t * funcs HB_UNUSED,void * paint_data,hb_paint_composite_mode_t mode,void * user_data HB_UNUSED)201 hb_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
211 static hb_bool_t
hb_paint_extents_paint_image(hb_paint_funcs_t * funcs HB_UNUSED,void * paint_data,hb_blob_t * blob HB_UNUSED,unsigned int width HB_UNUSED,unsigned int height HB_UNUSED,hb_tag_t format HB_UNUSED,float slant HB_UNUSED,hb_glyph_extents_t * glyph_extents,void * user_data HB_UNUSED)212 hb_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
235 static void
hb_paint_extents_paint_color(hb_paint_funcs_t * funcs HB_UNUSED,void * paint_data,hb_bool_t use_foreground HB_UNUSED,hb_color_t color HB_UNUSED,void * user_data HB_UNUSED)236 hb_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
247 static void
hb_paint_extents_paint_linear_gradient(hb_paint_funcs_t * funcs HB_UNUSED,void * paint_data,hb_color_line_t * color_line HB_UNUSED,float x0 HB_UNUSED,float y0 HB_UNUSED,float x1 HB_UNUSED,float y1 HB_UNUSED,float x2 HB_UNUSED,float y2 HB_UNUSED,void * user_data HB_UNUSED)248 hb_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
261 static void
hb_paint_extents_paint_radial_gradient(hb_paint_funcs_t * funcs HB_UNUSED,void * paint_data,hb_color_line_t * color_line HB_UNUSED,float x0 HB_UNUSED,float y0 HB_UNUSED,float r0 HB_UNUSED,float x1 HB_UNUSED,float y1 HB_UNUSED,float r1 HB_UNUSED,void * user_data HB_UNUSED)262 hb_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
274 static void
hb_paint_extents_paint_sweep_gradient(hb_paint_funcs_t * funcs HB_UNUSED,void * paint_data,hb_color_line_t * color_line HB_UNUSED,float cx HB_UNUSED,float cy HB_UNUSED,float start_angle HB_UNUSED,float end_angle HB_UNUSED,void * user_data HB_UNUSED)275 hb_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
288 static inline void free_static_paint_extents_funcs ();
289
290 static struct hb_paint_extents_funcs_lazy_loader_t : hb_paint_funcs_lazy_loader_t<hb_paint_extents_funcs_lazy_loader_t>
291 {
createhb_paint_extents_funcs_lazy_loader_t292 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
317 static inline
free_static_paint_extents_funcs()318 void free_static_paint_extents_funcs ()
319 {
320 static_paint_extents_funcs.free_instance ();
321 }
322
323 hb_paint_funcs_t *
hb_paint_extents_get_funcs()324 hb_paint_extents_get_funcs ()
325 {
326 return static_paint_extents_funcs.get_unconst ();
327 }
328
329
330 #endif
331