Coverage Report

Created: 2026-08-31 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/harfbuzz/src/hb-subset-plan.hh
Line
Count
Source
1
/*
2
 * Copyright © 2018  Google, Inc.
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
 * Google Author(s): Garret Rieger, Roderick Sheeter
25
 */
26
27
#ifndef HB_SUBSET_PLAN_HH
28
#define HB_SUBSET_PLAN_HH
29
30
#include "hb.hh"
31
32
#include "hb-subset.h"
33
#include "hb-subset-input.hh"
34
#include "hb-subset-accelerator.hh"
35
36
#include "hb-map.hh"
37
#include "hb-bimap.hh"
38
#include "hb-set.hh"
39
40
namespace OT {
41
struct Feature;
42
}
43
44
struct os2_info_t {
45
  hb_codepoint_t min_cmap_codepoint;
46
  hb_codepoint_t max_cmap_codepoint;
47
};
48
49
typedef struct os2_info_t os2_info_t;
50
51
struct head_maxp_info_t
52
{
53
  head_maxp_info_t ()
54
      :xMin (0x7FFF), xMax (-0x7FFF), yMin (0x7FFF), yMax (-0x7FFF),
55
      maxPoints (0), maxContours (0),
56
      maxCompositePoints (0),
57
      maxCompositeContours (0),
58
      maxComponentElements (0),
59
      maxComponentDepth (0),
60
0
      allXMinIsLsb (true) {}
61
62
  int xMin;
63
  int xMax;
64
  int yMin;
65
  int yMax;
66
  unsigned maxPoints;
67
  unsigned maxContours;
68
  unsigned maxCompositePoints;
69
  unsigned maxCompositeContours;
70
  unsigned maxComponentElements;
71
  unsigned maxComponentDepth;
72
  bool allXMinIsLsb;
73
};
74
75
typedef struct head_maxp_info_t head_maxp_info_t;
76
77
struct contour_point_t
78
{
79
  void init (float x_ = 0.f, float y_ = 0.f, bool is_end_point_ = false)
80
0
  { flag = 0; x = x_; y = y_; is_end_point = is_end_point_; }
81
82
  void transform (const float (&matrix)[4])
83
0
  {
84
0
    float x_ = x * matrix[0] + y * matrix[2];
85
0
    y  = x * matrix[1] + y * matrix[3];
86
0
    x  = x_;
87
0
  }
88
89
  void add_delta (float delta_x, float delta_y)
90
0
  {
91
0
    x += delta_x;
92
0
    y += delta_y;
93
0
  }
94
95
  HB_ALWAYS_INLINE
96
0
  void translate (const contour_point_t &p) { x += p.x; y += p.y; }
97
98
  float x;
99
  float y;
100
  uint8_t flag;
101
  bool is_end_point;
102
};
103
104
struct contour_point_vector_t : hb_vector_t<contour_point_t>
105
{
106
  bool add_deltas (hb_array_t<const float> deltas_x,
107
                   hb_array_t<const float> deltas_y,
108
                   hb_array_t<const bool> indices)
109
0
  {
110
0
    if (indices.length != deltas_x.length ||
111
0
        indices.length != deltas_y.length)
112
0
      return false;
113
0
114
0
    for (unsigned i = 0; i < indices.length; i++)
115
0
    {
116
0
      if (!indices.arrayZ[i]) continue;
117
0
      arrayZ[i].add_delta (deltas_x.arrayZ[i], deltas_y.arrayZ[i]);
118
0
    }
119
0
    return true;
120
0
  }
121
};
122
123
namespace OT {
124
  struct cff1_subset_accelerator_t;
125
  struct cff2_subset_accelerator_t;
126
}
127
128
struct hb_subset_plan_t
129
{
130
  HB_INTERNAL hb_subset_plan_t (hb_face_t *,
131
        const hb_subset_input_t *input);
132
133
  HB_INTERNAL ~hb_subset_plan_t();
134
135
  hb_object_header_t header;
136
137
  bool successful;
138
  unsigned flags;
139
  bool attach_accelerator_data = false;
140
  bool force_long_loca = false;
141
142
  // The glyph subset
143
  hb_map_t *codepoint_to_glyph; // Needs to be heap-allocated
144
145
  // Old -> New glyph id mapping
146
  hb_map_t *glyph_map; // Needs to be heap-allocated
147
  hb_map_t *reverse_glyph_map; // Needs to be heap-allocated
148
149
  // Plan is only good for a specific source/dest so keep them with it
150
  hb_face_t *source;
151
#ifndef HB_NO_SUBSET_CFF
152
  // These have to be immediately after source:
153
  hb_face_lazy_loader_t<OT::cff1_subset_accelerator_t, 1> cff1_accel;
154
  hb_face_lazy_loader_t<OT::cff2_subset_accelerator_t, 2> cff2_accel;
155
#endif
156
157
  hb_face_t *dest;
158
159
  unsigned int _num_output_glyphs;
160
161
  bool all_axes_pinned;
162
  bool pinned_at_default;
163
  bool has_seac;
164
165
  // whether to insert a catch-all FeatureVariationRecord
166
  bool gsub_insert_catch_all_feature_variation_rec;
167
  bool gpos_insert_catch_all_feature_variation_rec;
168
169
  // whether GDEF ItemVariationStore is retained
170
  mutable bool has_gdef_varstore;
171
172
  // whether we're doing avar2 partial instancing
173
  bool has_avar2;
174
175
#define HB_SUBSET_PLAN_MEMBER(Type, Name) Type Name;
176
#include "hb-subset-plan-member-list.hh"
177
#undef HB_SUBSET_PLAN_MEMBER
178
179
  //recalculated head/maxp table info after instancing
180
  mutable head_maxp_info_t head_maxp_info;
181
182
  os2_info_t os2_info;
183
184
  const hb_subset_accelerator_t* accelerator;
185
  hb_subset_accelerator_t* inprogress_accelerator;
186
187
 public:
188
189
  template<typename T>
190
  struct source_table_loader
191
  {
192
    hb_blob_ptr_t<T> operator () (hb_subset_plan_t *plan)
193
    {
194
      hb_lock_t lock (plan->accelerator ? &plan->accelerator->sanitized_table_cache_lock : nullptr);
195
196
      auto *cache = plan->accelerator ? &plan->accelerator->sanitized_table_cache : &plan->sanitized_table_cache;
197
      if (cache
198
    && !cache->in_error ()
199
    && cache->has (+T::tableTag)) {
200
  return hb_blob_reference (cache->get (+T::tableTag).get ());
201
      }
202
203
      hb::unique_ptr<hb_blob_t> table_blob {hb_sanitize_context_t ().reference_table<T> (plan->source)};
204
      hb_blob_t* ret = hb_blob_reference (table_blob.get ());
205
206
      if (likely (cache))
207
  cache->set (+T::tableTag, std::move (table_blob));
208
209
      return ret;
210
    }
211
  };
212
213
  template<typename T>
214
  auto source_table() HB_AUTO_RETURN (source_table_loader<T> {} (this))
215
216
0
  bool in_error () const { return !successful; }
217
218
  bool check_success(bool success)
219
0
  {
220
0
    successful = (successful && success);
221
0
    return successful;
222
0
  }
223
224
  /*
225
   * The set of input glyph ids which will be retained in the subset.
226
   * Does NOT include ids kept due to retain_gids. You probably want to use
227
   * glyph_map/reverse_glyph_map.
228
   */
229
  inline const hb_set_t *
230
  glyphset () const
231
0
  {
232
0
    return &_glyphset;
233
0
  }
234
235
  /*
236
   * The set of input glyph ids which will be retained in the subset.
237
   */
238
  inline const hb_set_t *
239
  glyphset_gsub () const
240
0
  {
241
0
    return &_glyphset_gsub;
242
0
  }
243
244
  /*
245
   * Old-to-new glyph id mapping for GSUB glyphs, through the flat
246
   * array; returns HB_MAP_VALUE_INVALID for glyphs not retained.
247
   */
248
  inline hb_codepoint_t
249
  map_gsub_glyph (hb_codepoint_t old_gid) const
250
0
  {
251
0
    return old_gid < glyph_map_gsub_flat.length
252
0
   ? glyph_map_gsub_flat.arrayZ[old_gid]
253
0
   : HB_MAP_VALUE_INVALID;
254
0
  }
255
256
  /*
257
   * The total number of output glyphs in the final subset.
258
   */
259
  inline unsigned int
260
  num_output_glyphs () const
261
0
  {
262
0
    return _num_output_glyphs;
263
0
  }
264
265
  inline bool new_gid_for_codepoint (hb_codepoint_t codepoint,
266
             hb_codepoint_t *new_gid) const
267
0
  {
268
0
    hb_codepoint_t old_gid = codepoint_to_glyph->get (codepoint);
269
0
    if (old_gid == HB_MAP_VALUE_INVALID)
270
0
      return false;
271
0
272
0
    return new_gid_for_old_gid (old_gid, new_gid);
273
0
  }
274
275
  inline bool new_gid_for_old_gid (hb_codepoint_t old_gid,
276
           hb_codepoint_t *new_gid) const
277
0
  {
278
0
    hb_codepoint_t gid = glyph_map->get (old_gid);
279
0
    if (gid == HB_MAP_VALUE_INVALID)
280
0
      return false;
281
0
282
0
    *new_gid = gid;
283
0
    return true;
284
0
  }
285
286
  inline bool old_gid_for_new_gid (hb_codepoint_t  new_gid,
287
           hb_codepoint_t *old_gid) const
288
0
  {
289
0
    hb_codepoint_t gid = reverse_glyph_map->get (new_gid);
290
0
    if (gid == HB_MAP_VALUE_INVALID)
291
0
      return false;
292
0
293
0
    *old_gid = gid;
294
0
    return true;
295
0
  }
296
297
  inline bool
298
  add_table (hb_tag_t tag,
299
       hb_blob_t *contents)
300
0
  {
301
0
    if (HB_DEBUG_SUBSET)
302
0
    {
303
0
      hb_blob_t *source_blob = source->reference_table (tag);
304
0
      DEBUG_MSG(SUBSET, nullptr, "add table %c%c%c%c, dest %u bytes, source %u bytes",
305
0
    HB_UNTAG(tag),
306
0
    hb_blob_get_length (contents),
307
0
    hb_blob_get_length (source_blob));
308
0
      hb_blob_destroy (source_blob);
309
0
    }
310
0
    return hb_face_builder_add_table (dest, tag, contents);
311
0
  }
312
};
313
314
// hb-subset-plan implementation is split into multiple files to keep
315
// compile times more reasonable:
316
// - hb-subset-plan.cc
317
// - hb-subset-plan-layout.cc
318
// - hb-subset-plan-var.cc
319
//
320
// The functions below are those needed to connect the split files
321
// above together.
322
HB_INTERNAL void
323
remap_indexes (const hb_set_t *indexes,
324
               hb_map_t       *mapping /* OUT */);
