Coverage Report

Created: 2025-10-10 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/harfbuzz/src/OT/Var/VARC/VARC.hh
Line
Count
Source
1
#ifndef OT_VAR_VARC_VARC_HH
2
#define OT_VAR_VARC_VARC_HH
3
4
#include "../../../hb-decycler.hh"
5
#include "../../../hb-geometry.hh"
6
#include "../../../hb-ot-layout-common.hh"
7
#include "../../../hb-ot-glyf-table.hh"
8
#include "../../../hb-ot-cff2-table.hh"
9
#include "../../../hb-ot-cff1-table.hh"
10
11
#include "coord-setter.hh"
12
13
namespace OT {
14
15
//namespace Var {
16
17
/*
18
 * VARC -- Variable Composites
19
 * https://github.com/harfbuzz/boring-expansion-spec/blob/main/VARC.md
20
 */
21
22
#ifndef HB_NO_VAR_COMPOSITES
23
24
struct hb_varc_scratch_t
25
{
26
  hb_vector_t<unsigned> axisIndices;
27
  hb_vector_t<float> axisValues;
28
  hb_glyf_scratch_t glyf_scratch;
29
};
30
31
struct hb_varc_context_t
32
{
33
  hb_font_t *font;
34
  hb_draw_session_t *draw_session;
35
  hb_extents_t<> *extents;
36
  mutable hb_decycler_t decycler;
37
  mutable signed edges_left;
38
  mutable signed depth_left;
39
  hb_varc_scratch_t &scratch;
40
};
41
42
struct VarComponent
43
{
44
  enum class flags_t : uint32_t
45
  {
46
    RESET_UNSPECIFIED_AXES  = 1u << 0,
47
    HAVE_AXES     = 1u << 1,
48
    AXIS_VALUES_HAVE_VARIATION  = 1u << 2,
49
    TRANSFORM_HAS_VARIATION = 1u << 3,
50
    HAVE_TRANSLATE_X    = 1u << 4,
51
    HAVE_TRANSLATE_Y    = 1u << 5,
52
    HAVE_ROTATION   = 1u << 6,
53
    HAVE_CONDITION    = 1u << 7,
54
    HAVE_SCALE_X    = 1u << 8,
55
    HAVE_SCALE_Y    = 1u << 9,
56
    HAVE_TCENTER_X    = 1u << 10,
57
    HAVE_TCENTER_Y    = 1u << 11,
58
    GID_IS_24BIT    = 1u << 12,
59
    HAVE_SKEW_X     = 1u << 13,
60
    HAVE_SKEW_Y     = 1u << 14,
61
    RESERVED_MASK   = ~((1u << 15) - 1),
62
  };
63
64
  HB_INTERNAL hb_ubytes_t
65
  get_path_at (const hb_varc_context_t &c,
66
         hb_codepoint_t parent_gid,
67
         hb_array_t<const int> coords,
68
         hb_transform_t<> transform,
69
         hb_ubytes_t record,
70
         hb_scalar_cache_t *cache = nullptr) const;
71
};
72
73
struct VarCompositeGlyph
74
{
75
  static void
76
  get_path_at (const hb_varc_context_t &c,
77
         hb_codepoint_t gid,
78
         hb_array_t<const int> coords,
79
         hb_transform_t<> transform,
80
         hb_ubytes_t record,
81
         hb_scalar_cache_t *cache)
82
2.46M
  {
83
16.4M
    while (record)
84
13.9M
    {
85
13.9M
      const VarComponent &comp = * (const VarComponent *) (record.arrayZ);
86
13.9M
      record = comp.get_path_at (c,
87
13.9M
         gid,
88
13.9M
         coords, transform,
89
13.9M
         record,
90
13.9M
         cache);
91
13.9M
    }
92
2.46M
  }
93
};
94
95
HB_MARK_AS_FLAG_T (VarComponent::flags_t);
96
97
struct VARC
98
{
99
  friend struct VarComponent;
100
101
  static constexpr hb_tag_t tableTag = HB_TAG ('V', 'A', 'R', 'C');
102
103
  HB_INTERNAL bool
104
  get_path_at (const hb_varc_context_t &c,
105
         hb_codepoint_t gid,
106
         hb_array_t<const int> coords,
107
         hb_transform_t<> transform = HB_TRANSFORM_IDENTITY,
108
         hb_codepoint_t parent_gid = HB_CODEPOINT_INVALID,
109
         hb_scalar_cache_t *parent_cache = nullptr) const;
110
111
  bool
112
  get_path (hb_font_t *font,
113
      hb_codepoint_t gid,
114
      hb_draw_session_t &draw_session,
115
      hb_varc_scratch_t &scratch) const
116
88.8k
  {
117
88.8k
    hb_varc_context_t c {font,
118
88.8k
       &draw_session,
119
88.8k
       nullptr,
120
88.8k
       hb_decycler_t {},
121
88.8k
       HB_MAX_GRAPH_EDGE_COUNT,
122
88.8k
       HB_MAX_NESTING_LEVEL,
123
88.8k
       scratch};
124
125
88.8k
    return get_path_at (c, gid,
126
88.8k
      hb_array (font->coords, font->num_coords));
127
88.8k
  }
128
129
  bool
130
  get_extents (hb_font_t *font,
131
         hb_codepoint_t gid,
132
         hb_extents_t<> *extents,
133
         hb_varc_scratch_t &scratch) const
134
53.0k
  {
135
53.0k
    hb_varc_context_t c {font,
136
53.0k
       nullptr,
137
53.0k
       extents,
138
53.0k
       hb_decycler_t {},
139
53.0k
       HB_MAX_GRAPH_EDGE_COUNT,
140
53.0k
       HB_MAX_NESTING_LEVEL,
141
53.0k
       scratch};
142
143
53.0k
    return get_path_at (c, gid,
144
53.0k
      hb_array (font->coords, font->num_coords));
145
53.0k
  }
146
147
  bool sanitize (hb_sanitize_context_t *c) const
148
9.22k
  {
149
9.22k
    TRACE_SANITIZE (this);
150
9.22k
    return_trace (version.sanitize (c) &&
151
9.22k
      hb_barrier () &&
152
9.22k
      version.major == 1 &&
153
9.22k
      coverage.sanitize (c, this) &&
154
9.22k
      varStore.sanitize (c, this) &&
155
9.22k
      conditionList.sanitize (c, this) &&
156
9.22k
      axisIndicesList.sanitize (c, this) &&
157
9.22k
      glyphRecords.sanitize (c, this));
158
9.22k
  }
159
160
  struct accelerator_t
161
  {
162
    friend struct VarComponent;
163
164
    accelerator_t (hb_face_t *face)
165
66.0k
    {
166
66.0k
      table = hb_sanitize_context_t ().reference_table<VARC> (face);
167
66.0k
    }
168
    ~accelerator_t ()
169
66.0k
    {
170
66.0k
      auto *scratch = cached_scratch.get_relaxed ();
171
66.0k
      if (scratch)
172
2.99k
      {
173
2.99k
  scratch->~hb_varc_scratch_t ();
174
2.99k
  hb_free (scratch);
175
2.99k
      }
176
177
66.0k
      table.destroy ();
178
66.0k
    }
179
180
    bool
181
    get_path (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session) const
182
1.68M
    {
183
1.68M
      if (!table->has_data ()) return false;
184
185
88.9k
      auto *scratch = acquire_scratch ();
186
88.9k
      if (unlikely (!scratch)) return true;
187
88.8k
      bool ret = table->get_path (font, gid, draw_session, *scratch);
188
88.8k
      release_scratch (scratch);
189
88.8k
      return ret;
190
88.9k
    }
191
192
    bool
193
    get_extents (hb_font_t *font,
194
     hb_codepoint_t gid,
195
     hb_glyph_extents_t *extents) const
196
1.78M
    {
197
1.78M
#ifndef HB_NO_DRAW
198
1.78M
      if (!table->has_data ()) return false;
199
200
53.0k
      hb_extents_t<> f_extents;
201
202
53.0k
      auto *scratch = acquire_scratch ();
203
53.0k
      if (unlikely (!scratch)) return true;
204
53.0k
      bool ret = table->get_extents (font, gid, &f_extents, *scratch);
205
53.0k
      release_scratch (scratch);
206
207
53.0k
      if (ret)
208
44.4k
  *extents = f_extents.to_glyph_extents (font->x_scale < 0, font->y_scale < 0);
209
210
53.0k
      return ret;
211
#else
212
      return false;
213
#endif
214
53.0k
    }
215
216
    private:
217
218
    hb_varc_scratch_t *acquire_scratch () const
219
141k
    {
220
141k
      hb_varc_scratch_t *scratch = cached_scratch.get_acquire ();
221
222
141k
      if (!scratch || unlikely (!cached_scratch.cmpexch (scratch, nullptr)))
223
3.07k
      {
224
3.07k
  scratch = (hb_varc_scratch_t *) hb_calloc (1, sizeof (hb_varc_scratch_t));
225
3.07k
  if (unlikely (!scratch))
226
77
    return nullptr;
227
3.07k
      }
228
229
141k
      return scratch;
230
141k
    }
231
    void release_scratch (hb_varc_scratch_t *scratch) const
232
141k
    {
233
141k
      if (!cached_scratch.cmpexch (nullptr, scratch))
234
0
      {
235
0
  scratch->~hb_varc_scratch_t ();
236
0
  hb_free (scratch);
237
0
      }
238
141k
    }
239
240
    private:
241
    hb_blob_ptr_t<VARC> table;
242
    mutable hb_atomic_t<hb_varc_scratch_t *> cached_scratch;
243
  };
244
245
3.47M
  bool has_data () const { return version.major != 0; }
246
247
  protected:
248
  FixedVersion<> version; /* Version identifier */
249
  Offset32To<Coverage> coverage;
250
  Offset32To<MultiItemVariationStore> varStore;
251
  Offset32To<ConditionList> conditionList;
252
  Offset32To<TupleList> axisIndicesList;
253
  Offset32To<CFF2Index/*Of<VarCompositeGlyph>*/> glyphRecords;
254
  public:
255
  DEFINE_SIZE_STATIC (24);
256
};
257
258
struct VARC_accelerator_t : VARC::accelerator_t {
259
66.0k
  VARC_accelerator_t (hb_face_t *face) : VARC::accelerator_t (face) {}
260
};
261
262
#endif
263
264
//}
265
266
}
267
268
#endif  /* OT_VAR_VARC_VARC_HH */