Coverage Report

Created: 2025-12-31 10:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/workdir/UnpackedTarball/harfbuzz/src/hb-outline.cc
Line
Count
Source
1
/*
2
 * Copyright © 2023  Behdad Esfahbod
3
 * Copyright © 1999  David Turner
4
 * Copyright © 2005  Werner Lemberg
5
 * Copyright © 2013-2015  Alexei Podtelezhnikov
6
 *
7
 *  This is part of HarfBuzz, a text shaping library.
8
 *
9
 * Permission is hereby granted, without written agreement and without
10
 * license or royalty fees, to use, copy, modify, and distribute this
11
 * software and its documentation for any purpose, provided that the
12
 * above copyright notice and the following two paragraphs appear in
13
 * all copies of this software.
14
 *
15
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
16
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
17
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
18
 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
19
 * DAMAGE.
20
 *
21
 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
22
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
23
 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
24
 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
25
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
26
 */
27
28
#include "hb.hh"
29
30
#ifndef HB_NO_OUTLINE
31
32
#include "hb-outline.hh"
33
34
#include "hb-machinery.hh"
35
36
37
void hb_outline_t::replay (hb_draw_funcs_t *pen, void *pen_data) const
38
0
{
39
0
  hb_draw_state_t st = HB_DRAW_STATE_DEFAULT;
40
41
0
  unsigned first = 0;
42
0
  for (unsigned contour : contours)
43
0
  {
44
0
    auto it = points.as_array ().sub_array (first, contour - first);
45
0
    while (it)
46
0
    {
47
0
      hb_outline_point_t p1 = *it++;
48
0
      switch (p1.type)
49
0
      {
50
0
  case hb_outline_point_t::type_t::MOVE_TO:
51
0
  {
52
0
    pen->move_to (pen_data, st,
53
0
         p1.x, p1.y);
54
0
  }
55
0
  break;
56
0
  case hb_outline_point_t::type_t::LINE_TO:
57
0
  {
58
0
    pen->line_to (pen_data, st,
59
0
         p1.x, p1.y);
60
0
  }
61
0
  break;
62
0
  case hb_outline_point_t::type_t::QUADRATIC_TO:
63
0
  {
64
0
    hb_outline_point_t p2 = *it++;
65
0
    pen->quadratic_to (pen_data, st,
66
0
        p1.x, p1.y,
67
0
        p2.x, p2.y);
68
0
  }
69
0
  break;
70
0
  case hb_outline_point_t::type_t::CUBIC_TO:
71
0
  {
72
0
    hb_outline_point_t p2 = *it++;
73
0
    hb_outline_point_t p3 = *it++;
74
0
    pen->cubic_to (pen_data, st,
75
0
          p1.x, p1.y,
76
0
          p2.x, p2.y,
77
0
          p3.x, p3.y);
78
0
  }
79
0
  break;
80
0
      }
81
0
    }
82
0
    pen->close_path (pen_data, st);
83
0
    first = contour;
84
0
  }
85
0
}
86
87
void hb_outline_t::translate (float dx, float dy)
88
0
{
89
0
  for (auto &p : points)
90
0
  {
91
0
    p.x += dx;
92
0
    p.y += dy;
93
0
  }
94
0
}
95
96
void hb_outline_t::slant (float slant_xy)
97
0
{
98
0
  for (auto &p : points)
99
0
    p.x += slant_xy * p.y;
100
0
}
101
102
float hb_outline_t::control_area () const
103
0
{
104
0
  float a = 0;
105
0
  unsigned first = 0;
106
0
  for (unsigned contour : contours)
107
0
  {
108
0
    for (unsigned i = first; i < contour; i++)
109
0
    {
110
0
      unsigned j = i + 1 < contour ? i + 1 : first;
111
112
0
      auto &pi = points[i];
113
0
      auto &pj = points[j];
114
0
      a += pi.x * pj.y - pi.y * pj.x;
115
0
    }
116
117
0
    first = contour;
118
0
  }
119
0
  return a * .5f;
120
0
}
121
122
void hb_outline_t::embolden (float x_strength, float y_strength,
123
           float x_shift, float y_shift)
