Coverage Report

Created: 2024-08-21 15:15

/src/harfbuzz/src/hb-ot-hmtx-table.hh
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright © 2011,2012  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): Behdad Esfahbod, Roderick Sheeter
25
 */
26
27
#ifndef HB_OT_HMTX_TABLE_HH
28
#define HB_OT_HMTX_TABLE_HH
29
30
#include "hb-open-type.hh"
31
#include "hb-ot-maxp-table.hh"
32
#include "hb-ot-hhea-table.hh"
33
#include "hb-ot-var-hvar-table.hh"
34
#include "hb-ot-var-mvar-table.hh"
35
#include "hb-ot-metrics.hh"
36
37
/*
38
 * hmtx -- Horizontal Metrics
39
 * https://docs.microsoft.com/en-us/typography/opentype/spec/hmtx
40
 * vmtx -- Vertical Metrics
41
 * https://docs.microsoft.com/en-us/typography/opentype/spec/vmtx
42
 */
43
#define HB_OT_TAG_hmtx HB_TAG('h','m','t','x')
44
25.0k
#define HB_OT_TAG_vmtx HB_TAG('v','m','t','x')
45
46
47
HB_INTERNAL bool
48
_glyf_get_leading_bearing_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical, int *lsb);
49
50
HB_INTERNAL unsigned
51
_glyf_get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical);
52
53
54
namespace OT {
55
56
57
struct LongMetric
58
{
59
  UFWORD  advance; /* Advance width/height. */
60
  FWORD   sb; /* Leading (left/top) side bearing. */
61
  public:
62
  DEFINE_SIZE_STATIC (4);
63
};
64
65
66
template <typename T/*Data table type*/, typename H/*Header table type*/, typename V/*Var table type*/>
67
struct hmtxvmtx
68
{
69
  bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const
70
41.7k
  {
71
41.7k
    TRACE_SANITIZE (this);
72
    /* We don't check for anything specific here.  The users of the
73
     * struct do all the hard work... */
74
41.7k
    return_trace (true);
75
41.7k
  }
OT::hmtxvmtx<OT::hmtx, OT::hhea, OT::HVAR>::sanitize(hb_sanitize_context_t*) const
Line
Count
Source
70
39.6k
  {
71
39.6k
    TRACE_SANITIZE (this);
72
    /* We don't check for anything specific here.  The users of the
73
     * struct do all the hard work... */
74
39.6k
    return_trace (true);
75
39.6k
  }
OT::hmtxvmtx<OT::vmtx, OT::vhea, OT::VVAR>::sanitize(hb_sanitize_context_t*) const
Line
Count
Source
70
2.15k
  {
71
2.15k
    TRACE_SANITIZE (this);
72
    /* We don't check for anything specific here.  The users of the
73
     * struct do all the hard work... */
74
2.15k
    return_trace (true);
75
2.15k
  }
76
77
  const hb_hashmap_t<hb_codepoint_t, hb_pair_t<unsigned, int>>* get_mtx_map (const hb_subset_plan_t *plan) const
78
  { return T::is_horizontal ? &plan->hmtx_map : &plan->vmtx_map; }
79
80
  bool subset_update_header (hb_subset_context_t *c,
81
           unsigned int num_hmetrics,
82
           const hb_hashmap_t<hb_codepoint_t, hb_pair_t<unsigned, int>> *mtx_map,
83
           const hb_map_t *bounds_map) const
84
  {
85
    hb_blob_t *src_blob = hb_sanitize_context_t ().reference_table<H> (c->plan->source, H::tableTag);
86
    hb_blob_t *dest_blob = hb_blob_copy_writable_or_fail (src_blob);
87
    hb_blob_destroy (src_blob);
88
89
    if (unlikely (!dest_blob)) {
90
      return false;
91
    }
92
93
    unsigned int length;
94
    H *table = (H *) hb_blob_get_data (dest_blob, &length);
95
    table->numberOfLongMetrics = num_hmetrics;
96
97
#ifndef HB_NO_VAR
98
    if (c->plan->normalized_coords)
99
    {
100
      auto &MVAR = *c->plan->source->table.MVAR;
101
      if (T::is_horizontal)
102
      {
103
  HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_HORIZONTAL_CARET_RISE,   caretSlopeRise);
104
  HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_HORIZONTAL_CARET_RUN,    caretSlopeRun);
105
  HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_HORIZONTAL_CARET_OFFSET, caretOffset);
106
      }
107
      else
108
      {
109
  HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_VERTICAL_CARET_RISE,     caretSlopeRise);
110
  HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_VERTICAL_CARET_RUN,      caretSlopeRun);
