Coverage Report

Created: 2026-08-14 06:53

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