124
0
{
125
  /* This function is a straight port of FreeType's FT_Outline_EmboldenXY.
126
   * Permission has been obtained from the FreeType authors of the code
127
   * to relicense it under the HarfBuzz license. */
128
129
0
  if (!x_strength && !y_strength) return;
130
0
  if (!points) return;
131
132
0
  x_strength /= 2.f;
133
0
  y_strength /= 2.f;
134
135
0
  bool orientation_negative = control_area () < 0;
136
137
0
  signed first = 0;
138
0
  for (unsigned c = 0; c < contours.length; c++)
139
0
  {
140
0
    hb_outline_vector_t in, out, anchor, shift;
141
0
    float l_in, l_out, l_anchor = 0, l, q, d;
142
143
0
    l_in = 0;
144
0
    signed last = (int) contours[c] - 1;
145
146
    /* pacify compiler */
147
0
    in.x = in.y = anchor.x = anchor.y = 0;
148
149
    /* Counter j cycles though the points; counter i advances only  */
150
    /* when points are moved; anchor k marks the first moved point. */
151
0
    for ( signed i = last, j = first, k = -1;
152
0
    j != i && i != k;
153
0
    j = j < last ? j + 1 : first )
154
0
    {
155
0
      if ( j != k )
156
0
      {
157
0
  out.x = points[j].x - points[i].x;
158
0
  out.y = points[j].y - points[i].y;
159
0
  l_out = out.normalize_len ();
160
161
0
  if ( l_out == 0 )
162
0
    continue;
163
0
      }
164
0
      else
165
0
      {
166
0
  out   = anchor;
167
0
  l_out = l_anchor;
168
0
      }
169
170
0
      if ( l_in != 0 )
171
0
      {
172
0
  if ( k < 0 )
173
0
  {
174
0
    k        = i;
175
0
    anchor   = in;
176
0
    l_anchor = l_in;
177
0
  }
178
179
0
  d = in.x * out.x + in.y * out.y;
180
181
  /* shift only if turn is less than ~160 degrees */
182
0
  if ( d > -15.f/16.f )
183
0
  {
184
0
    d = d + 1.f;
185
186
    /* shift components along lateral bisector in proper orientation */
187
0
    shift.x = in.y + out.y;
188
0
    shift.y = in.x + out.x;
189
190
0
    if ( orientation_negative )
191
0
      shift.x = -shift.x;
192
0
    else
193
0
      shift.y = -shift.y;
194
195
    /* restrict shift magnitude to better handle collapsing segments */
196
0
    q = out.x * in.y - out.y * in.x;
197
0
    if ( orientation_negative )
198
0
      q = -q;
199
200
0
    l = hb_min (l_in, l_out);
201
202
    /* non-strict inequalities avoid divide-by-zero when q == l == 0 */
203
0
    if (x_strength * q <= l * d)
204
0
      shift.x = shift.x * x_strength / d;
205
0
    else
206
0
      shift.x = shift.x * l / q;
207
208
209
0
    if (y_strength * q <= l * d)
210
0
      shift.y = shift.y * y_strength / d;
211
0
    else
212
0
      shift.y = shift.y * l / q;
213
0
  }
214
0
  else
215
0
    shift.x = shift.y = 0;
216
217
0
  for ( ;
218
0
        i != j;
219
0
        i = i < last ? i + 1 : first )
220
0
  {
221
0
    points[i].x += x_shift + shift.x;
222
0
    points[i].y += y_shift + shift.y;
223
0
  }
224
0
      }
225
0
      else
226
0
  i = j;
227
228
0
      in   = out;
229
0
      l_in = l_out;
230
0
    }
231
232
0
    first = last + 1;
233
0
  }
234
0
}
235
236
static void
237
hb_outline_recording_pen_move_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
238
          void *data,
239
          hb_draw_state_t *st,
240
          float to_x, float to_y,
241
          void *user_data HB_UNUSED)
242
0
{
243
0
  hb_outline_t *c = (hb_outline_t *) data;
244
245
0
  c->points.push (hb_outline_point_t {to_x, to_y, hb_outline_point_t::type_t::MOVE_TO});
246
0
}
247
248
static void
249
hb_outline_recording_pen_line_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
250
          void *data,