111
  HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_VERTICAL_CARET_OFFSET,   caretOffset);
112
      }
113
114
      int min_lsb = 0x7FFF;
115
      int min_rsb = 0x7FFF;
116
      int max_extent = -0x7FFF;
117
      unsigned max_adv = 0;
118
      for (const auto _ : *mtx_map)
119
      {
120
        hb_codepoint_t gid = _.first;
121
        unsigned adv = _.second.first;
122
        int lsb = _.second.second;
123
        max_adv = hb_max (max_adv, adv);
124
125
        if (bounds_map->has (gid))
126
        {
127
          unsigned bound_width = bounds_map->get (gid);
128
          int rsb = adv - lsb - bound_width;
129
          int extent = lsb + bound_width;
130
          min_lsb = hb_min (min_lsb, lsb);
131
          min_rsb = hb_min (min_rsb, rsb);
132
          max_extent = hb_max (max_extent, extent);
133
        }
134
      }
135
136
      table->advanceMax = max_adv;
137
      if (!bounds_map->is_empty ())
138
      {
139
        table->minLeadingBearing = min_lsb;
140
        table->minTrailingBearing = min_rsb;
141
        table->maxExtent = max_extent;
142
      }
143
    }
144
#endif
145
146
    bool result = c->plan->add_table (H::tableTag, dest_blob);
147
    hb_blob_destroy (dest_blob);
148
149
    return result;
150
  }
151
152
  template<typename Iterator,
153
     hb_requires (hb_is_iterator (Iterator))>
154
  void serialize (hb_serialize_context_t *c,
155
      Iterator it,
156
      unsigned num_long_metrics)
157
  {
158
    unsigned idx = 0;
159
    for (auto _ : it)
160
    {
161
      if (idx < num_long_metrics)
162
      {
163
  LongMetric lm;
164
  lm.advance = _.first;
165
  lm.sb = _.second;
166
  if (unlikely (!c->embed<LongMetric> (&lm))) return;
167
      }
168
      else
169
      {
170
  FWORD *sb = c->allocate_size<FWORD> (FWORD::static_size);
171
  if (unlikely (!sb)) return;
172
  *sb = _.second;
173
      }
174
      idx++;
175
    }
176
  }
177
178
  bool subset (hb_subset_context_t *c) const
179
  {
180
    TRACE_SUBSET (this);
181
182
    T *table_prime = c->serializer->start_embed <T> ();
183
    if (unlikely (!table_prime)) return_trace (false);
184
185
    accelerator_t _mtx (c->plan->source);
186
    unsigned num_long_metrics;
187
    const hb_hashmap_t<hb_codepoint_t, hb_pair_t<unsigned, int>> *mtx_map = get_mtx_map (c->plan);
188
    {
189
      /* Determine num_long_metrics to encode. */
190
      auto& plan = c->plan;
191
192
      num_long_metrics = plan->num_output_glyphs ();
193
      unsigned int last_advance = get_new_gid_advance_unscaled (plan, mtx_map, num_long_metrics - 1, _mtx);
194
      while (num_long_metrics > 1 &&
195
       last_advance == get_new_gid_advance_unscaled (plan, mtx_map, num_long_metrics - 2, _mtx))
196
      {
197
  num_long_metrics--;
198
      }
199
    }
200
201
    auto it =
202
    + hb_range (c->plan->num_output_glyphs ())
203
    | hb_map ([c, &_mtx, mtx_map] (unsigned _)
204
        {
205
    if (!mtx_map->has (_))
206
    {
207
      hb_codepoint_t old_gid;
208
      if (!c->plan->old_gid_for_new_gid (_, &old_gid))
209
        return hb_pair (0u, 0);
210
      int lsb = 0;
211
      (void) _mtx.get_leading_bearing_without_var_unscaled (old_gid, &lsb);
212
      return hb_pair (_mtx.get_advance_without_var_unscaled (old_gid), +lsb);
213
    }
214
    return mtx_map->get (_);
215
        })
216
    ;
217
218
    table_prime->serialize (c->serializer, it, num_long_metrics);
219
220
    if (unlikely (c->serializer->in_error ()))
221
      return_trace (false);
222
223
    // Amend header num hmetrics
224
    if (unlikely (!subset_update_header (c, num_long_metrics, mtx_map,
225
                                         T::is_horizontal ? &c->plan->bounds_width_map : &c->plan->bounds_height_map)))
226
      return_trace (false);
227
228
    return_trace (true);
229
  }