325
326
327
#ifndef HB_NO_VAR
328
template<typename ItemVarStore>
329
HB_INTERNAL void
330
remap_variation_indices (const ItemVarStore &var_store,
331
                         const hb_set_t &variation_indices,
332
                         const hb_vector_t<int>& normalized_coords,
333
                         bool calculate_delta, /* not pinned at default */
334
                         bool no_variations, /* all axes pinned */
335
                         hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> &variation_idx_delta_map /* OUT */);
336
337
338
template<typename DeltaSetIndexMap>
339
HB_INTERNAL void
340
remap_colrv1_delta_set_index_indices (const DeltaSetIndexMap &index_map,
341
                                      const hb_set_t &delta_set_idxes,
342
                                      hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> &variation_idx_delta_map, /* IN/OUT */
343
                                      hb_map_t &new_deltaset_idx_varidx_map /* OUT */);
344
345
346
HB_INTERNAL void
347
generate_varstore_inner_maps (const hb_set_t& varidx_set,
348
                              unsigned subtable_count,
349
                              hb_vector_t<hb_inc_bimap_t> &inner_maps /* OUT */);
350
351
HB_INTERNAL bool
352
normalize_axes_location (hb_face_t *face, hb_subset_plan_t *plan);
353
354
HB_INTERNAL void
355
update_instance_metrics_map_from_cff2 (hb_subset_plan_t *plan);
356
357
HB_INTERNAL bool
358
get_instance_glyphs_contour_points (hb_subset_plan_t *plan);
359
360
#ifndef HB_NO_BASE
361
HB_INTERNAL void
362
collect_base_variation_indices (hb_subset_plan_t* plan);
363
#endif
364
#endif
365
366
#ifndef HB_NO_SUBSET_LAYOUT
367
typedef hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> script_langsys_map;
368
369
HB_INTERNAL void
370
remap_used_mark_sets (hb_subset_plan_t *plan,
371
                      hb_map_t& used_mark_sets_map);
372
373
HB_INTERNAL void
374
layout_nameid_closure (hb_subset_plan_t* plan,
375
                       hb_set_t* drop_tables);
376
377
HB_INTERNAL void
378
layout_populate_gids_to_retain (hb_subset_plan_t* plan,
379
                                hb_set_t* drop_tables);
380
381
HB_INTERNAL void
382
collect_layout_variation_indices (hb_subset_plan_t* plan);
383
#endif
384
385
386
#endif /* HB_SUBSET_PLAN_HH */