251
          hb_draw_state_t *st,
252
          float to_x, float to_y,
253
          void *user_data HB_UNUSED)
254
0
{
255
0
  hb_outline_t *c = (hb_outline_t *) data;
256
257
0
  c->points.push (hb_outline_point_t {to_x, to_y, hb_outline_point_t::type_t::LINE_TO});
258
0
}
259
260
static void
261
hb_outline_recording_pen_quadratic_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
262
               void *data,
263
               hb_draw_state_t *st,
264
               float control_x, float control_y,
265
               float to_x, float to_y,
266
               void *user_data HB_UNUSED)
267
0
{
268
0
  hb_outline_t *c = (hb_outline_t *) data;
269
270
0
  c->points.push (hb_outline_point_t {control_x, control_y, hb_outline_point_t::type_t::QUADRATIC_TO});
271
0
  c->points.push (hb_outline_point_t {to_x, to_y, hb_outline_point_t::type_t::QUADRATIC_TO});
272
0
}
273
274
static void
275
hb_outline_recording_pen_cubic_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
276
           void *data,
277
           hb_draw_state_t *st,
278
           float control1_x, float control1_y,
279
           float control2_x, float control2_y,
280
           float to_x, float to_y,
281
           void *user_data HB_UNUSED)
282
0
{
283
0
  hb_outline_t *c = (hb_outline_t *) data;
284
285
0
  c->points.push (hb_outline_point_t {control1_x, control1_y, hb_outline_point_t::type_t::CUBIC_TO});
286
0
  c->points.push (hb_outline_point_t {control2_x, control2_y, hb_outline_point_t::type_t::CUBIC_TO});
287
0
  c->points.push (hb_outline_point_t {to_x, to_y, hb_outline_point_t::type_t::CUBIC_TO});
288
0
}
289
290
static void
291
hb_outline_recording_pen_close_path (hb_draw_funcs_t *dfuncs HB_UNUSED,
292
             void *data,
293
             hb_draw_state_t *st,
294
             void *user_data HB_UNUSED)
295
0
{
296
0
  hb_outline_t *c = (hb_outline_t *) data;
297
298
0
  c->contours.push (c->points.length);
299
0
}
300
301
static inline void free_static_outline_recording_pen_funcs ();
302
303
static struct hb_outline_recording_pen_funcs_lazy_loader_t : hb_draw_funcs_lazy_loader_t<hb_outline_recording_pen_funcs_lazy_loader_t>
304
{
305
  static hb_draw_funcs_t *create ()
306
0
  {
307
0
    hb_draw_funcs_t *funcs = hb_draw_funcs_create ();
308
309
0
    hb_draw_funcs_set_move_to_func (funcs, hb_outline_recording_pen_move_to, nullptr, nullptr);
310
0
    hb_draw_funcs_set_line_to_func (funcs, hb_outline_recording_pen_line_to, nullptr, nullptr);
311
0
    hb_draw_funcs_set_quadratic_to_func (funcs, hb_outline_recording_pen_quadratic_to, nullptr, nullptr);
312
0
    hb_draw_funcs_set_cubic_to_func (funcs, hb_outline_recording_pen_cubic_to, nullptr, nullptr);
313
0
    hb_draw_funcs_set_close_path_func (funcs, hb_outline_recording_pen_close_path, nullptr, nullptr);
314
315
0
    hb_draw_funcs_make_immutable (funcs);
316
317
0
    hb_atexit (free_static_outline_recording_pen_funcs);
318
319
0
    return funcs;
320
0
  }
321
} static_outline_recording_pen_funcs;
322
323
static inline
324
void free_static_outline_recording_pen_funcs ()
325
0
{
326
0
  static_outline_recording_pen_funcs.free_instance ();
327
0
}
328
329
hb_draw_funcs_t *
330
hb_outline_recording_pen_get_funcs ()
331
0
{
332
0
  return static_outline_recording_pen_funcs.get_unconst ();
333
0
}
334
335
336
#endif