230
231
  struct accelerator_t
232
  {
233
    friend struct hmtxvmtx;
234
235
    accelerator_t (hb_face_t *face)
236
301k
    {
237
301k
      table = hb_sanitize_context_t ().reference_table<hmtxvmtx> (face, T::tableTag);
238
301k
      var_table = hb_sanitize_context_t ().reference_table<V> (face, T::variationsTag);
239
240
301k
      default_advance = T::is_horizontal ? hb_face_get_upem (face) / 2 : hb_face_get_upem (face);
241
242
      /* Populate count variables and sort them out as we go */
243
244
301k
      unsigned int len = table.get_length ();
245
301k
      if (len & 1)
246
607
        len--;
247
248
301k
      num_long_metrics = T::is_horizontal ?
249
150k
       face->table.hhea->numberOfLongMetrics :
250
301k
#ifndef HB_NO_VERTICAL
251
301k
       face->table.vhea->numberOfLongMetrics
252
#else
253
       0
254
#endif
255
301k
       ;
256
301k
      if (unlikely (num_long_metrics * 4 > len))
257
3.30k
  num_long_metrics = len / 4;
258
301k
      len -= num_long_metrics * 4;
259
260
301k
      num_bearings = face->table.maxp->get_num_glyphs ();
261
262
301k
      if (unlikely (num_bearings < num_long_metrics))
263
1.94k
        num_bearings = num_long_metrics;
264
301k
      if (unlikely ((num_bearings - num_long_metrics) * 2 > len))
265
50.7k
        num_bearings = num_long_metrics + len / 2;
266
301k
      len -= (num_bearings - num_long_metrics) * 2;
267
268
      /* We MUST set num_bearings to zero if num_long_metrics is zero.
269
       * Our get_advance() depends on that. */
270
301k
      if (unlikely (!num_long_metrics))
271
267k
  num_bearings = num_long_metrics = 0;
272
273
301k
      num_advances = num_bearings + len / 2;
274
301k
      num_glyphs = face->get_num_glyphs ();
275
301k
      if (num_glyphs < num_advances)
276
4.88k
        num_glyphs = num_advances;
277
301k
    }
OT::hmtxvmtx<OT::hmtx, OT::hhea, OT::HVAR>::accelerator_t::accelerator_t(hb_face_t*)
Line
Count
Source
236
150k
    {
237
150k
      table = hb_sanitize_context_t ().reference_table<hmtxvmtx> (face, T::tableTag);
238
150k
      var_table = hb_sanitize_context_t ().reference_table<V> (face, T::variationsTag);
239
240
150k
      default_advance = T::is_horizontal ? hb_face_get_upem (face) / 2 : hb_face_get_upem (face);
241
242
      /* Populate count variables and sort them out as we go */
243
244
150k
      unsigned int len = table.get_length ();
245
150k
      if (len & 1)
246
464
        len--;
247
248
150k
      num_long_metrics = T::is_horizontal ?
249
150k
       face->table.hhea->numberOfLongMetrics :
250
150k
#ifndef HB_NO_VERTICAL
251
150k
       face->table.vhea->numberOfLongMetrics
252
#else
253
       0
254
#endif
255
150k
       ;
256
150k
      if (unlikely (num_long_metrics * 4 > len))
257
3.14k
  num_long_metrics = len / 4;
258
150k
      len -= num_long_metrics * 4;
259
260
150k
      num_bearings = face->table.maxp->get_num_glyphs ();
261
262
150k
      if (unlikely (num_bearings < num_long_metrics))
263
1.81k
        num_bearings = num_long_metrics;
264
150k
      if (unlikely ((num_bearings - num_long_metrics) * 2 > len))
265
9.38k
        num_bearings = num_long_metrics + len / 2;
266
150k
      len -= (num_bearings - num_long_metrics) * 2;
267
268
      /* We MUST set num_bearings to zero if num_long_metrics is zero.
269
       * Our get_advance() depends on that. */
270
150k
      if (unlikely (!num_long_metrics))
271
118k
  num_bearings = num_long_metrics = 0;
272
273
150k
      num_advances = num_bearings + len / 2;
274
150k
      num_glyphs = face->get_num_glyphs ();
275
150k
      if (num_glyphs < num_advances)
276
4.49k
        num_glyphs = num_advances;
277
150k
    }
OT::hmtxvmtx<OT::vmtx, OT::vhea, OT::VVAR>::accelerator_t::accelerator_t(hb_face_t*)
Line
Count
Source
236
150k
    {
237
150k
      table = hb_sanitize_context_t ().reference_table<hmtxvmtx> (face, T::tableTag);
238
150k
      var_table = hb_sanitize_context_t ().reference_table<V> (face, T::variationsTag);
239
240
150k
      default_advance = T::is_horizontal ? hb_face_get_upem (face) / 2 : hb_face_get_upem (face);
241
242
      /* Populate count variables and sort them out as we go */
243
244
150k
      unsigned int len = table.get_length ();
245
150k
      if (len & 1)
246
143
        len--;
247
248
150k
      num_long_metrics = T::is_horizontal ?
249
0
       face->table.hhea->numberOfLongMetrics :
250
150k
#ifndef HB_NO_VERTICAL
251
150k
       face->table.vhea->numberOfLongMetrics
252
#else
253
       0
254
#endif
255
150k
       ;
256
150k
      if (unlikely (num_long_metrics * 4 > len))
257
157
  num_long_metrics = len / 4;
258
150k
      len -= num_long_metrics * 4;
259
260
150k
      num_bearings = face->table.maxp->get_num_glyphs ();
261
262
150k
      if (unlikely (num_bearings < num_long_metrics))
263
127
        num_bearings = num_long_metrics;
264
150k
      if (unlikely ((num_bearings - num_long_metrics) * 2 > len))
265
41.4k
        num_bearings = num_long_metrics + len / 2;
266
150k
      len -= (num_bearings - num_long_metrics) * 2;
267
268
      /* We MUST set num_bearings to zero if num_long_metrics is zero.
269
       * Our get_advance() depends on that. */
270
150k
      if (unlikely (!num_long_metrics))
271
149k
  num_bearings = num_long_metrics = 0;
272
273
150k
      num_advances = num_bearings + len / 2;
274
150k
      num_glyphs = face->get_num_glyphs ();
275
150k
      if (num_glyphs < num_advances)
276
383
        num_glyphs = num_advances;
277
150k
    }
278
    ~accelerator_t ()
279
301k
    {
280
301k
      table.destroy ();
281
301k
      var_table.destroy ();
282
301k
    }
OT::hmtxvmtx<OT::hmtx, OT::hhea, OT::HVAR>::accelerator_t::~accelerator_t()
Line
Count
Source
279
150k
    {
280
150k
      table.destroy ();
281
150k
      var_table.destroy ();
282
150k
    }
OT::hmtxvmtx<OT::vmtx, OT::vhea, OT::VVAR>::accelerator_t::~accelerator_t()
Line
Count
Source
279
150k
    {
280
150k
      table.destroy ();
281
150k
      var_table.destroy ();
282
150k
    }
283
284
151k
    bool has_data () const { return (bool) num_bearings; }
285
286
    bool get_leading_bearing_without_var_unscaled (hb_codepoint_t glyph,
287
               int *lsb) const
288
263k
    {
289
263k
      if (glyph < num_long_metrics)
290
48.7k
      {
291
48.7k
  *lsb = table->longMetricZ[glyph].sb;
292
48.7k
  return true;
293
48.7k
      }
294
295
214k
      if (unlikely (glyph >= num_bearings))
296
212k
  return false;
297
298
2.48k
      const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_long_metrics];
299
2.48k
      *lsb = bearings[glyph - num_long_metrics];
300
2.48k
      return true;
301
214k
    }
OT::hmtxvmtx<OT::hmtx, OT::hhea, OT::HVAR>::accelerator_t::get_leading_bearing_without_var_unscaled(unsigned int, int*) const
Line
Count
Source
288
133k
    {
289
133k
      if (glyph < num_long_metrics)
290
48.3k
      {
291
48.3k
  *lsb = table->longMetricZ[glyph].sb;
292
48.3k
  return true;
293
48.3k
      }
294
295
85.2k
      if (unlikely (glyph >= num_bearings))
296
82.7k
  return false;
297
298
2.47k
      const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_long_metrics];
299
2.47k
      *lsb = bearings[glyph - num_long_metrics];
300
2.47k
      return true;
301
85.2k
    }
OT::hmtxvmtx<OT::vmtx, OT::vhea, OT::VVAR>::accelerator_t::get_leading_bearing_without_var_unscaled(unsigned int, int*) const
Line
Count
Source
288
130k
    {
289
130k
      if (glyph < num_long_metrics)
290
425
      {
291
425
  *lsb = table->longMetricZ[glyph].sb;
292
425
  return true;
293
425
      }
294
295
129k
      if (unlikely (glyph >= num_bearings))
296
129k
  return false;
297
298
7
      const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_long_metrics];
299
7
      *lsb = bearings[glyph - num_long_metrics];
300
7
      return true;
301
129k
    }
302
303
    bool get_leading_bearing_with_var_unscaled (hb_font_t *font,
304
            hb_codepoint_t glyph,
305
            int *lsb) const
306
5.52k
    {
307
5.52k
      if (!font->num_coords)
308
5.52k
  return get_leading_bearing_without_var_unscaled (glyph, lsb);
309
310
0
#ifndef HB_NO_VAR
311
0
      float delta;
312
0
      if (var_table->get_lsb_delta_unscaled (glyph, font->coords, font->num_coords, &delta) &&
313
0
    get_leading_bearing_without_var_unscaled (glyph, lsb))
314
0
      {
315
0
  *lsb += roundf (delta);
316
0
  return true;
317
0
      }
318
319
0
      return _glyf_get_leading_bearing_with_var_unscaled (font, glyph, T::tableTag == HB_OT_TAG_vmtx, lsb);
320
#else
321
      return false;
322
#endif
323
0
    }
324
325
    unsigned int get_advance_without_var_unscaled (hb_codepoint_t glyph) const
326
21.2M
    {
327
      /* OpenType case. */
328
21.2M
      if (glyph < num_bearings)
329
2.91M
  return table->longMetricZ[hb_min (glyph, (uint32_t) num_long_metrics - 1)].advance;
330
331
      /* If num_advances is zero, it means we don't have the metrics table
332
       * for this direction: return default advance.  Otherwise, there's a
333
       * well-defined answer. */
334
18.3M
      if (unlikely (!num_advances))
335
16.2M
  return default_advance;
336
337
#ifdef HB_NO_BEYOND_64K
338
      return 0;
339
#endif
340
341
2.08M
      if (unlikely (glyph >= num_glyphs))
342
1.04M
        return 0;
343
344
      /* num_bearings <= glyph < num_glyphs;
345
       * num_bearings <= num_advances */
346
347
1.04M
      if (num_bearings == num_advances)
348
5.82k
        return get_advance_without_var_unscaled (num_bearings - 1);
349
350
1.04M
      const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_long_metrics];
351
1.04M
      const UFWORD *advances = (const UFWORD *) &bearings[num_bearings - num_long_metrics];
352
353
1.04M
      return advances[hb_min (glyph - num_bearings, num_advances - num_bearings - 1)];
354
1.04M
    }
OT::hmtxvmtx<OT::vmtx, OT::vhea, OT::VVAR>::accelerator_t::get_advance_without_var_unscaled(unsigned int) const
Line
Count
Source
326
125k
    {
327
      /* OpenType case. */
328
125k
      if (glyph < num_bearings)
329
680
  return table->longMetricZ[hb_min (glyph, (uint32_t) num_long_metrics - 1)].advance;
330
331
      /* If num_advances is zero, it means we don't have the metrics table
332
       * for this direction: return default advance.  Otherwise, there's a
333
       * well-defined answer. */
334
125k
      if (unlikely (!num_advances))
335
123k
  return default_advance;
336
337
#ifdef HB_NO_BEYOND_64K
338
      return 0;
339
#endif
340
341
2.02k
      if (unlikely (glyph >= num_glyphs))
342
1.32k
        return 0;
343
344
      /* num_bearings <= glyph < num_glyphs;
345
       * num_bearings <= num_advances */
346
347
694
      if (num_bearings == num_advances)
348
21
        return get_advance_without_var_unscaled (num_bearings - 1);
349
350
673
      const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_long_metrics];
351
673
      const UFWORD *advances = (const UFWORD *) &bearings[num_bearings - num_long_metrics];
352
353
673
      return advances[hb_min (glyph - num_bearings, num_advances - num_bearings - 1)];
354
694
    }
OT::hmtxvmtx<OT::hmtx, OT::hhea, OT::HVAR>::accelerator_t::get_advance_without_var_unscaled(unsigned int) const
Line
Count
Source
326
21.1M
    {
327
      /* OpenType case. */
328
21.1M
      if (glyph < num_bearings)
329
2.91M
  return table->longMetricZ[hb_min (glyph, (uint32_t) num_long_metrics - 1)].advance;
330
331
      /* If num_advances is zero, it means we don't have the metrics table
332
       * for this direction: return default advance.  Otherwise, there's a
333
       * well-defined answer. */
334
18.2M
      if (unlikely (!num_advances))
335
16.1M
  return default_advance;
336
337
#ifdef HB_NO_BEYOND_64K
338
      return 0;
339
#endif
340
341
2.08M
      if (unlikely (glyph >= num_glyphs))
342
1.03M
        return 0;
343
344
      /* num_bearings <= glyph < num_glyphs;
345
       * num_bearings <= num_advances */
346
347
1.04M
      if (num_bearings == num_advances)
348
5.80k
        return get_advance_without_var_unscaled (num_bearings - 1);
349
350
1.04M
      const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_long_metrics];
351
1.04M
      const UFWORD *advances = (const UFWORD *) &bearings[num_bearings - num_long_metrics];
352
353
1.04M
      return advances[hb_min (glyph - num_bearings, num_advances - num_bearings - 1)];
354
1.04M
    }
355
356
    unsigned get_advance_with_var_unscaled (hb_codepoint_t  glyph,
357
              hb_font_t      *font,
358
              VariationStore::cache_t *store_cache = nullptr) const
359
21.0M
    {
360
21.0M
      unsigned int advance = get_advance_without_var_unscaled (glyph);
361
362
21.0M
#ifndef HB_NO_VAR
363
21.0M
      if (unlikely (glyph >= num_bearings) || !font->num_coords)
364
20.9M
  return advance;
365
366
29.4k
      if (var_table.get_length ())
367
4.43k
  return advance + roundf (var_table->get_advance_delta_unscaled (glyph,
368
29.4k
                  font->coords, font->num_coords,
369
29.4k
                  store_cache));
370
371
25.0k
      return _glyf_get_advance_with_var_unscaled (font, glyph, T::tableTag == HB_OT_TAG_vmtx);
372
#else
373
      return advance;
374
#endif
375
29.4k
    }
OT::hmtxvmtx<OT::hmtx, OT::hhea, OT::HVAR>::accelerator_t::get_advance_with_var_unscaled(unsigned int, hb_font_t*, float*) const
Line
Count
Source
359
21.0M
    {
360
21.0M
      unsigned int advance = get_advance_without_var_unscaled (glyph);
361
362
21.0M
#ifndef HB_NO_VAR
363
21.0M
      if (unlikely (glyph >= num_bearings) || !font->num_coords)
364
20.9M
  return advance;
365
366
29.4k
      if (var_table.get_length ())
367
4.43k
  return advance + roundf (var_table->get_advance_delta_unscaled (glyph,
368
29.4k
                  font->coords, font->num_coords,
369
29.4k
                  store_cache));
370
371
25.0k
      return _glyf_get_advance_with_var_unscaled (font, glyph, T::tableTag == HB_OT_TAG_vmtx);
372
#else
373
      return advance;
374
#endif
375
29.4k
    }
OT::hmtxvmtx<OT::vmtx, OT::vhea, OT::VVAR>::accelerator_t::get_advance_with_var_unscaled(unsigned int, hb_font_t*, float*) const
Line
Count
Source
359
1.45k
    {
360
1.45k
      unsigned int advance = get_advance_without_var_unscaled (glyph);
361
362
1.45k
#ifndef HB_NO_VAR
363
1.45k
      if (unlikely (glyph >= num_bearings) || !font->num_coords)
364
1.45k
  return advance;
365
366
0
      if (var_table.get_length ())
367
0
  return advance + roundf (var_table->get_advance_delta_unscaled (glyph,
368
0
                  font->coords, font->num_coords,
369
0
                  store_cache));
370
371
0
      return _glyf_get_advance_with_var_unscaled (font, glyph, T::tableTag == HB_OT_TAG_vmtx);
372
#else
373
      return advance;
374
#endif
375
0
    }
376
377
    protected:
378
    // 0 <= num_long_metrics <= num_bearings <= num_advances <= num_glyphs
379
    unsigned num_long_metrics;
380
    unsigned num_bearings;
381
    unsigned num_advances;
382
    unsigned num_glyphs;
383
384
    unsigned int default_advance;
385
386
    public:
387
    hb_blob_ptr_t<hmtxvmtx> table;
388
    hb_blob_ptr_t<V> var_table;
389
  };
390
391
  /* get advance: when no variations, call get_advance_without_var_unscaled.
392
   * when there're variations, get advance value from mtx_map in subset_plan*/
393
  unsigned get_new_gid_advance_unscaled (const hb_subset_plan_t *plan,
394
                                         const hb_hashmap_t<hb_codepoint_t, hb_pair_t<unsigned, int>> *mtx_map,
395
                                         unsigned new_gid,
396
                                         const accelerator_t &_mtx) const
397
  {
398
    if (mtx_map->is_empty ())
399
    {
400
      hb_codepoint_t old_gid = 0;
401
      return plan->old_gid_for_new_gid (new_gid, &old_gid) ?
402
             _mtx.get_advance_without_var_unscaled (old_gid) : 0;
403
    }
404
    return mtx_map->get (new_gid).first;
405
  }
406
407
  protected:
408
  UnsizedArrayOf<LongMetric>
409
    longMetricZ;  /* Paired advance width and leading
410
         * bearing values for each glyph. The
411
         * value numOfHMetrics comes from
412
         * the 'hhea' table. If the font is
413
         * monospaced, only one entry need
414
         * be in the array, but that entry is
415
         * required. The last entry applies to
416
         * all subsequent glyphs. */
417
/*UnsizedArrayOf<FWORD> leadingBearingX;*/
418
        /* Here the advance is assumed
419
         * to be the same as the advance
420
         * for the last entry above. The
421
         * number of entries in this array is
422
         * derived from numGlyphs (from 'maxp'
423
         * table) minus numberOfLongMetrics.
424
         * This generally is used with a run
425
         * of monospaced glyphs (e.g., Kanji
426
         * fonts or Courier fonts). Only one
427
         * run is allowed and it must be at
428
         * the end. This allows a monospaced
429
         * font to vary the side bearing
430
         * values for each glyph. */
431
/*UnsizedArrayOf<UFWORD>advancesX;*/
432
        /* TODO Document. */
433
  public:
434
  DEFINE_SIZE_ARRAY (0, longMetricZ);
435
};
436
437
struct hmtx : hmtxvmtx<hmtx, hhea, HVAR> {
438
  static constexpr hb_tag_t tableTag = HB_OT_TAG_hmtx;
439
  static constexpr hb_tag_t variationsTag = HB_OT_TAG_HVAR;
440
  static constexpr bool is_horizontal = true;
441
};
442
struct vmtx : hmtxvmtx<vmtx, vhea, VVAR> {
443
  static constexpr hb_tag_t tableTag = HB_OT_TAG_vmtx;
444
  static constexpr hb_tag_t variationsTag = HB_OT_TAG_VVAR;
445
  static constexpr bool is_horizontal = false;
446
};
447
448
struct hmtx_accelerator_t : hmtx::accelerator_t {
449
150k
  hmtx_accelerator_t (hb_face_t *face) : hmtx::accelerator_t (face) {}
450
};
451
struct vmtx_accelerator_t : vmtx::accelerator_t {
452
150k
  vmtx_accelerator_t (hb_face_t *face) : vmtx::accelerator_t (face) {}
453
};
454
455
} /* namespace OT */
456
457
458
#endif /* HB_OT_HMTX_TABLE_HH */