Coverage Report

Created: 2026-02-14 09:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/workdir/UnpackedTarball/harfbuzz/src/hb-ot-layout-gsubgpos.hh
Line
Count
Source
1
/*
2
 * Copyright © 2007,2008,2009,2010  Red Hat, Inc.
3
 * Copyright © 2010,2012  Google, Inc.
4
 *
5
 *  This is part of HarfBuzz, a text shaping library.
6
 *
7
 * Permission is hereby granted, without written agreement and without
8
 * license or royalty fees, to use, copy, modify, and distribute this
9
 * software and its documentation for any purpose, provided that the
10
 * above copyright notice and the following two paragraphs appear in
11
 * all copies of this software.
12
 *
13
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16
 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
17
 * DAMAGE.
18
 *
19
 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21
 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
22
 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24
 *
25
 * Red Hat Author(s): Behdad Esfahbod
26
 * Google Author(s): Behdad Esfahbod
27
 */
28
29
#ifndef HB_OT_LAYOUT_GSUBGPOS_HH
30
#define HB_OT_LAYOUT_GSUBGPOS_HH
31
32
#include "hb.hh"
33
#include "hb-buffer.hh"
34
#include "hb-map.hh"
35
#include "hb-set.hh"
36
#include "hb-ot-map.hh"
37
#include "hb-ot-layout-common.hh"
38
#include "hb-ot-layout-gdef-table.hh"
39
40
41
namespace OT {
42
43
44
struct hb_intersects_context_t :
45
       hb_dispatch_context_t<hb_intersects_context_t, bool>
46
{
47
  template <typename T>
48
0
  return_t dispatch (const T &obj) { return obj.intersects (this->glyphs); }
Unexecuted instantiation: bool OT::hb_intersects_context_t::dispatch<OT::Layout::GPOS_impl::SinglePosFormat1>(OT::Layout::GPOS_impl::SinglePosFormat1 const&)
Unexecuted instantiation: bool OT::hb_intersects_context_t::dispatch<OT::Layout::GPOS_impl::SinglePosFormat2>(OT::Layout::GPOS_impl::SinglePosFormat2 const&)
Unexecuted instantiation: bool OT::hb_intersects_context_t::dispatch<OT::Layout::GPOS_impl::PairPosFormat1_3<OT::Layout::SmallTypes> >(OT::Layout::GPOS_impl::PairPosFormat1_3<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: bool OT::hb_intersects_context_t::dispatch<OT::Layout::GPOS_impl::PairPosFormat2_4<OT::Layout::SmallTypes> >(OT::Layout::GPOS_impl::PairPosFormat2_4<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: bool OT::hb_intersects_context_t::dispatch<OT::Layout::GPOS_impl::CursivePosFormat1>(OT::Layout::GPOS_impl::CursivePosFormat1 const&)
Unexecuted instantiation: bool OT::hb_intersects_context_t::dispatch<OT::Layout::GPOS_impl::MarkBasePosFormat1_2<OT::Layout::SmallTypes> >(OT::Layout::GPOS_impl::MarkBasePosFormat1_2<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: bool OT::hb_intersects_context_t::dispatch<OT::Layout::GPOS_impl::MarkLigPosFormat1_2<OT::Layout::SmallTypes> >(OT::Layout::GPOS_impl::MarkLigPosFormat1_2<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: bool OT::hb_intersects_context_t::dispatch<OT::Layout::GPOS_impl::MarkMarkPosFormat1_2<OT::Layout::SmallTypes> >(OT::Layout::GPOS_impl::MarkMarkPosFormat1_2<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: bool OT::hb_intersects_context_t::dispatch<OT::ContextFormat1_4<OT::Layout::SmallTypes> >(OT::ContextFormat1_4<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: bool OT::hb_intersects_context_t::dispatch<OT::ContextFormat2_5<OT::Layout::SmallTypes> >(OT::ContextFormat2_5<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: bool OT::hb_intersects_context_t::dispatch<OT::ContextFormat3>(OT::ContextFormat3 const&)
Unexecuted instantiation: bool OT::hb_intersects_context_t::dispatch<OT::ChainContextFormat1_4<OT::Layout::SmallTypes> >(OT::ChainContextFormat1_4<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: bool OT::hb_intersects_context_t::dispatch<OT::ChainContextFormat2_5<OT::Layout::SmallTypes> >(OT::ChainContextFormat2_5<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: bool OT::hb_intersects_context_t::dispatch<OT::ChainContextFormat3>(OT::ChainContextFormat3 const&)
Unexecuted instantiation: bool OT::hb_intersects_context_t::dispatch<OT::Layout::GSUB_impl::SingleSubstFormat1_3<OT::Layout::SmallTypes> >(OT::Layout::GSUB_impl::SingleSubstFormat1_3<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: bool OT::hb_intersects_context_t::dispatch<OT::Layout::GSUB_impl::SingleSubstFormat2_4<OT::Layout::SmallTypes> >(OT::Layout::GSUB_impl::SingleSubstFormat2_4<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: bool OT::hb_intersects_context_t::dispatch<OT::Layout::GSUB_impl::MultipleSubstFormat1_2<OT::Layout::SmallTypes> >(OT::Layout::GSUB_impl::MultipleSubstFormat1_2<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: bool OT::hb_intersects_context_t::dispatch<OT::Layout::GSUB_impl::AlternateSubstFormat1_2<OT::Layout::SmallTypes> >(OT::Layout::GSUB_impl::AlternateSubstFormat1_2<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: bool OT::hb_intersects_context_t::dispatch<OT::Layout::GSUB_impl::LigatureSubstFormat1_2<OT::Layout::SmallTypes> >(OT::Layout::GSUB_impl::LigatureSubstFormat1_2<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: bool OT::hb_intersects_context_t::dispatch<OT::Layout::GSUB_impl::ReverseChainSingleSubstFormat1>(OT::Layout::GSUB_impl::ReverseChainSingleSubstFormat1 const&)
49
0
  static return_t default_return_value () { return false; }
50
0
  bool stop_sublookup_iteration (return_t r) const { return r; }
51
52
  const hb_set_t *glyphs;
53
54
  hb_intersects_context_t (const hb_set_t *glyphs_) :
55
0
                            glyphs (glyphs_) {}
56
};
57
58
struct hb_have_non_1to1_context_t :
59
       hb_dispatch_context_t<hb_have_non_1to1_context_t, bool>
60
{
61
  template <typename T>
62
0
  return_t dispatch (const T &obj) { return obj.may_have_non_1to1 (); }
Unexecuted instantiation: bool OT::hb_have_non_1to1_context_t::dispatch<OT::Layout::GSUB_impl::SingleSubstFormat1_3<OT::Layout::SmallTypes> >(OT::Layout::GSUB_impl::SingleSubstFormat1_3<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: bool OT::hb_have_non_1to1_context_t::dispatch<OT::Layout::GSUB_impl::SingleSubstFormat2_4<OT::Layout::SmallTypes> >(OT::Layout::GSUB_impl::SingleSubstFormat2_4<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: bool OT::hb_have_non_1to1_context_t::dispatch<OT::Layout::GSUB_impl::MultipleSubstFormat1_2<OT::Layout::SmallTypes> >(OT::Layout::GSUB_impl::MultipleSubstFormat1_2<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: bool OT::hb_have_non_1to1_context_t::dispatch<OT::Layout::GSUB_impl::AlternateSubstFormat1_2<OT::Layout::SmallTypes> >(OT::Layout::GSUB_impl::AlternateSubstFormat1_2<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: bool OT::hb_have_non_1to1_context_t::dispatch<OT::Layout::GSUB_impl::LigatureSubstFormat1_2<OT::Layout::SmallTypes> >(OT::Layout::GSUB_impl::LigatureSubstFormat1_2<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: bool OT::hb_have_non_1to1_context_t::dispatch<OT::ContextFormat1_4<OT::Layout::SmallTypes> >(OT::ContextFormat1_4<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: bool OT::hb_have_non_1to1_context_t::dispatch<OT::ContextFormat2_5<OT::Layout::SmallTypes> >(OT::ContextFormat2_5<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: bool OT::hb_have_non_1to1_context_t::dispatch<OT::ContextFormat3>(OT::ContextFormat3 const&)
Unexecuted instantiation: bool OT::hb_have_non_1to1_context_t::dispatch<OT::ChainContextFormat1_4<OT::Layout::SmallTypes> >(OT::ChainContextFormat1_4<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: bool OT::hb_have_non_1to1_context_t::dispatch<OT::ChainContextFormat2_5<OT::Layout::SmallTypes> >(OT::ChainContextFormat2_5<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: bool OT::hb_have_non_1to1_context_t::dispatch<OT::ChainContextFormat3>(OT::ChainContextFormat3 const&)
Unexecuted instantiation: bool OT::hb_have_non_1to1_context_t::dispatch<OT::Layout::GSUB_impl::ReverseChainSingleSubstFormat1>(OT::Layout::GSUB_impl::ReverseChainSingleSubstFormat1 const&)
63
0
  static return_t default_return_value () { return false; }
64
0
  bool stop_sublookup_iteration (return_t r) const { return r; }
65
};
66
67
struct hb_closure_context_t :
68
       hb_dispatch_context_t<hb_closure_context_t>
69
{
70
  typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *covered_seq_indicies, unsigned seq_index, unsigned end_index);
71
  template <typename T>
72
0
  return_t dispatch (const T &obj) { obj.closure (this); return hb_empty_t (); }
Unexecuted instantiation: hb_empty_t OT::hb_closure_context_t::dispatch<OT::Layout::GSUB_impl::SingleSubstFormat1_3<OT::Layout::SmallTypes> >(OT::Layout::GSUB_impl::SingleSubstFormat1_3<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: hb_empty_t OT::hb_closure_context_t::dispatch<OT::Layout::GSUB_impl::SingleSubstFormat2_4<OT::Layout::SmallTypes> >(OT::Layout::GSUB_impl::SingleSubstFormat2_4<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: hb_empty_t OT::hb_closure_context_t::dispatch<OT::Layout::GSUB_impl::MultipleSubstFormat1_2<OT::Layout::SmallTypes> >(OT::Layout::GSUB_impl::MultipleSubstFormat1_2<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: hb_empty_t OT::hb_closure_context_t::dispatch<OT::Layout::GSUB_impl::AlternateSubstFormat1_2<OT::Layout::SmallTypes> >(OT::Layout::GSUB_impl::AlternateSubstFormat1_2<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: hb_empty_t OT::hb_closure_context_t::dispatch<OT::Layout::GSUB_impl::LigatureSubstFormat1_2<OT::Layout::SmallTypes> >(OT::Layout::GSUB_impl::LigatureSubstFormat1_2<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: hb_empty_t OT::hb_closure_context_t::dispatch<OT::ContextFormat1_4<OT::Layout::SmallTypes> >(OT::ContextFormat1_4<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: hb_empty_t OT::hb_closure_context_t::dispatch<OT::ContextFormat2_5<OT::Layout::SmallTypes> >(OT::ContextFormat2_5<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: hb_empty_t OT::hb_closure_context_t::dispatch<OT::ContextFormat3>(OT::ContextFormat3 const&)
Unexecuted instantiation: hb_empty_t OT::hb_closure_context_t::dispatch<OT::ChainContextFormat1_4<OT::Layout::SmallTypes> >(OT::ChainContextFormat1_4<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: hb_empty_t OT::hb_closure_context_t::dispatch<OT::ChainContextFormat2_5<OT::Layout::SmallTypes> >(OT::ChainContextFormat2_5<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: hb_empty_t OT::hb_closure_context_t::dispatch<OT::ChainContextFormat3>(OT::ChainContextFormat3 const&)
Unexecuted instantiation: hb_empty_t OT::hb_closure_context_t::dispatch<OT::Layout::GSUB_impl::ReverseChainSingleSubstFormat1>(OT::Layout::GSUB_impl::ReverseChainSingleSubstFormat1 const&)
73
0
  static return_t default_return_value () { return hb_empty_t (); }
74
  void recurse (unsigned lookup_index, hb_set_t *covered_seq_indicies, unsigned seq_index, unsigned end_index)
75
0
  {
76
0
    if (unlikely (nesting_level_left == 0 || !recurse_func))
77
0
      return;
78
79
0
    nesting_level_left--;
80
0
    recurse_func (this, lookup_index, covered_seq_indicies, seq_index, end_index);
81
0
    nesting_level_left++;
82
0
  }
83
84
  void reset_lookup_visit_count ()
85
0
  { lookup_count = 0; }
86
87
  bool lookup_limit_exceeded ()
88
0
  { return lookup_count > HB_MAX_LOOKUP_VISIT_COUNT; }
89
90
  bool should_visit_lookup (unsigned int lookup_index)
91
0
  {
92
0
    if (lookup_count++ > HB_MAX_LOOKUP_VISIT_COUNT)
93
0
      return false;
94
95
0
    if (is_lookup_done (lookup_index))
96
0
      return false;
97
98
0
    return true;
99
0
  }
100
101
  bool is_lookup_done (unsigned int lookup_index)
102
0
  {
103
0
    if (unlikely (done_lookups_glyph_count->in_error () ||
104
0
      done_lookups_glyph_set->in_error ()))
105
0
      return true;
106
107
    /* Have we visited this lookup with the current set of glyphs? */
108
0
    if (done_lookups_glyph_count->get (lookup_index) != glyphs->get_population ())
109
0
    {
110
0
      done_lookups_glyph_count->set (lookup_index, glyphs->get_population ());
111
112
0
      if (!done_lookups_glyph_set->has (lookup_index))
113
0
      {
114
0
  if (unlikely (!done_lookups_glyph_set->set (lookup_index, hb::unique_ptr<hb_set_t> {hb_set_create ()})))
115
0
    return true;
116
0
      }
117
118
0
      done_lookups_glyph_set->get (lookup_index)->clear ();
119
0
    }
120
121
0
    hb_set_t *covered_glyph_set = done_lookups_glyph_set->get (lookup_index);
122
0
    if (unlikely (covered_glyph_set->in_error ()))
123
0
      return true;
124
0
    if (parent_active_glyphs ().is_subset (*covered_glyph_set))
125
0
      return true;
126
127
0
    covered_glyph_set->union_ (parent_active_glyphs ());
128
0
    return false;
129
0
  }
130
131
0
  const hb_set_t& previous_parent_active_glyphs () {
132
0
    if (active_glyphs_stack.length <= 1)
133
0
      return *glyphs;
134
135
0
    return active_glyphs_stack[active_glyphs_stack.length - 2];
136
0
  }
137
138
  const hb_set_t& parent_active_glyphs ()
139
0
  {
140
0
    if (!active_glyphs_stack)
141
0
      return *glyphs;
142
143
0
    return active_glyphs_stack.tail ();
144
0
  }
145
146
  hb_set_t* push_cur_active_glyphs ()
147
0
  {
148
0
    hb_set_t *s = active_glyphs_stack.push ();
149
0
    if (unlikely (active_glyphs_stack.in_error ()))
150
0
      return nullptr;
151
0
    return s;
152
0
  }
153
154
  bool pop_cur_done_glyphs ()
155
0
  {
156
0
    if (!active_glyphs_stack)
157
0
      return false;
158
159
0
    active_glyphs_stack.pop ();
160
0
    return true;
161
0
  }
162
163
  hb_face_t *face;
164
  hb_set_t *glyphs;
165
  hb_set_t output[1];
166
  hb_vector_t<hb_set_t> active_glyphs_stack;
167
  recurse_func_t recurse_func = nullptr;
168
  unsigned int nesting_level_left;
169
170
  hb_closure_context_t (hb_face_t *face_,
171
      hb_set_t *glyphs_,
172
      hb_map_t *done_lookups_glyph_count_,
173
      hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *done_lookups_glyph_set_,
174
      unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
175
0
        face (face_),
176
0
        glyphs (glyphs_),
177
0
        nesting_level_left (nesting_level_left_),
178
0
        done_lookups_glyph_count (done_lookups_glyph_count_),
179
0
        done_lookups_glyph_set (done_lookups_glyph_set_)
180
0
  {}
181
182
0
  ~hb_closure_context_t () { flush (); }
183
184
0
  void set_recurse_func (recurse_func_t func) { recurse_func = func; }
185
186
  void flush ()
187
0
  {
188
0
    output->del_range (face->get_num_glyphs (), HB_SET_VALUE_INVALID);  /* Remove invalid glyphs. */
189
0
    glyphs->union_ (*output);
190
0
    output->clear ();
191
0
    active_glyphs_stack.pop ();
192
0
    active_glyphs_stack.reset ();
193
0
  }
194
195
  private:
196
  hb_map_t *done_lookups_glyph_count;
197
  hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *done_lookups_glyph_set;
198
  unsigned int lookup_count = 0;
199
};
200
201
202
203
struct hb_closure_lookups_context_t :
204
       hb_dispatch_context_t<hb_closure_lookups_context_t>
205
{
206
  typedef return_t (*recurse_func_t) (hb_closure_lookups_context_t *c, unsigned lookup_index);
207
  template <typename T>
208
0
  return_t dispatch (const T &obj) { obj.closure_lookups (this); return hb_empty_t (); }
Unexecuted instantiation: hb_empty_t OT::hb_closure_lookups_context_t::dispatch<OT::Layout::GPOS_impl::SinglePosFormat1>(OT::Layout::GPOS_impl::SinglePosFormat1 const&)
Unexecuted instantiation: hb_empty_t OT::hb_closure_lookups_context_t::dispatch<OT::Layout::GPOS_impl::SinglePosFormat2>(OT::Layout::GPOS_impl::SinglePosFormat2 const&)
Unexecuted instantiation: hb_empty_t OT::hb_closure_lookups_context_t::dispatch<OT::Layout::GPOS_impl::PairPosFormat1_3<OT::Layout::SmallTypes> >(OT::Layout::GPOS_impl::PairPosFormat1_3<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: hb_empty_t OT::hb_closure_lookups_context_t::dispatch<OT::Layout::GPOS_impl::PairPosFormat2_4<OT::Layout::SmallTypes> >(OT::Layout::GPOS_impl::PairPosFormat2_4<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: hb_empty_t OT::hb_closure_lookups_context_t::dispatch<OT::Layout::GPOS_impl::CursivePosFormat1>(OT::Layout::GPOS_impl::CursivePosFormat1 const&)
Unexecuted instantiation: hb_empty_t OT::hb_closure_lookups_context_t::dispatch<OT::Layout::GPOS_impl::MarkBasePosFormat1_2<OT::Layout::SmallTypes> >(OT::Layout::GPOS_impl::MarkBasePosFormat1_2<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: hb_empty_t OT::hb_closure_lookups_context_t::dispatch<OT::Layout::GPOS_impl::MarkLigPosFormat1_2<OT::Layout::SmallTypes> >(OT::Layout::GPOS_impl::MarkLigPosFormat1_2<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: hb_empty_t OT::hb_closure_lookups_context_t::dispatch<OT::Layout::GPOS_impl::MarkMarkPosFormat1_2<OT::Layout::SmallTypes> >(OT::Layout::GPOS_impl::MarkMarkPosFormat1_2<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: hb_empty_t OT::hb_closure_lookups_context_t::dispatch<OT::ContextFormat1_4<OT::Layout::SmallTypes> >(OT::ContextFormat1_4<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: hb_empty_t OT::hb_closure_lookups_context_t::dispatch<OT::ContextFormat2_5<OT::Layout::SmallTypes> >(OT::ContextFormat2_5<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: hb_empty_t OT::hb_closure_lookups_context_t::dispatch<OT::ContextFormat3>(OT::ContextFormat3 const&)
Unexecuted instantiation: hb_empty_t OT::hb_closure_lookups_context_t::dispatch<OT::ChainContextFormat1_4<OT::Layout::SmallTypes> >(OT::ChainContextFormat1_4<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: hb_empty_t OT::hb_closure_lookups_context_t::dispatch<OT::ChainContextFormat2_5<OT::Layout::SmallTypes> >(OT::ChainContextFormat2_5<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: hb_empty_t OT::hb_closure_lookups_context_t::dispatch<OT::ChainContextFormat3>(OT::ChainContextFormat3 const&)
Unexecuted instantiation: hb_empty_t OT::hb_closure_lookups_context_t::dispatch<OT::Layout::GSUB_impl::SingleSubstFormat1_3<OT::Layout::SmallTypes> >(OT::Layout::GSUB_impl::SingleSubstFormat1_3<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: hb_empty_t OT::hb_closure_lookups_context_t::dispatch<OT::Layout::GSUB_impl::SingleSubstFormat2_4<OT::Layout::SmallTypes> >(OT::Layout::GSUB_impl::SingleSubstFormat2_4<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: hb_empty_t OT::hb_closure_lookups_context_t::dispatch<OT::Layout::GSUB_impl::MultipleSubstFormat1_2<OT::Layout::SmallTypes> >(OT::Layout::GSUB_impl::MultipleSubstFormat1_2<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: hb_empty_t OT::hb_closure_lookups_context_t::dispatch<OT::Layout::GSUB_impl::AlternateSubstFormat1_2<OT::Layout::SmallTypes> >(OT::Layout::GSUB_impl::AlternateSubstFormat1_2<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: hb_empty_t OT::hb_closure_lookups_context_t::dispatch<OT::Layout::GSUB_impl::LigatureSubstFormat1_2<OT::Layout::SmallTypes> >(OT::Layout::GSUB_impl::LigatureSubstFormat1_2<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: hb_empty_t OT::hb_closure_lookups_context_t::dispatch<OT::Layout::GSUB_impl::ReverseChainSingleSubstFormat1>(OT::Layout::GSUB_impl::ReverseChainSingleSubstFormat1 const&)
209
0
  static return_t default_return_value () { return hb_empty_t (); }
210
  void recurse (unsigned lookup_index)
211
0
  {
212
0
    if (unlikely (nesting_level_left == 0 || !recurse_func))
213
0
      return;
214
0
215
0
    /* Return if new lookup was recursed to before. */
216
0
    if (lookup_limit_exceeded ()
217
0
        || visited_lookups->in_error ()
218
0
        || visited_lookups->has (lookup_index))
219
0
      // Don't increment lookup count here, that will be done in the call to closure_lookups()
220
0
      // made by recurse_func.
221
0
      return;
222
0
223
0
    nesting_level_left--;
224
0
    recurse_func (this, lookup_index);
225
0
    nesting_level_left++;
226
0
  }
227
228
  void set_lookup_visited (unsigned lookup_index)
229
0
  { visited_lookups->add (lookup_index); }
230
231
  void set_lookup_inactive (unsigned lookup_index)
232
0
  { inactive_lookups->add (lookup_index); }
233
234
  bool lookup_limit_exceeded ()
235
0
  {
236
0
    bool ret = lookup_count > HB_MAX_LOOKUP_VISIT_COUNT;
237
0
    if (ret)
238
0
      DEBUG_MSG (SUBSET, nullptr, "lookup visit count limit exceeded in lookup closure!");
239
0
    return ret; }
240
241
  bool is_lookup_visited (unsigned lookup_index)
242
0
  {
243
0
    if (unlikely (lookup_count++ > HB_MAX_LOOKUP_VISIT_COUNT))
244
0
    {
245
0
      DEBUG_MSG (SUBSET, nullptr, "total visited lookup count %u exceeds max limit, lookup %u is dropped.",
246
0
                 lookup_count, lookup_index);
247
0
      return true;
248
0
    }
249
0
250
0
    if (unlikely (visited_lookups->in_error ()))
251
0
      return true;
252
0
253
0
    return visited_lookups->has (lookup_index);
254
0
  }
255
256
  hb_face_t *face;
257
  const hb_set_t *glyphs;
258
  recurse_func_t recurse_func;
259
  unsigned int nesting_level_left;
260
261
  hb_closure_lookups_context_t (hb_face_t *face_,
262
        const hb_set_t *glyphs_,
263
        hb_set_t *visited_lookups_,
264
        hb_set_t *inactive_lookups_,
265
        unsigned nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
266
        face (face_),
267
        glyphs (glyphs_),
268
        recurse_func (nullptr),
269
        nesting_level_left (nesting_level_left_),
270
        visited_lookups (visited_lookups_),
271
        inactive_lookups (inactive_lookups_),
272
0
        lookup_count (0) {}
273
274
0
  void set_recurse_func (recurse_func_t func) { recurse_func = func; }
275
276
  private:
277
  hb_set_t *visited_lookups;
278
  hb_set_t *inactive_lookups;
279
  unsigned int lookup_count;
280
};
281
282
struct hb_would_apply_context_t :
283
       hb_dispatch_context_t<hb_would_apply_context_t, bool>
284
{
285
  template <typename T>
286
0
  return_t dispatch (const T &obj) { return obj.would_apply (this); }
Unexecuted instantiation: bool OT::hb_would_apply_context_t::dispatch<OT::Layout::GSUB_impl::SingleSubstFormat1_3<OT::Layout::SmallTypes> >(OT::Layout::GSUB_impl::SingleSubstFormat1_3<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: bool OT::hb_would_apply_context_t::dispatch<OT::Layout::GSUB_impl::SingleSubstFormat2_4<OT::Layout::SmallTypes> >(OT::Layout::GSUB_impl::SingleSubstFormat2_4<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: bool OT::hb_would_apply_context_t::dispatch<OT::Layout::GSUB_impl::MultipleSubstFormat1_2<OT::Layout::SmallTypes> >(OT::Layout::GSUB_impl::MultipleSubstFormat1_2<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: bool OT::hb_would_apply_context_t::dispatch<OT::Layout::GSUB_impl::AlternateSubstFormat1_2<OT::Layout::SmallTypes> >(OT::Layout::GSUB_impl::AlternateSubstFormat1_2<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: bool OT::hb_would_apply_context_t::dispatch<OT::Layout::GSUB_impl::LigatureSubstFormat1_2<OT::Layout::SmallTypes> >(OT::Layout::GSUB_impl::LigatureSubstFormat1_2<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: bool OT::hb_would_apply_context_t::dispatch<OT::ContextFormat1_4<OT::Layout::SmallTypes> >(OT::ContextFormat1_4<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: bool OT::hb_would_apply_context_t::dispatch<OT::ContextFormat2_5<OT::Layout::SmallTypes> >(OT::ContextFormat2_5<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: bool OT::hb_would_apply_context_t::dispatch<OT::ContextFormat3>(OT::ContextFormat3 const&)
Unexecuted instantiation: bool OT::hb_would_apply_context_t::dispatch<OT::ChainContextFormat1_4<OT::Layout::SmallTypes> >(OT::ChainContextFormat1_4<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: bool OT::hb_would_apply_context_t::dispatch<OT::ChainContextFormat2_5<OT::Layout::SmallTypes> >(OT::ChainContextFormat2_5<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: bool OT::hb_would_apply_context_t::dispatch<OT::ChainContextFormat3>(OT::ChainContextFormat3 const&)
Unexecuted instantiation: bool OT::hb_would_apply_context_t::dispatch<OT::Layout::GSUB_impl::ReverseChainSingleSubstFormat1>(OT::Layout::GSUB_impl::ReverseChainSingleSubstFormat1 const&)
287
0
  static return_t default_return_value () { return false; }
288
0
  bool stop_sublookup_iteration (return_t r) const { return r; }
289
290
  hb_face_t *face;
291
  const hb_codepoint_t *glyphs;
292
  unsigned int len;
293
  bool zero_context;
294
295
  hb_would_apply_context_t (hb_face_t *face_,
296
          const hb_codepoint_t *glyphs_,
297
          unsigned int len_,
298
          bool zero_context_) :
299
0
            face (face_),
300
0
            glyphs (glyphs_),
301
0
            len (len_),
302
0
            zero_context (zero_context_) {}
303
};
304
305
struct hb_collect_glyphs_context_t :
306
       hb_dispatch_context_t<hb_collect_glyphs_context_t>
307
{
308
  typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index);
309
  template <typename T>
310
0
  return_t dispatch (const T &obj) { obj.collect_glyphs (this); return hb_empty_t (); }
Unexecuted instantiation: hb_empty_t OT::hb_collect_glyphs_context_t::dispatch<OT::Layout::GPOS_impl::SinglePosFormat1>(OT::Layout::GPOS_impl::SinglePosFormat1 const&)
Unexecuted instantiation: hb_empty_t OT::hb_collect_glyphs_context_t::dispatch<OT::Layout::GPOS_impl::SinglePosFormat2>(OT::Layout::GPOS_impl::SinglePosFormat2 const&)
Unexecuted instantiation: hb_empty_t OT::hb_collect_glyphs_context_t::dispatch<OT::Layout::GPOS_impl::PairPosFormat1_3<OT::Layout::SmallTypes> >(OT::Layout::GPOS_impl::PairPosFormat1_3<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: hb_empty_t OT::hb_collect_glyphs_context_t::dispatch<OT::Layout::GPOS_impl::PairPosFormat2_4<OT::Layout::SmallTypes> >(OT::Layout::GPOS_impl::PairPosFormat2_4<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: hb_empty_t OT::hb_collect_glyphs_context_t::dispatch<OT::Layout::GPOS_impl::CursivePosFormat1>(OT::Layout::GPOS_impl::CursivePosFormat1 const&)
Unexecuted instantiation: hb_empty_t OT::hb_collect_glyphs_context_t::dispatch<OT::Layout::GPOS_impl::MarkBasePosFormat1_2<OT::Layout::SmallTypes> >(OT::Layout::GPOS_impl::MarkBasePosFormat1_2<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: hb_empty_t OT::hb_collect_glyphs_context_t::dispatch<OT::Layout::GPOS_impl::MarkLigPosFormat1_2<OT::Layout::SmallTypes> >(OT::Layout::GPOS_impl::MarkLigPosFormat1_2<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: hb_empty_t OT::hb_collect_glyphs_context_t::dispatch<OT::Layout::GPOS_impl::MarkMarkPosFormat1_2<OT::Layout::SmallTypes> >(OT::Layout::GPOS_impl::MarkMarkPosFormat1_2<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: hb_empty_t OT::hb_collect_glyphs_context_t::dispatch<OT::ContextFormat1_4<OT::Layout::SmallTypes> >(OT::ContextFormat1_4<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: hb_empty_t OT::hb_collect_glyphs_context_t::dispatch<OT::ContextFormat2_5<OT::Layout::SmallTypes> >(OT::ContextFormat2_5<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: hb_empty_t OT::hb_collect_glyphs_context_t::dispatch<OT::ContextFormat3>(OT::ContextFormat3 const&)
Unexecuted instantiation: hb_empty_t OT::hb_collect_glyphs_context_t::dispatch<OT::ChainContextFormat1_4<OT::Layout::SmallTypes> >(OT::ChainContextFormat1_4<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: hb_empty_t OT::hb_collect_glyphs_context_t::dispatch<OT::ChainContextFormat2_5<OT::Layout::SmallTypes> >(OT::ChainContextFormat2_5<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: hb_empty_t OT::hb_collect_glyphs_context_t::dispatch<OT::ChainContextFormat3>(OT::ChainContextFormat3 const&)
Unexecuted instantiation: hb_empty_t OT::hb_collect_glyphs_context_t::dispatch<OT::Layout::GSUB_impl::SingleSubstFormat1_3<OT::Layout::SmallTypes> >(OT::Layout::GSUB_impl::SingleSubstFormat1_3<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: hb_empty_t OT::hb_collect_glyphs_context_t::dispatch<OT::Layout::GSUB_impl::SingleSubstFormat2_4<OT::Layout::SmallTypes> >(OT::Layout::GSUB_impl::SingleSubstFormat2_4<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: hb_empty_t OT::hb_collect_glyphs_context_t::dispatch<OT::Layout::GSUB_impl::MultipleSubstFormat1_2<OT::Layout::SmallTypes> >(OT::Layout::GSUB_impl::MultipleSubstFormat1_2<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: hb_empty_t OT::hb_collect_glyphs_context_t::dispatch<OT::Layout::GSUB_impl::AlternateSubstFormat1_2<OT::Layout::SmallTypes> >(OT::Layout::GSUB_impl::AlternateSubstFormat1_2<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: hb_empty_t OT::hb_collect_glyphs_context_t::dispatch<OT::Layout::GSUB_impl::LigatureSubstFormat1_2<OT::Layout::SmallTypes> >(OT::Layout::GSUB_impl::LigatureSubstFormat1_2<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: hb_empty_t OT::hb_collect_glyphs_context_t::dispatch<OT::Layout::GSUB_impl::ReverseChainSingleSubstFormat1>(OT::Layout::GSUB_impl::ReverseChainSingleSubstFormat1 const&)
311
0
  static return_t default_return_value () { return hb_empty_t (); }
312
  void recurse (unsigned int lookup_index)
313
0
  {
314
0
    if (unlikely (nesting_level_left == 0 || !recurse_func))
315
0
      return;
316
317
    /* Note that GPOS sets recurse_func to nullptr already, so it doesn't get
318
     * past the previous check.  For GSUB, we only want to collect the output
319
     * glyphs in the recursion.  If output is not requested, we can go home now.
320
     *
321
     * Note further, that the above is not exactly correct.  A recursed lookup
322
     * is allowed to match input that is not matched in the context, but that's
323
     * not how most fonts are built.  It's possible to relax that and recurse
324
     * with all sets here if it proves to be an issue.
325
     */
326
327
0
    if (output == hb_set_get_empty ())
328
0
      return;
329
330
    /* Return if new lookup was recursed to before. */
331
0
    if (recursed_lookups->has (lookup_index))
332
0
      return;
333
334
0
    hb_set_t *old_before = before;
335
0
    hb_set_t *old_input  = input;
336
0
    hb_set_t *old_after  = after;
337
0
    before = input = after = hb_set_get_empty ();
338
339
0
    nesting_level_left--;
340
0
    recurse_func (this, lookup_index);
341
0
    nesting_level_left++;
342
343
0
    before = old_before;
344
0
    input  = old_input;
345
0
    after  = old_after;
346
347
0
    recursed_lookups->add (lookup_index);
348
0
  }
349
350
  hb_face_t *face;
351
  hb_set_t *before;
352
  hb_set_t *input;
353
  hb_set_t *after;
354
  hb_set_t *output;
355
  recurse_func_t recurse_func;
356
  hb_set_t *recursed_lookups;
357
  unsigned int nesting_level_left;
358
359
  hb_collect_glyphs_context_t (hb_face_t *face_,
360
             hb_set_t  *glyphs_before, /* OUT.  May be NULL */
361
             hb_set_t  *glyphs_input,  /* OUT.  May be NULL */
362
             hb_set_t  *glyphs_after,  /* OUT.  May be NULL */
363
             hb_set_t  *glyphs_output, /* OUT.  May be NULL */
364
             unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
365
0
            face (face_),
366
0
            before (glyphs_before ? glyphs_before : hb_set_get_empty ()),
367
0
            input  (glyphs_input  ? glyphs_input  : hb_set_get_empty ()),
368
0
            after  (glyphs_after  ? glyphs_after  : hb_set_get_empty ()),
369
0
            output (glyphs_output ? glyphs_output : hb_set_get_empty ()),
370
0
            recurse_func (nullptr),
371
0
            recursed_lookups (hb_set_create ()),
372
0
            nesting_level_left (nesting_level_left_) {}
373
0
  ~hb_collect_glyphs_context_t () { hb_set_destroy (recursed_lookups); }
374
375
0
  void set_recurse_func (recurse_func_t func) { recurse_func = func; }
376
};
377
378
379
380
template <typename set_t>
381
struct hb_collect_coverage_context_t :
382
       hb_dispatch_context_t<hb_collect_coverage_context_t<set_t>, const Coverage &>
383
{
384
  typedef const Coverage &return_t; // Stoopid that we have to dupe this here.
385
  template <typename T>
386
  return_t dispatch (const T &obj) { return obj.get_coverage (); }
387
  static return_t default_return_value () { return Null (Coverage); }
388
  bool stop_sublookup_iteration (return_t r) const
389
  {
390
    r.collect_coverage (set);
391
    return false;
392
  }
393
394
  hb_collect_coverage_context_t (set_t *set_) :
395
           set (set_) {}
396
397
  set_t *set;
398
};
399
400
struct matcher_t
401
{
402
  typedef bool (*match_func_t) (hb_glyph_info_t &info, unsigned value, const void *data);
403
404
  template <typename context_t>
405
  void init (const context_t *c, bool context_match = false)
406
115M
  {
407
115M
    set_match_func (nullptr, nullptr);
408
115M
    lookup_props = c->lookup_props;
409
    /* Ignore ZWNJ if we are matching GPOS, or matching GSUB context and asked to. */
410
115M
    ignore_zwnj = c->table_index == 1 || (context_match && c->auto_zwnj);
411
    /* Ignore ZWJ if we are matching context, or asked to. */
412
115M
    ignore_zwj = context_match || c->auto_zwj;
413
    /* Ignore hidden glyphs (like CGJ) during GPOS. */
414
115M
    ignore_hidden = c->table_index == 1;
415
115M
    mask = context_match ? -1 : c->lookup_mask;
416
    /* Per syllable matching is only for GSUB. */
417
115M
    per_syllable = c->table_index == 0 && c->per_syllable;
418
115M
    syllable = 0;
419
115M
  }
420
421
  void set_match_func (match_func_t match_func_,
422
           const void *match_data_)
423
116M
  { match_func = match_func_; match_data = match_data_; }
424
425
  enum may_match_t {
426
    MATCH_NO,
427
    MATCH_YES,
428
    MATCH_MAYBE
429
  };
430
431
#ifndef HB_OPTIMIZE_SIZE
432
  HB_ALWAYS_INLINE
433
#endif
434
  may_match_t may_match (hb_glyph_info_t &info,
435
       hb_codepoint_t glyph_data) const
436
15.0M
  {
437
15.0M
    if (!(info.mask & mask) ||
438
15.0M
  (per_syllable && syllable && syllable != info.syllable ()))
439
0
      return MATCH_NO;
440
441
15.0M
    if (match_func)
442
890k
      return match_func (info, glyph_data, match_data) ? MATCH_YES : MATCH_NO;
443
444
14.1M
    return MATCH_MAYBE;
445
15.0M
  }
446
447
  enum may_skip_t {
448
    SKIP_NO,
449
    SKIP_YES,
450
    SKIP_MAYBE
451
  };
452
453
  template <typename context_t>
454
#ifndef HB_OPTIMIZE_SIZE
455
  HB_ALWAYS_INLINE
456
#endif
457
  may_skip_t may_skip (const context_t *c,
458
           const hb_glyph_info_t &info) const
459
15.1M
  {
460
15.1M
    if (!c->check_glyph_property (&info, lookup_props))
461
86.5k
      return SKIP_YES;
462
463
15.0M
    if (unlikely (_hb_glyph_info_is_default_ignorable (&info) &&
464
15.0M
      (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) &&
465
15.0M
      (ignore_zwj || !_hb_glyph_info_is_zwj (&info)) &&
466
15.0M
      (ignore_hidden || !_hb_glyph_info_is_hidden (&info))))
467
15.3k
      return SKIP_MAYBE;
468
469
15.0M
    return SKIP_NO;
470
15.0M
  }
471
472
  public:
473
  unsigned int lookup_props = 0;
474
  hb_mask_t mask = -1;
475
  bool ignore_zwnj = false;
476
  bool ignore_zwj = false;
477
  bool ignore_hidden = false;
478
  bool per_syllable = false;
479
  uint8_t syllable = 0;
480
  match_func_t match_func = nullptr;
481
  const void *match_data = nullptr;
482
};
483
484
template <typename context_t>
485
struct skipping_iterator_t
486
{
487
  void init (context_t *c_, bool context_match = false)
488
115M
  {
489
115M
    c = c_;
490
115M
    end = c->buffer->len;
491
115M
    match_glyph_data16 = nullptr;
492
#ifndef HB_NO_BEYOND_64K
493
    match_glyph_data24 = nullptr;
494
#endif
495
115M
    matcher.init (c, context_match);
496
115M
  }
497
  void set_lookup_props (unsigned int lookup_props)
498
458k
  {
499
458k
    matcher.lookup_props = lookup_props;
500
458k
  }
501
  void set_match_func (matcher_t::match_func_t match_func_,
502
           const void *match_data_)
503
1.46M
  {
504
1.46M
    matcher.set_match_func (match_func_, match_data_);
505
1.46M
  }
506
  void set_glyph_data (const HBUINT16 glyph_data[])
507
1.46M
  {
508
1.46M
    match_glyph_data16 = glyph_data;
509
#ifndef HB_NO_BEYOND_64K
510
    match_glyph_data24 = nullptr;
511
#endif
512
1.46M
  }
513
#ifndef HB_NO_BEYOND_64K
514
  void set_glyph_data (const HBUINT24 glyph_data[])
515
  {
516
    match_glyph_data16 = nullptr;
517
    match_glyph_data24 = glyph_data;
518
  }
519
#endif
520
521
#ifndef HB_OPTIMIZE_SIZE
522
  HB_ALWAYS_INLINE
523
#endif
524
  void reset (unsigned int start_index_)
525
896k
  {
526
    // For GSUB forward iterator
527
896k
    idx = start_index_;
528
896k
    end = c->buffer->len;
529
896k
    matcher.syllable = c->buffer->cur().syllable();
530
896k
  }
531
  void reset_back (unsigned int start_index_, bool from_out_buffer = false)
532
569k
  {
533
    // For GSUB backward iterator
534
569k
    idx = start_index_;
535
569k
    matcher.syllable = c->buffer->cur().syllable();
536
569k
  }
537
538
#ifndef HB_OPTIMIZE_SIZE
539
  HB_ALWAYS_INLINE
540
#endif
541
  void reset_fast (unsigned int start_index_)
542
15.4M
  {
543
    // Doesn't set end or syllable. Used by GPOS which doesn't care / change.
544
15.4M
    idx = start_index_;
545
15.4M
  }
546
547
#ifndef HB_OPTIMIZE_SIZE
548
  HB_ALWAYS_INLINE
549
#endif
550
  matcher_t::may_skip_t may_skip (const hb_glyph_info_t &info) const
551
24.3k
  { return matcher.may_skip (c, info); }
552
553
  enum match_t {
554
    MATCH,
555
    NOT_MATCH,
556
    SKIP
557
  };
558
559
#ifndef HB_OPTIMIZE_SIZE
560
  HB_ALWAYS_INLINE
561
#endif
562
  match_t match (hb_glyph_info_t &info)
563
15.1M
  {
564
15.1M
    matcher_t::may_skip_t skip = matcher.may_skip (c, info);
565
15.1M
    if (unlikely (skip == matcher_t::SKIP_YES))
566
86.5k
      return SKIP;
567
568
15.0M
    matcher_t::may_match_t match = matcher.may_match (info, get_glyph_data ());
569
15.0M
    if (match == matcher_t::MATCH_YES ||
570
14.8M
  (match == matcher_t::MATCH_MAYBE &&
571
14.1M
   skip == matcher_t::SKIP_NO))
572
14.4M
      return MATCH;
573
574
660k
    if (skip == matcher_t::SKIP_NO)
575
645k
      return NOT_MATCH;
576
577
15.1k
    return SKIP;
578
660k
  }
579
580
#ifndef HB_OPTIMIZE_SIZE
581
  HB_ALWAYS_INLINE
582
#endif
583
  bool next (unsigned *unsafe_to = nullptr)
584
16.1M
  {
585
16.1M
    auto *info = c->buffer->info;
586
16.1M
    const signed stop = (signed) end - 1;
587
16.1M
    while ((signed) idx < stop)
588
14.3M
    {
589
14.3M
      idx++;
590
14.3M
      switch (match (info[idx]))
591
14.3M
      {
592
13.9M
  case MATCH:
593
13.9M
  {
594
13.9M
    advance_glyph_data ();
595
13.9M
    return true;
596
0
  }
597
302k
  case NOT_MATCH:
598
302k
  {
599
302k
    if (unsafe_to)
600
302k
      *unsafe_to = idx + 1;
601
302k
    return false;
602
0
  }
603
50.0k
  case SKIP:
604
50.0k
    continue;
605
14.3M
      }
606
14.3M
    }
607
1.87M
    if (unsafe_to)
608
1.87M
      *unsafe_to = end;
609
1.87M
    return false;
610
16.1M
  }
611
#ifndef HB_OPTIMIZE_SIZE
612
  HB_ALWAYS_INLINE
613
#endif
614
  bool prev (unsigned *unsafe_from = nullptr)
615
804k
  {
616
804k
    auto *out_info = c->buffer->out_info;
617
804k
    const unsigned stop = 0;
618
805k
    while (idx > stop)
619
572k
    {
620
572k
      idx--;
621
572k
      switch (match (out_info[idx]))
622
572k
      {
623
228k
  case MATCH:
624
228k
  {
625
228k
    advance_glyph_data ();
626
228k
    return true;
627
0
  }
628
343k
  case NOT_MATCH:
629
343k
  {
630
343k
    if (unsafe_from)
631
343k
      *unsafe_from = hb_max (1u, idx) - 1u;
632
343k
    return false;
633
0
  }
634
801
  case SKIP:
635
801
    continue;
636
572k
      }
637
572k
    }
638
232k
    if (unsafe_from)
639
232k
      *unsafe_from = 0;
640
232k
    return false;
641
804k
  }
642
643
  HB_ALWAYS_INLINE
644
  hb_codepoint_t
645
  get_glyph_data ()
646
15.0M
  {
647
15.0M
    if (match_glyph_data16) return *match_glyph_data16;
648
#ifndef HB_NO_BEYOND_64K
649
    else
650
    if (match_glyph_data24) return *match_glyph_data24;
651
#endif
652
14.1M
    return 0;
653
15.0M
  }
654
  HB_ALWAYS_INLINE
655
  void
656
  advance_glyph_data ()
657
14.2M
  {
658
14.2M
    if (match_glyph_data16) match_glyph_data16++;
659
#ifndef HB_NO_BEYOND_64K
660
    else
661
    if (match_glyph_data24) match_glyph_data24++;
662
#endif
663
14.2M
  }
664
665
  unsigned int idx;
666
  protected:
667
  context_t *c;
668
  matcher_t matcher;
669
  const HBUINT16 *match_glyph_data16;
670
#ifndef HB_NO_BEYOND_64K
671
  const HBUINT24 *match_glyph_data24;
672
#endif
673
674
  unsigned int end;
675
};
676
677
struct hb_ot_apply_context_t :
678
       hb_dispatch_context_t<hb_ot_apply_context_t, bool, HB_DEBUG_APPLY>
679
{
680
0
  const char *get_name () { return "APPLY"; }
681
  typedef return_t (*recurse_func_t) (hb_ot_apply_context_t *c, unsigned int lookup_index);
682
683
  template <typename T>
684
  static inline auto apply_ (const T &obj, hb_ot_apply_context_t *c, hb_priority<1>) HB_RETURN (return_t, obj.apply (c, nullptr) )
685
  template <typename T>
686
  static inline auto apply_ (const T &obj, hb_ot_apply_context_t *c, hb_priority<0>) HB_RETURN (return_t, obj.apply (c) )
687
  template <typename T>
688
0
  return_t dispatch (const T &obj) { return apply_(obj, this, hb_prioritize); }
Unexecuted instantiation: bool OT::hb_ot_apply_context_t::dispatch<OT::Layout::GPOS_impl::SinglePosFormat1>(OT::Layout::GPOS_impl::SinglePosFormat1 const&)
Unexecuted instantiation: bool OT::hb_ot_apply_context_t::dispatch<OT::Layout::GPOS_impl::SinglePosFormat2>(OT::Layout::GPOS_impl::SinglePosFormat2 const&)
Unexecuted instantiation: bool OT::hb_ot_apply_context_t::dispatch<OT::Layout::GPOS_impl::PairPosFormat1_3<OT::Layout::SmallTypes> >(OT::Layout::GPOS_impl::PairPosFormat1_3<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: bool OT::hb_ot_apply_context_t::dispatch<OT::Layout::GPOS_impl::PairPosFormat2_4<OT::Layout::SmallTypes> >(OT::Layout::GPOS_impl::PairPosFormat2_4<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: bool OT::hb_ot_apply_context_t::dispatch<OT::Layout::GPOS_impl::CursivePosFormat1>(OT::Layout::GPOS_impl::CursivePosFormat1 const&)
Unexecuted instantiation: bool OT::hb_ot_apply_context_t::dispatch<OT::Layout::GPOS_impl::MarkBasePosFormat1_2<OT::Layout::SmallTypes> >(OT::Layout::GPOS_impl::MarkBasePosFormat1_2<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: bool OT::hb_ot_apply_context_t::dispatch<OT::Layout::GPOS_impl::MarkLigPosFormat1_2<OT::Layout::SmallTypes> >(OT::Layout::GPOS_impl::MarkLigPosFormat1_2<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: bool OT::hb_ot_apply_context_t::dispatch<OT::Layout::GPOS_impl::MarkMarkPosFormat1_2<OT::Layout::SmallTypes> >(OT::Layout::GPOS_impl::MarkMarkPosFormat1_2<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: bool OT::hb_ot_apply_context_t::dispatch<OT::ContextFormat1_4<OT::Layout::SmallTypes> >(OT::ContextFormat1_4<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: bool OT::hb_ot_apply_context_t::dispatch<OT::ContextFormat2_5<OT::Layout::SmallTypes> >(OT::ContextFormat2_5<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: bool OT::hb_ot_apply_context_t::dispatch<OT::ContextFormat3>(OT::ContextFormat3 const&)
Unexecuted instantiation: bool OT::hb_ot_apply_context_t::dispatch<OT::ChainContextFormat1_4<OT::Layout::SmallTypes> >(OT::ChainContextFormat1_4<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: bool OT::hb_ot_apply_context_t::dispatch<OT::ChainContextFormat2_5<OT::Layout::SmallTypes> >(OT::ChainContextFormat2_5<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: bool OT::hb_ot_apply_context_t::dispatch<OT::ChainContextFormat3>(OT::ChainContextFormat3 const&)
Unexecuted instantiation: bool OT::hb_ot_apply_context_t::dispatch<OT::Layout::GSUB_impl::SingleSubstFormat1_3<OT::Layout::SmallTypes> >(OT::Layout::GSUB_impl::SingleSubstFormat1_3<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: bool OT::hb_ot_apply_context_t::dispatch<OT::Layout::GSUB_impl::SingleSubstFormat2_4<OT::Layout::SmallTypes> >(OT::Layout::GSUB_impl::SingleSubstFormat2_4<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: bool OT::hb_ot_apply_context_t::dispatch<OT::Layout::GSUB_impl::MultipleSubstFormat1_2<OT::Layout::SmallTypes> >(OT::Layout::GSUB_impl::MultipleSubstFormat1_2<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: bool OT::hb_ot_apply_context_t::dispatch<OT::Layout::GSUB_impl::AlternateSubstFormat1_2<OT::Layout::SmallTypes> >(OT::Layout::GSUB_impl::AlternateSubstFormat1_2<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: bool OT::hb_ot_apply_context_t::dispatch<OT::Layout::GSUB_impl::LigatureSubstFormat1_2<OT::Layout::SmallTypes> >(OT::Layout::GSUB_impl::LigatureSubstFormat1_2<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: bool OT::hb_ot_apply_context_t::dispatch<OT::Layout::GSUB_impl::ReverseChainSingleSubstFormat1>(OT::Layout::GSUB_impl::ReverseChainSingleSubstFormat1 const&)
689
690
0
  static return_t default_return_value () { return false; }
691
0
  bool stop_sublookup_iteration (return_t r) const { return r; }
692
  return_t recurse (unsigned int sub_lookup_index)
693
10.9k
  {
694
10.9k
    assert (recurse_func);
695
10.9k
    if (unlikely (nesting_level_left == 0))
696
0
    {
697
0
      buffer->successful = false;
698
0
      return default_return_value ();
699
0
    }
700
701
10.9k
    buffer->max_ops--;
702
10.9k
    if (unlikely (buffer->max_ops < 0))
703
0
    {
704
0
      buffer->successful = false;
705
0
      return default_return_value ();
706
0
    }
707
708
10.9k
    nesting_level_left--;
709
10.9k
    bool ret = recurse_func (this, sub_lookup_index);
710
10.9k
    nesting_level_left++;
711
10.9k
    return ret;
712
10.9k
  }
713
714
  skipping_iterator_t<hb_ot_apply_context_t> iter_input, iter_context;
715
716
  unsigned int table_index; /* GSUB/GPOS */
717
  hb_font_t *font;
718
  hb_face_t *face;
719
  hb_buffer_t *buffer;
720
  hb_sanitize_context_t sanitizer;
721
  recurse_func_t recurse_func = nullptr;
722
  const GDEF &gdef;
723
  const GDEF::accelerator_t &gdef_accel;
724
  const hb_ot_layout_lookup_accelerator_t *lookup_accel = nullptr;
725
  const ItemVariationStore &var_store;
726
  hb_scalar_cache_t *var_store_cache;
727
728
  hb_direction_t direction;
729
  hb_mask_t lookup_mask = 1;
730
  unsigned int lookup_index = (unsigned) -1;
731
  unsigned int lookup_props = 0;
732
  unsigned int nesting_level_left = HB_MAX_NESTING_LEVEL;
733
734
  bool has_glyph_classes;
735
  bool auto_zwnj = true;
736
  bool auto_zwj = true;
737
  bool per_syllable = false;
738
  bool random = false;
739
  unsigned new_syllables = (unsigned) -1;
740
741
  signed last_base = -1; // GPOS uses
742
  unsigned last_base_until = 0; // GPOS uses
743
744
  hb_vector_t<uint32_t> match_positions;
745
  uint32_t stack_match_positions[8];
746
747
  hb_ot_apply_context_t (unsigned int table_index_,
748
       hb_font_t *font_,
749
       hb_buffer_t *buffer_,
750
       hb_blob_t *table_blob_,
751
       hb_scalar_cache_t *var_store_cache_ = nullptr) :
752
50.3M
      table_index (table_index_),
753
50.3M
      font (font_), face (font->face), buffer (buffer_),
754
50.3M
      sanitizer (table_blob_),
755
      gdef (
756
#ifndef HB_NO_OT_LAYOUT
757
50.3M
            *face->table.GDEF->table
758
#else
759
            Null (GDEF)
760
#endif
761
           ),
762
      gdef_accel (
763
#ifndef HB_NO_OT_LAYOUT
764
50.3M
            *face->table.GDEF
765
#else
766
            Null (GDEF::accelerator_t)
767
#endif
768
           ),
769
50.3M
      var_store (gdef.get_var_store ()),
770
50.3M
      var_store_cache (var_store_cache_),
771
50.3M
      direction (buffer_->props.direction),
772
50.3M
      has_glyph_classes (gdef.has_glyph_classes ())
773
50.3M
  {
774
50.3M
    init_iters ();
775
50.3M
    match_positions.set_storage (stack_match_positions);
776
50.3M
  }
777
778
  void init_iters ()
779
57.6M
  {
780
57.6M
    iter_input.init (this, false);
781
57.6M
    iter_context.init (this, true);
782
57.6M
  }
783
784
6.72M
  void set_lookup_mask (hb_mask_t mask, bool init = true) { lookup_mask = mask; last_base = -1; last_base_until = 0; if (init) init_iters (); }
785
6.15M
  void set_auto_zwj (bool auto_zwj_, bool init = true) { auto_zwj = auto_zwj_; if (init) init_iters (); }
786
6.15M
  void set_auto_zwnj (bool auto_zwnj_, bool init = true) { auto_zwnj = auto_zwnj_; if (init) init_iters (); }
787
6.15M
  void set_per_syllable (bool per_syllable_, bool init = true) { per_syllable = per_syllable_; if (init) init_iters (); }
788
6.15M
  void set_random (bool random_) { random = random_; }
789
49.2M
  void set_recurse_func (recurse_func_t func) { recurse_func = func; }
790
6.17M
  void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; }
791
  void set_lookup_props (unsigned int lookup_props_)
792
6.74M
  {
793
6.74M
    lookup_props = gdef_accel.sanitize_lookup_props (lookup_props_);
794
6.74M
    init_iters ();
795
6.74M
  }
796
797
  uint32_t random_number ()
798
0
  {
799
    /* http://www.cplusplus.com/reference/random/minstd_rand/ */
800
0
    buffer->random_state = buffer->random_state * 48271 % 2147483647;
801
0
    return buffer->random_state;
802
0
  }
803
804
  HB_ALWAYS_INLINE
805
  HB_HOT
806
  bool match_properties_mark (const hb_glyph_info_t *info,
807
            unsigned int    glyph_props,
808
            unsigned int    match_props) const
809
937k
  {
810
    /* If using mark filtering sets, the high short of
811
     * match_props has the set index.
812
     */
813
937k
    if (match_props & LookupFlag::UseMarkFilteringSet)
814
0
      return gdef_accel.mark_set_covers (match_props >> 16, info->codepoint);
815
816
    /* The second byte of match_props has the meaning
817
     * "ignore marks of attachment type different than
818
     * the attachment type specified."
819
     */
820
937k
    if (match_props & LookupFlag::MarkAttachmentType)
821
240
      return (match_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType);
822
823
937k
    return true;
824
937k
  }
825
826
#ifndef HB_OPTIMIZE_SIZE
827
  HB_ALWAYS_INLINE
828
#endif
829
  bool check_glyph_property (const hb_glyph_info_t *info,
830
           unsigned match_props) const
831
132M
  {
832
132M
    unsigned int glyph_props = _hb_glyph_info_get_glyph_props (info);
833
834
    /* Not covered, if, for example, glyph class is ligature and
835
     * match_props includes LookupFlags::IgnoreLigatures
836
     */
837
132M
    if (glyph_props & match_props & LookupFlag::IgnoreFlags)
838
86.3k
      return false;
839
840
132M
    if (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK)
841
937k
      return match_properties_mark (info, glyph_props, match_props);
842
843
131M
    return true;
844
132M
  }
845
846
  void _set_glyph_class (hb_codepoint_t glyph_index,
847
        unsigned int class_guess = 0,
848
        bool ligature = false,
849
        bool component = false)
850
22.6k
  {
851
22.6k
    buffer->digest.add (glyph_index);
852
853
22.6k
    if (new_syllables != (unsigned) -1)
854
0
      buffer->cur().syllable() = new_syllables;
855
856
22.6k
    unsigned int props = _hb_glyph_info_get_glyph_props (&buffer->cur());
857
22.6k
    props |= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED;
858
22.6k
    if (ligature)
859
22.6k
    {
860
22.6k
      props |= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED;
861
      /* In the only place that the MULTIPLIED bit is used, Uniscribe
862
       * seems to only care about the "last" transformation between
863
       * Ligature and Multiple substitutions.  Ie. if you ligate, expand,
864
       * and ligate again, it forgives the multiplication and acts as
865
       * if only ligation happened.  As such, clear MULTIPLIED bit.
866
       */
867
22.6k
      props &= ~HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
868
22.6k
    }
869
22.6k
    if (component)
870
0
      props |= HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
871
22.6k
    if (likely (has_glyph_classes))
872
22.6k
    {
873
22.6k
      props &= HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE;
874
22.6k
      _hb_glyph_info_set_glyph_props (&buffer->cur(), props | gdef_accel.get_glyph_props (glyph_index));
875
22.6k
    }
876
0
    else if (class_guess)
877
0
    {
878
0
      props &= HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE;
879
0
      _hb_glyph_info_set_glyph_props (&buffer->cur(), props | class_guess);
880
0
    }
881
0
    else
882
0
      _hb_glyph_info_set_glyph_props (&buffer->cur(), props);
883
22.6k
  }
884
885
  void replace_glyph (hb_codepoint_t glyph_index)
886
0
  {
887
0
    _set_glyph_class (glyph_index);
888
0
    (void) buffer->replace_glyph (glyph_index);
889
0
  }
890
  void replace_glyph_inplace (hb_codepoint_t glyph_index)
891
0
  {
892
0
    _set_glyph_class (glyph_index);
893
0
    buffer->cur().codepoint = glyph_index;
894
0
  }
895
  void replace_glyph_with_ligature (hb_codepoint_t glyph_index,
896
            unsigned int class_guess)
897
22.6k
  {
898
22.6k
    _set_glyph_class (glyph_index, class_guess, true);
899
22.6k
    (void) buffer->replace_glyph (glyph_index);
900
22.6k
  }
901
  void output_glyph_for_component (hb_codepoint_t glyph_index,
902
           unsigned int class_guess)
903
0
  {
904
0
    _set_glyph_class (glyph_index, class_guess, false, true);
905
0
    (void) buffer->output_glyph (glyph_index);
906
0
  }
907
};
908
909
enum class hb_ot_subtable_cache_op_t
910
{
911
  ENTER,
912
  LEAVE,
913
};
914
915
struct hb_accelerate_subtables_context_t :
916
       hb_dispatch_context_t<hb_accelerate_subtables_context_t>
917
{
918
  template <typename T>
919
  static inline auto apply_ (const T *obj, hb_ot_apply_context_t *c, void *external_cache, hb_priority<1>) HB_RETURN (bool, obj->apply (c, external_cache) )
920
  template <typename T>
921
  static inline auto apply_ (const T *obj, hb_ot_apply_context_t *c, void *external_cache, hb_priority<0>) HB_RETURN (bool, obj->apply (c) )
922
  template <typename T>
923
  static inline bool apply_to (const void *obj, hb_ot_apply_context_t *c, void *external_cache)
924
118M
  {
925
118M
    const T *typed_obj = (const T *) obj;
926
118M
    return apply_ (typed_obj, c, external_cache, hb_prioritize);
927
118M
  }
bool OT::hb_accelerate_subtables_context_t::apply_to<OT::Layout::GPOS_impl::SinglePosFormat1>(void const*, OT::hb_ot_apply_context_t*, void*)
Line
Count
Source
924
822
  {
925
822
    const T *typed_obj = (const T *) obj;
926
822
    return apply_ (typed_obj, c, external_cache, hb_prioritize);
927
822
  }
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::apply_to<OT::Layout::GPOS_impl::SinglePosFormat2>(void const*, OT::hb_ot_apply_context_t*, void*)
bool OT::hb_accelerate_subtables_context_t::apply_to<OT::Layout::GPOS_impl::PairPosFormat1_3<OT::Layout::SmallTypes> >(void const*, OT::hb_ot_apply_context_t*, void*)
Line
Count
Source
924
116M
  {
925
116M
    const T *typed_obj = (const T *) obj;
926
116M
    return apply_ (typed_obj, c, external_cache, hb_prioritize);
927
116M
  }
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::apply_to<OT::Layout::GPOS_impl::PairPosFormat2_4<OT::Layout::SmallTypes> >(void const*, OT::hb_ot_apply_context_t*, void*)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::apply_to<OT::Layout::GPOS_impl::CursivePosFormat1>(void const*, OT::hb_ot_apply_context_t*, void*)
bool OT::hb_accelerate_subtables_context_t::apply_to<OT::Layout::GPOS_impl::MarkBasePosFormat1_2<OT::Layout::SmallTypes> >(void const*, OT::hb_ot_apply_context_t*, void*)
Line
Count
Source
924
372k
  {
925
372k
    const T *typed_obj = (const T *) obj;
926
372k
    return apply_ (typed_obj, c, external_cache, hb_prioritize);
927
372k
  }
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::apply_to<OT::Layout::GPOS_impl::MarkLigPosFormat1_2<OT::Layout::SmallTypes> >(void const*, OT::hb_ot_apply_context_t*, void*)
bool OT::hb_accelerate_subtables_context_t::apply_to<OT::Layout::GPOS_impl::MarkMarkPosFormat1_2<OT::Layout::SmallTypes> >(void const*, OT::hb_ot_apply_context_t*, void*)
Line
Count
Source
924
201k
  {
925
201k
    const T *typed_obj = (const T *) obj;
926
201k
    return apply_ (typed_obj, c, external_cache, hb_prioritize);
927
201k
  }
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::apply_to<OT::ContextFormat1_4<OT::Layout::SmallTypes> >(void const*, OT::hb_ot_apply_context_t*, void*)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::apply_to<OT::ContextFormat2_5<OT::Layout::SmallTypes> >(void const*, OT::hb_ot_apply_context_t*, void*)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::apply_to<OT::ContextFormat3>(void const*, OT::hb_ot_apply_context_t*, void*)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::apply_to<OT::ChainContextFormat1_4<OT::Layout::SmallTypes> >(void const*, OT::hb_ot_apply_context_t*, void*)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::apply_to<OT::ChainContextFormat2_5<OT::Layout::SmallTypes> >(void const*, OT::hb_ot_apply_context_t*, void*)
bool OT::hb_accelerate_subtables_context_t::apply_to<OT::ChainContextFormat3>(void const*, OT::hb_ot_apply_context_t*, void*)
Line
Count
Source
924
1.32M
  {
925
1.32M
    const T *typed_obj = (const T *) obj;
926
1.32M
    return apply_ (typed_obj, c, external_cache, hb_prioritize);
927
1.32M
  }
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::apply_to<OT::Layout::GSUB_impl::SingleSubstFormat1_3<OT::Layout::SmallTypes> >(void const*, OT::hb_ot_apply_context_t*, void*)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::apply_to<OT::Layout::GSUB_impl::SingleSubstFormat2_4<OT::Layout::SmallTypes> >(void const*, OT::hb_ot_apply_context_t*, void*)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::apply_to<OT::Layout::GSUB_impl::MultipleSubstFormat1_2<OT::Layout::SmallTypes> >(void const*, OT::hb_ot_apply_context_t*, void*)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::apply_to<OT::Layout::GSUB_impl::AlternateSubstFormat1_2<OT::Layout::SmallTypes> >(void const*, OT::hb_ot_apply_context_t*, void*)
bool OT::hb_accelerate_subtables_context_t::apply_to<OT::Layout::GSUB_impl::LigatureSubstFormat1_2<OT::Layout::SmallTypes> >(void const*, OT::hb_ot_apply_context_t*, void*)
Line
Count
Source
924
272k
  {
925
272k
    const T *typed_obj = (const T *) obj;
926
272k
    return apply_ (typed_obj, c, external_cache, hb_prioritize);
927
272k
  }
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::apply_to<OT::Layout::GSUB_impl::ReverseChainSingleSubstFormat1>(void const*, OT::hb_ot_apply_context_t*, void*)
928
929
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
930
  template <typename T>
931
  static inline auto apply_cached_ (const T *obj, hb_ot_apply_context_t *c, void *external_cache, hb_priority<2>) HB_RETURN (bool, obj->apply_cached (c, external_cache) )
932
  template <typename T>
933
  static inline auto apply_cached_ (const T *obj, hb_ot_apply_context_t *c, void *external_cache, hb_priority<1>) HB_RETURN (bool, obj->apply (c, external_cache) )
934
  template <typename T>
935
  static inline auto apply_cached_ (const T *obj, hb_ot_apply_context_t *c, void *external_cache, hb_priority<0>) HB_RETURN (bool, obj->apply (c) )
936
  template <typename T>
937
  static inline bool apply_cached_to (const void *obj, hb_ot_apply_context_t *c, void *external_cache)
938
0
  {
939
0
    const T *typed_obj = (const T *) obj;
940
0
    return apply_cached_ (typed_obj, c, external_cache, hb_prioritize);
941
0
  }
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::apply_cached_to<OT::Layout::GPOS_impl::SinglePosFormat1>(void const*, OT::hb_ot_apply_context_t*, void*)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::apply_cached_to<OT::Layout::GPOS_impl::SinglePosFormat2>(void const*, OT::hb_ot_apply_context_t*, void*)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::apply_cached_to<OT::Layout::GPOS_impl::PairPosFormat1_3<OT::Layout::SmallTypes> >(void const*, OT::hb_ot_apply_context_t*, void*)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::apply_cached_to<OT::Layout::GPOS_impl::PairPosFormat2_4<OT::Layout::SmallTypes> >(void const*, OT::hb_ot_apply_context_t*, void*)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::apply_cached_to<OT::Layout::GPOS_impl::CursivePosFormat1>(void const*, OT::hb_ot_apply_context_t*, void*)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::apply_cached_to<OT::Layout::GPOS_impl::MarkBasePosFormat1_2<OT::Layout::SmallTypes> >(void const*, OT::hb_ot_apply_context_t*, void*)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::apply_cached_to<OT::Layout::GPOS_impl::MarkLigPosFormat1_2<OT::Layout::SmallTypes> >(void const*, OT::hb_ot_apply_context_t*, void*)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::apply_cached_to<OT::Layout::GPOS_impl::MarkMarkPosFormat1_2<OT::Layout::SmallTypes> >(void const*, OT::hb_ot_apply_context_t*, void*)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::apply_cached_to<OT::ContextFormat1_4<OT::Layout::SmallTypes> >(void const*, OT::hb_ot_apply_context_t*, void*)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::apply_cached_to<OT::ContextFormat2_5<OT::Layout::SmallTypes> >(void const*, OT::hb_ot_apply_context_t*, void*)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::apply_cached_to<OT::ContextFormat3>(void const*, OT::hb_ot_apply_context_t*, void*)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::apply_cached_to<OT::ChainContextFormat1_4<OT::Layout::SmallTypes> >(void const*, OT::hb_ot_apply_context_t*, void*)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::apply_cached_to<OT::ChainContextFormat2_5<OT::Layout::SmallTypes> >(void const*, OT::hb_ot_apply_context_t*, void*)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::apply_cached_to<OT::ChainContextFormat3>(void const*, OT::hb_ot_apply_context_t*, void*)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::apply_cached_to<OT::Layout::GSUB_impl::SingleSubstFormat1_3<OT::Layout::SmallTypes> >(void const*, OT::hb_ot_apply_context_t*, void*)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::apply_cached_to<OT::Layout::GSUB_impl::SingleSubstFormat2_4<OT::Layout::SmallTypes> >(void const*, OT::hb_ot_apply_context_t*, void*)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::apply_cached_to<OT::Layout::GSUB_impl::MultipleSubstFormat1_2<OT::Layout::SmallTypes> >(void const*, OT::hb_ot_apply_context_t*, void*)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::apply_cached_to<OT::Layout::GSUB_impl::AlternateSubstFormat1_2<OT::Layout::SmallTypes> >(void const*, OT::hb_ot_apply_context_t*, void*)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::apply_cached_to<OT::Layout::GSUB_impl::LigatureSubstFormat1_2<OT::Layout::SmallTypes> >(void const*, OT::hb_ot_apply_context_t*, void*)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::apply_cached_to<OT::Layout::GSUB_impl::ReverseChainSingleSubstFormat1>(void const*, OT::hb_ot_apply_context_t*, void*)
942
943
  template <typename T>
944
  static inline auto cache_func_ (hb_ot_apply_context_t *c,
945
          hb_ot_subtable_cache_op_t op,
946
          hb_priority<1>) HB_RETURN (bool, T::cache_func (c, op) )
947
  template <typename T=void>
948
  static inline bool cache_func_ (hb_ot_apply_context_t *c,
949
          hb_ot_subtable_cache_op_t op HB_UNUSED,
950
0
          hb_priority<0>) { return false; }
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::cache_func_<OT::Layout::GPOS_impl::SinglePosFormat1>(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t, hb_priority<0u>)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::cache_func_<OT::Layout::GPOS_impl::SinglePosFormat2>(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t, hb_priority<0u>)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::cache_func_<OT::Layout::GPOS_impl::PairPosFormat1_3<OT::Layout::SmallTypes> >(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t, hb_priority<0u>)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::cache_func_<OT::Layout::GPOS_impl::PairPosFormat2_4<OT::Layout::SmallTypes> >(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t, hb_priority<0u>)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::cache_func_<OT::Layout::GPOS_impl::CursivePosFormat1>(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t, hb_priority<0u>)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::cache_func_<OT::Layout::GPOS_impl::MarkBasePosFormat1_2<OT::Layout::SmallTypes> >(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t, hb_priority<0u>)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::cache_func_<OT::Layout::GPOS_impl::MarkLigPosFormat1_2<OT::Layout::SmallTypes> >(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t, hb_priority<0u>)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::cache_func_<OT::Layout::GPOS_impl::MarkMarkPosFormat1_2<OT::Layout::SmallTypes> >(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t, hb_priority<0u>)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::cache_func_<OT::ContextFormat1_4<OT::Layout::SmallTypes> >(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t, hb_priority<0u>)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::cache_func_<OT::ContextFormat3>(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t, hb_priority<0u>)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::cache_func_<OT::ChainContextFormat1_4<OT::Layout::SmallTypes> >(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t, hb_priority<0u>)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::cache_func_<OT::ChainContextFormat3>(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t, hb_priority<0u>)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::cache_func_<OT::Layout::GSUB_impl::SingleSubstFormat1_3<OT::Layout::SmallTypes> >(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t, hb_priority<0u>)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::cache_func_<OT::Layout::GSUB_impl::SingleSubstFormat2_4<OT::Layout::SmallTypes> >(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t, hb_priority<0u>)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::cache_func_<OT::Layout::GSUB_impl::MultipleSubstFormat1_2<OT::Layout::SmallTypes> >(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t, hb_priority<0u>)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::cache_func_<OT::Layout::GSUB_impl::AlternateSubstFormat1_2<OT::Layout::SmallTypes> >(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t, hb_priority<0u>)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::cache_func_<OT::Layout::GSUB_impl::LigatureSubstFormat1_2<OT::Layout::SmallTypes> >(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t, hb_priority<0u>)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::cache_func_<OT::Layout::GSUB_impl::ReverseChainSingleSubstFormat1>(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t, hb_priority<0u>)
951
  template <typename Type>
952
  static inline bool cache_func_to (hb_ot_apply_context_t *c,
953
            hb_ot_subtable_cache_op_t op)
954
0
  {
955
0
    return cache_func_<Type> (c, op, hb_prioritize);
956
0
  }
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::cache_func_to<OT::Layout::GPOS_impl::SinglePosFormat1>(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::cache_func_to<OT::Layout::GPOS_impl::SinglePosFormat2>(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::cache_func_to<OT::Layout::GPOS_impl::PairPosFormat1_3<OT::Layout::SmallTypes> >(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::cache_func_to<OT::Layout::GPOS_impl::PairPosFormat2_4<OT::Layout::SmallTypes> >(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::cache_func_to<OT::Layout::GPOS_impl::CursivePosFormat1>(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::cache_func_to<OT::Layout::GPOS_impl::MarkBasePosFormat1_2<OT::Layout::SmallTypes> >(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::cache_func_to<OT::Layout::GPOS_impl::MarkLigPosFormat1_2<OT::Layout::SmallTypes> >(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::cache_func_to<OT::Layout::GPOS_impl::MarkMarkPosFormat1_2<OT::Layout::SmallTypes> >(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::cache_func_to<OT::ContextFormat1_4<OT::Layout::SmallTypes> >(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::cache_func_to<OT::ContextFormat2_5<OT::Layout::SmallTypes> >(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::cache_func_to<OT::ContextFormat3>(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::cache_func_to<OT::ChainContextFormat1_4<OT::Layout::SmallTypes> >(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::cache_func_to<OT::ChainContextFormat2_5<OT::Layout::SmallTypes> >(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::cache_func_to<OT::ChainContextFormat3>(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::cache_func_to<OT::Layout::GSUB_impl::SingleSubstFormat1_3<OT::Layout::SmallTypes> >(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::cache_func_to<OT::Layout::GSUB_impl::SingleSubstFormat2_4<OT::Layout::SmallTypes> >(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::cache_func_to<OT::Layout::GSUB_impl::MultipleSubstFormat1_2<OT::Layout::SmallTypes> >(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::cache_func_to<OT::Layout::GSUB_impl::AlternateSubstFormat1_2<OT::Layout::SmallTypes> >(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::cache_func_to<OT::Layout::GSUB_impl::LigatureSubstFormat1_2<OT::Layout::SmallTypes> >(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t)
Unexecuted instantiation: bool OT::hb_accelerate_subtables_context_t::cache_func_to<OT::Layout::GSUB_impl::ReverseChainSingleSubstFormat1>(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t)
957
#endif
958
959
  typedef bool (*hb_apply_func_t) (const void *obj, hb_ot_apply_context_t *c, void *external_cache);
960
  typedef bool (*hb_cache_func_t) (hb_ot_apply_context_t *c, hb_ot_subtable_cache_op_t op);
961
962
  struct hb_applicable_t
963
  {
964
    friend struct hb_accelerate_subtables_context_t;
965
    friend struct hb_ot_layout_lookup_accelerator_t;
966
967
    template <typename T>
968
    void init (const T &obj_,
969
         hb_apply_func_t apply_func_
970
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
971
         , hb_apply_func_t apply_cached_func_
972
         , hb_cache_func_t cache_func_
973
         , void *external_cache_
974
#endif
975
    )
976
1.68k
    {
977
1.68k
      obj = &obj_;
978
1.68k
      apply_func = apply_func_;
979
1.68k
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
980
1.68k
      apply_cached_func = apply_cached_func_;
981
1.68k
      cache_func = cache_func_;
982
1.68k
      external_cache = external_cache_;
983
1.68k
#endif
984
1.68k
      digest.init ();
985
1.68k
      obj_.get_coverage ().collect_coverage (&digest);
986
1.68k
    }
void OT::hb_accelerate_subtables_context_t::hb_applicable_t::init<OT::Layout::GPOS_impl::SinglePosFormat1>(OT::Layout::GPOS_impl::SinglePosFormat1 const&, bool (*)(void const*, OT::hb_ot_apply_context_t*, void*), bool (*)(void const*, OT::hb_ot_apply_context_t*, void*), bool (*)(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t), void*)
Line
Count
Source
976
4
    {
977
4
      obj = &obj_;
978
4
      apply_func = apply_func_;
979
4
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
980
4
      apply_cached_func = apply_cached_func_;
981
4
      cache_func = cache_func_;
982
4
      external_cache = external_cache_;
983
4
#endif
984
4
      digest.init ();
985
4
      obj_.get_coverage ().collect_coverage (&digest);
986
4
    }
Unexecuted instantiation: void OT::hb_accelerate_subtables_context_t::hb_applicable_t::init<OT::Layout::GPOS_impl::SinglePosFormat2>(OT::Layout::GPOS_impl::SinglePosFormat2 const&, bool (*)(void const*, OT::hb_ot_apply_context_t*, void*), bool (*)(void const*, OT::hb_ot_apply_context_t*, void*), bool (*)(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t), void*)
void OT::hb_accelerate_subtables_context_t::hb_applicable_t::init<OT::Layout::GPOS_impl::PairPosFormat1_3<OT::Layout::SmallTypes> >(OT::Layout::GPOS_impl::PairPosFormat1_3<OT::Layout::SmallTypes> const&, bool (*)(void const*, OT::hb_ot_apply_context_t*, void*), bool (*)(void const*, OT::hb_ot_apply_context_t*, void*), bool (*)(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t), void*)
Line
Count
Source
976
53
    {
977
53
      obj = &obj_;
978
53
      apply_func = apply_func_;
979
53
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
980
53
      apply_cached_func = apply_cached_func_;
981
53
      cache_func = cache_func_;
982
53
      external_cache = external_cache_;
983
53
#endif
984
53
      digest.init ();
985
53
      obj_.get_coverage ().collect_coverage (&digest);
986
53
    }
Unexecuted instantiation: void OT::hb_accelerate_subtables_context_t::hb_applicable_t::init<OT::Layout::GPOS_impl::PairPosFormat2_4<OT::Layout::SmallTypes> >(OT::Layout::GPOS_impl::PairPosFormat2_4<OT::Layout::SmallTypes> const&, bool (*)(void const*, OT::hb_ot_apply_context_t*, void*), bool (*)(void const*, OT::hb_ot_apply_context_t*, void*), bool (*)(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t), void*)
Unexecuted instantiation: void OT::hb_accelerate_subtables_context_t::hb_applicable_t::init<OT::Layout::GPOS_impl::CursivePosFormat1>(OT::Layout::GPOS_impl::CursivePosFormat1 const&, bool (*)(void const*, OT::hb_ot_apply_context_t*, void*), bool (*)(void const*, OT::hb_ot_apply_context_t*, void*), bool (*)(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t), void*)
void OT::hb_accelerate_subtables_context_t::hb_applicable_t::init<OT::Layout::GPOS_impl::MarkBasePosFormat1_2<OT::Layout::SmallTypes> >(OT::Layout::GPOS_impl::MarkBasePosFormat1_2<OT::Layout::SmallTypes> const&, bool (*)(void const*, OT::hb_ot_apply_context_t*, void*), bool (*)(void const*, OT::hb_ot_apply_context_t*, void*), bool (*)(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t), void*)
Line
Count
Source
976
562
    {
977
562
      obj = &obj_;
978
562
      apply_func = apply_func_;
979
562
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
980
562
      apply_cached_func = apply_cached_func_;
981
562
      cache_func = cache_func_;
982
562
      external_cache = external_cache_;
983
562
#endif
984
562
      digest.init ();
985
562
      obj_.get_coverage ().collect_coverage (&digest);
986
562
    }
Unexecuted instantiation: void OT::hb_accelerate_subtables_context_t::hb_applicable_t::init<OT::Layout::GPOS_impl::MarkLigPosFormat1_2<OT::Layout::SmallTypes> >(OT::Layout::GPOS_impl::MarkLigPosFormat1_2<OT::Layout::SmallTypes> const&, bool (*)(void const*, OT::hb_ot_apply_context_t*, void*), bool (*)(void const*, OT::hb_ot_apply_context_t*, void*), bool (*)(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t), void*)
void OT::hb_accelerate_subtables_context_t::hb_applicable_t::init<OT::Layout::GPOS_impl::MarkMarkPosFormat1_2<OT::Layout::SmallTypes> >(OT::Layout::GPOS_impl::MarkMarkPosFormat1_2<OT::Layout::SmallTypes> const&, bool (*)(void const*, OT::hb_ot_apply_context_t*, void*), bool (*)(void const*, OT::hb_ot_apply_context_t*, void*), bool (*)(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t), void*)
Line
Count
Source
976
94
    {
977
94
      obj = &obj_;
978
94
      apply_func = apply_func_;
979
94
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
980
94
      apply_cached_func = apply_cached_func_;
981
94
      cache_func = cache_func_;
982
94
      external_cache = external_cache_;
983
94
#endif
984
94
      digest.init ();
985
94
      obj_.get_coverage ().collect_coverage (&digest);
986
94
    }
Unexecuted instantiation: void OT::hb_accelerate_subtables_context_t::hb_applicable_t::init<OT::ContextFormat1_4<OT::Layout::SmallTypes> >(OT::ContextFormat1_4<OT::Layout::SmallTypes> const&, bool (*)(void const*, OT::hb_ot_apply_context_t*, void*), bool (*)(void const*, OT::hb_ot_apply_context_t*, void*), bool (*)(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t), void*)
Unexecuted instantiation: void OT::hb_accelerate_subtables_context_t::hb_applicable_t::init<OT::ContextFormat2_5<OT::Layout::SmallTypes> >(OT::ContextFormat2_5<OT::Layout::SmallTypes> const&, bool (*)(void const*, OT::hb_ot_apply_context_t*, void*), bool (*)(void const*, OT::hb_ot_apply_context_t*, void*), bool (*)(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t), void*)
Unexecuted instantiation: void OT::hb_accelerate_subtables_context_t::hb_applicable_t::init<OT::ContextFormat3>(OT::ContextFormat3 const&, bool (*)(void const*, OT::hb_ot_apply_context_t*, void*), bool (*)(void const*, OT::hb_ot_apply_context_t*, void*), bool (*)(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t), void*)
Unexecuted instantiation: void OT::hb_accelerate_subtables_context_t::hb_applicable_t::init<OT::ChainContextFormat1_4<OT::Layout::SmallTypes> >(OT::ChainContextFormat1_4<OT::Layout::SmallTypes> const&, bool (*)(void const*, OT::hb_ot_apply_context_t*, void*), bool (*)(void const*, OT::hb_ot_apply_context_t*, void*), bool (*)(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t), void*)
Unexecuted instantiation: void OT::hb_accelerate_subtables_context_t::hb_applicable_t::init<OT::ChainContextFormat2_5<OT::Layout::SmallTypes> >(OT::ChainContextFormat2_5<OT::Layout::SmallTypes> const&, bool (*)(void const*, OT::hb_ot_apply_context_t*, void*), bool (*)(void const*, OT::hb_ot_apply_context_t*, void*), bool (*)(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t), void*)
void OT::hb_accelerate_subtables_context_t::hb_applicable_t::init<OT::ChainContextFormat3>(OT::ChainContextFormat3 const&, bool (*)(void const*, OT::hb_ot_apply_context_t*, void*), bool (*)(void const*, OT::hb_ot_apply_context_t*, void*), bool (*)(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t), void*)
Line
Count
Source
976
902
    {
977
902
      obj = &obj_;
978
902
      apply_func = apply_func_;
979
902
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
980
902
      apply_cached_func = apply_cached_func_;
981
902
      cache_func = cache_func_;
982
902
      external_cache = external_cache_;
983
902
#endif
984
902
      digest.init ();
985
902
      obj_.get_coverage ().collect_coverage (&digest);
986
902
    }
Unexecuted instantiation: void OT::hb_accelerate_subtables_context_t::hb_applicable_t::init<OT::Layout::GSUB_impl::SingleSubstFormat1_3<OT::Layout::SmallTypes> >(OT::Layout::GSUB_impl::SingleSubstFormat1_3<OT::Layout::SmallTypes> const&, bool (*)(void const*, OT::hb_ot_apply_context_t*, void*), bool (*)(void const*, OT::hb_ot_apply_context_t*, void*), bool (*)(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t), void*)
Unexecuted instantiation: void OT::hb_accelerate_subtables_context_t::hb_applicable_t::init<OT::Layout::GSUB_impl::SingleSubstFormat2_4<OT::Layout::SmallTypes> >(OT::Layout::GSUB_impl::SingleSubstFormat2_4<OT::Layout::SmallTypes> const&, bool (*)(void const*, OT::hb_ot_apply_context_t*, void*), bool (*)(void const*, OT::hb_ot_apply_context_t*, void*), bool (*)(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t), void*)
Unexecuted instantiation: void OT::hb_accelerate_subtables_context_t::hb_applicable_t::init<OT::Layout::GSUB_impl::MultipleSubstFormat1_2<OT::Layout::SmallTypes> >(OT::Layout::GSUB_impl::MultipleSubstFormat1_2<OT::Layout::SmallTypes> const&, bool (*)(void const*, OT::hb_ot_apply_context_t*, void*), bool (*)(void const*, OT::hb_ot_apply_context_t*, void*), bool (*)(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t), void*)
Unexecuted instantiation: void OT::hb_accelerate_subtables_context_t::hb_applicable_t::init<OT::Layout::GSUB_impl::AlternateSubstFormat1_2<OT::Layout::SmallTypes> >(OT::Layout::GSUB_impl::AlternateSubstFormat1_2<OT::Layout::SmallTypes> const&, bool (*)(void const*, OT::hb_ot_apply_context_t*, void*), bool (*)(void const*, OT::hb_ot_apply_context_t*, void*), bool (*)(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t), void*)
void OT::hb_accelerate_subtables_context_t::hb_applicable_t::init<OT::Layout::GSUB_impl::LigatureSubstFormat1_2<OT::Layout::SmallTypes> >(OT::Layout::GSUB_impl::LigatureSubstFormat1_2<OT::Layout::SmallTypes> const&, bool (*)(void const*, OT::hb_ot_apply_context_t*, void*), bool (*)(void const*, OT::hb_ot_apply_context_t*, void*), bool (*)(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t), void*)
Line
Count
Source
976
74
    {
977
74
      obj = &obj_;
978
74
      apply_func = apply_func_;
979
74
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
980
74
      apply_cached_func = apply_cached_func_;
981
74
      cache_func = cache_func_;
982
74
      external_cache = external_cache_;
983
74
#endif
984
74
      digest.init ();
985
74
      obj_.get_coverage ().collect_coverage (&digest);
986
74
    }
Unexecuted instantiation: void OT::hb_accelerate_subtables_context_t::hb_applicable_t::init<OT::Layout::GSUB_impl::ReverseChainSingleSubstFormat1>(OT::Layout::GSUB_impl::ReverseChainSingleSubstFormat1 const&, bool (*)(void const*, OT::hb_ot_apply_context_t*, void*), bool (*)(void const*, OT::hb_ot_apply_context_t*, void*), bool (*)(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t), void*)
987
988
#ifdef HB_NO_OT_LAYOUT_LOOKUP_CACHE
989
    bool apply (hb_ot_apply_context_t *c) const
990
    {
991
      return digest.may_have (c->buffer->cur().codepoint) && apply_func (obj, c, nullptr);
992
    }
993
#else
994
    bool apply (hb_ot_apply_context_t *c) const
995
118M
    {
996
118M
      return digest.may_have (c->buffer->cur().codepoint) && apply_func (obj, c, external_cache);
997
118M
    }
998
    bool apply_cached (hb_ot_apply_context_t *c) const
999
0
    {
1000
0
      return digest.may_have (c->buffer->cur().codepoint) &&  apply_cached_func (obj, c, external_cache);
1001
0
    }
1002
1003
    bool cache_enter (hb_ot_apply_context_t *c) const
1004
0
    {
1005
0
      return cache_func (c, hb_ot_subtable_cache_op_t::ENTER);
1006
0
    }
1007
    void cache_leave (hb_ot_apply_context_t *c) const
1008
0
    {
1009
0
      cache_func (c, hb_ot_subtable_cache_op_t::LEAVE);
1010
0
    }
1011
#endif
1012
1013
    private:
1014
    const void *obj;
1015
    hb_apply_func_t apply_func;
1016
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
1017
    hb_apply_func_t apply_cached_func;
1018
    hb_cache_func_t cache_func;
1019
    void *external_cache;
1020
#endif
1021
    hb_set_digest_t digest;
1022
  };
1023
1024
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
1025
  template <typename T>
1026
  auto cache_cost (const T &obj, hb_priority<1>) HB_AUTO_RETURN ( obj.cache_cost () )
1027
  template <typename T>
1028
  auto cache_cost (const T &obj, hb_priority<0>) HB_AUTO_RETURN ( 0u )
1029
1030
  template <typename T>
1031
  auto external_cache_create (const T &obj, hb_priority<1>) HB_AUTO_RETURN ( obj.external_cache_create () )
1032
  template <typename T>
1033
  auto external_cache_create (const T &obj, hb_priority<0>) HB_AUTO_RETURN ( nullptr )
1034
#endif
1035
1036
  /* Dispatch interface. */
1037
  template <typename T>
1038
  return_t dispatch (const T &obj)
1039
1.68k
  {
1040
1.68k
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
1041
1.68k
    void *external_cache = nullptr;
1042
1.68k
    if (i < 8)
1043
1.57k
      external_cache = external_cache_create (obj, hb_prioritize);
1044
1.68k
#endif
1045
1046
1.68k
    hb_applicable_t *entry = &array[i++];
1047
1048
1.68k
    entry->init (obj,
1049
1.68k
     apply_to<T>
1050
1.68k
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
1051
1.68k
     , apply_cached_to<T>
1052
1.68k
     , cache_func_to<T>
1053
1.68k
     , external_cache
1054
1.68k
#endif
1055
1.68k
     );
1056
1057
1.68k
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
1058
    /* Cache handling
1059
     *
1060
     * We allow one subtable from each lookup to use a cache. The assumption
1061
     * being that multiple subtables of the same lookup cannot use a cache
1062
     * because the resources they would use will collide.  As such, we ask
1063
     * each subtable to tell us how much it costs (which a cache would avoid),
1064
     * and we allocate the cache opportunity to the costliest subtable.
1065
     */
1066
1.68k
    unsigned cost = cache_cost (obj, hb_prioritize);
1067
1.68k
    if (cost > subtable_cache_user_cost)
1068
0
    {
1069
0
      subtable_cache_user_idx = i - 1;
1070
0
      subtable_cache_user_cost = cost;
1071
0
    }
1072
1.68k
#endif
1073
1074
1.68k
    return hb_empty_t ();
1075
1.68k
  }
hb_empty_t OT::hb_accelerate_subtables_context_t::dispatch<OT::Layout::GPOS_impl::SinglePosFormat1>(OT::Layout::GPOS_impl::SinglePosFormat1 const&)
Line
Count
Source
1039
4
  {
1040
4
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
1041
4
    void *external_cache = nullptr;
1042
4
    if (i < 8)
1043
4
      external_cache = external_cache_create (obj, hb_prioritize);
1044
4
#endif
1045
1046
4
    hb_applicable_t *entry = &array[i++];
1047
1048
4
    entry->init (obj,
1049
4
     apply_to<T>
1050
4
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
1051
4
     , apply_cached_to<T>
1052
4
     , cache_func_to<T>
1053
4
     , external_cache
1054
4
#endif
1055
4
     );
1056
1057
4
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
1058
    /* Cache handling
1059
     *
1060
     * We allow one subtable from each lookup to use a cache. The assumption
1061
     * being that multiple subtables of the same lookup cannot use a cache
1062
     * because the resources they would use will collide.  As such, we ask
1063
     * each subtable to tell us how much it costs (which a cache would avoid),
1064
     * and we allocate the cache opportunity to the costliest subtable.
1065
     */
1066
4
    unsigned cost = cache_cost (obj, hb_prioritize);
1067
4
    if (cost > subtable_cache_user_cost)
1068
0
    {
1069
0
      subtable_cache_user_idx = i - 1;
1070
0
      subtable_cache_user_cost = cost;
1071
0
    }
1072
4
#endif
1073
1074
4
    return hb_empty_t ();
1075
4
  }
Unexecuted instantiation: hb_empty_t OT::hb_accelerate_subtables_context_t::dispatch<OT::Layout::GPOS_impl::SinglePosFormat2>(OT::Layout::GPOS_impl::SinglePosFormat2 const&)
hb_empty_t OT::hb_accelerate_subtables_context_t::dispatch<OT::Layout::GPOS_impl::PairPosFormat1_3<OT::Layout::SmallTypes> >(OT::Layout::GPOS_impl::PairPosFormat1_3<OT::Layout::SmallTypes> const&)
Line
Count
Source
1039
53
  {
1040
53
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
1041
53
    void *external_cache = nullptr;
1042
53
    if (i < 8)
1043
53
      external_cache = external_cache_create (obj, hb_prioritize);
1044
53
#endif
1045
1046
53
    hb_applicable_t *entry = &array[i++];
1047
1048
53
    entry->init (obj,
1049
53
     apply_to<T>
1050
53
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
1051
53
     , apply_cached_to<T>
1052
53
     , cache_func_to<T>
1053
53
     , external_cache
1054
53
#endif
1055
53
     );
1056
1057
53
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
1058
    /* Cache handling
1059
     *
1060
     * We allow one subtable from each lookup to use a cache. The assumption
1061
     * being that multiple subtables of the same lookup cannot use a cache
1062
     * because the resources they would use will collide.  As such, we ask
1063
     * each subtable to tell us how much it costs (which a cache would avoid),
1064
     * and we allocate the cache opportunity to the costliest subtable.
1065
     */
1066
53
    unsigned cost = cache_cost (obj, hb_prioritize);
1067
53
    if (cost > subtable_cache_user_cost)
1068
0
    {
1069
0
      subtable_cache_user_idx = i - 1;
1070
0
      subtable_cache_user_cost = cost;
1071
0
    }
1072
53
#endif
1073
1074
53
    return hb_empty_t ();
1075
53
  }
Unexecuted instantiation: hb_empty_t OT::hb_accelerate_subtables_context_t::dispatch<OT::Layout::GPOS_impl::PairPosFormat2_4<OT::Layout::SmallTypes> >(OT::Layout::GPOS_impl::PairPosFormat2_4<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: hb_empty_t OT::hb_accelerate_subtables_context_t::dispatch<OT::Layout::GPOS_impl::CursivePosFormat1>(OT::Layout::GPOS_impl::CursivePosFormat1 const&)
hb_empty_t OT::hb_accelerate_subtables_context_t::dispatch<OT::Layout::GPOS_impl::MarkBasePosFormat1_2<OT::Layout::SmallTypes> >(OT::Layout::GPOS_impl::MarkBasePosFormat1_2<OT::Layout::SmallTypes> const&)
Line
Count
Source
1039
562
  {
1040
562
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
1041
562
    void *external_cache = nullptr;
1042
562
    if (i < 8)
1043
562
      external_cache = external_cache_create (obj, hb_prioritize);
1044
562
#endif
1045
1046
562
    hb_applicable_t *entry = &array[i++];
1047
1048
562
    entry->init (obj,
1049
562
     apply_to<T>
1050
562
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
1051
562
     , apply_cached_to<T>
1052
562
     , cache_func_to<T>
1053
562
     , external_cache
1054
562
#endif
1055
562
     );
1056
1057
562
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
1058
    /* Cache handling
1059
     *
1060
     * We allow one subtable from each lookup to use a cache. The assumption
1061
     * being that multiple subtables of the same lookup cannot use a cache
1062
     * because the resources they would use will collide.  As such, we ask
1063
     * each subtable to tell us how much it costs (which a cache would avoid),
1064
     * and we allocate the cache opportunity to the costliest subtable.
1065
     */
1066
562
    unsigned cost = cache_cost (obj, hb_prioritize);
1067
562
    if (cost > subtable_cache_user_cost)
1068
0
    {
1069
0
      subtable_cache_user_idx = i - 1;
1070
0
      subtable_cache_user_cost = cost;
1071
0
    }
1072
562
#endif
1073
1074
562
    return hb_empty_t ();
1075
562
  }
Unexecuted instantiation: hb_empty_t OT::hb_accelerate_subtables_context_t::dispatch<OT::Layout::GPOS_impl::MarkLigPosFormat1_2<OT::Layout::SmallTypes> >(OT::Layout::GPOS_impl::MarkLigPosFormat1_2<OT::Layout::SmallTypes> const&)
hb_empty_t OT::hb_accelerate_subtables_context_t::dispatch<OT::Layout::GPOS_impl::MarkMarkPosFormat1_2<OT::Layout::SmallTypes> >(OT::Layout::GPOS_impl::MarkMarkPosFormat1_2<OT::Layout::SmallTypes> const&)
Line
Count
Source
1039
94
  {
1040
94
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
1041
94
    void *external_cache = nullptr;
1042
94
    if (i < 8)
1043
94
      external_cache = external_cache_create (obj, hb_prioritize);
1044
94
#endif
1045
1046
94
    hb_applicable_t *entry = &array[i++];
1047
1048
94
    entry->init (obj,
1049
94
     apply_to<T>
1050
94
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
1051
94
     , apply_cached_to<T>
1052
94
     , cache_func_to<T>
1053
94
     , external_cache
1054
94
#endif
1055
94
     );
1056
1057
94
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
1058
    /* Cache handling
1059
     *
1060
     * We allow one subtable from each lookup to use a cache. The assumption
1061
     * being that multiple subtables of the same lookup cannot use a cache
1062
     * because the resources they would use will collide.  As such, we ask
1063
     * each subtable to tell us how much it costs (which a cache would avoid),
1064
     * and we allocate the cache opportunity to the costliest subtable.
1065
     */
1066
94
    unsigned cost = cache_cost (obj, hb_prioritize);
1067
94
    if (cost > subtable_cache_user_cost)
1068
0
    {
1069
0
      subtable_cache_user_idx = i - 1;
1070
0
      subtable_cache_user_cost = cost;
1071
0
    }
1072
94
#endif
1073
1074
94
    return hb_empty_t ();
1075
94
  }
Unexecuted instantiation: hb_empty_t OT::hb_accelerate_subtables_context_t::dispatch<OT::ContextFormat1_4<OT::Layout::SmallTypes> >(OT::ContextFormat1_4<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: hb_empty_t OT::hb_accelerate_subtables_context_t::dispatch<OT::ContextFormat2_5<OT::Layout::SmallTypes> >(OT::ContextFormat2_5<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: hb_empty_t OT::hb_accelerate_subtables_context_t::dispatch<OT::ContextFormat3>(OT::ContextFormat3 const&)
Unexecuted instantiation: hb_empty_t OT::hb_accelerate_subtables_context_t::dispatch<OT::ChainContextFormat1_4<OT::Layout::SmallTypes> >(OT::ChainContextFormat1_4<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: hb_empty_t OT::hb_accelerate_subtables_context_t::dispatch<OT::ChainContextFormat2_5<OT::Layout::SmallTypes> >(OT::ChainContextFormat2_5<OT::Layout::SmallTypes> const&)
hb_empty_t OT::hb_accelerate_subtables_context_t::dispatch<OT::ChainContextFormat3>(OT::ChainContextFormat3 const&)
Line
Count
Source
1039
902
  {
1040
902
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
1041
902
    void *external_cache = nullptr;
1042
902
    if (i < 8)
1043
792
      external_cache = external_cache_create (obj, hb_prioritize);
1044
902
#endif
1045
1046
902
    hb_applicable_t *entry = &array[i++];
1047
1048
902
    entry->init (obj,
1049
902
     apply_to<T>
1050
902
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
1051
902
     , apply_cached_to<T>
1052
902
     , cache_func_to<T>
1053
902
     , external_cache
1054
902
#endif
1055
902
     );
1056
1057
902
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
1058
    /* Cache handling
1059
     *
1060
     * We allow one subtable from each lookup to use a cache. The assumption
1061
     * being that multiple subtables of the same lookup cannot use a cache
1062
     * because the resources they would use will collide.  As such, we ask
1063
     * each subtable to tell us how much it costs (which a cache would avoid),
1064
     * and we allocate the cache opportunity to the costliest subtable.
1065
     */
1066
902
    unsigned cost = cache_cost (obj, hb_prioritize);
1067
902
    if (cost > subtable_cache_user_cost)
1068
0
    {
1069
0
      subtable_cache_user_idx = i - 1;
1070
0
      subtable_cache_user_cost = cost;
1071
0
    }
1072
902
#endif
1073
1074
902
    return hb_empty_t ();
1075
902
  }
Unexecuted instantiation: hb_empty_t OT::hb_accelerate_subtables_context_t::dispatch<OT::Layout::GSUB_impl::SingleSubstFormat1_3<OT::Layout::SmallTypes> >(OT::Layout::GSUB_impl::SingleSubstFormat1_3<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: hb_empty_t OT::hb_accelerate_subtables_context_t::dispatch<OT::Layout::GSUB_impl::SingleSubstFormat2_4<OT::Layout::SmallTypes> >(OT::Layout::GSUB_impl::SingleSubstFormat2_4<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: hb_empty_t OT::hb_accelerate_subtables_context_t::dispatch<OT::Layout::GSUB_impl::MultipleSubstFormat1_2<OT::Layout::SmallTypes> >(OT::Layout::GSUB_impl::MultipleSubstFormat1_2<OT::Layout::SmallTypes> const&)
Unexecuted instantiation: hb_empty_t OT::hb_accelerate_subtables_context_t::dispatch<OT::Layout::GSUB_impl::AlternateSubstFormat1_2<OT::Layout::SmallTypes> >(OT::Layout::GSUB_impl::AlternateSubstFormat1_2<OT::Layout::SmallTypes> const&)
hb_empty_t OT::hb_accelerate_subtables_context_t::dispatch<OT::Layout::GSUB_impl::LigatureSubstFormat1_2<OT::Layout::SmallTypes> >(OT::Layout::GSUB_impl::LigatureSubstFormat1_2<OT::Layout::SmallTypes> const&)
Line
Count
Source
1039
74
  {
1040
74
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
1041
74
    void *external_cache = nullptr;
1042
74
    if (i < 8)
1043
74
      external_cache = external_cache_create (obj, hb_prioritize);
1044
74
#endif
1045
1046
74
    hb_applicable_t *entry = &array[i++];
1047
1048
74
    entry->init (obj,
1049
74
     apply_to<T>
1050
74
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
1051
74
     , apply_cached_to<T>
1052
74
     , cache_func_to<T>
1053
74
     , external_cache
1054
74
#endif
1055
74
     );
1056
1057
74
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
1058
    /* Cache handling
1059
     *
1060
     * We allow one subtable from each lookup to use a cache. The assumption
1061
     * being that multiple subtables of the same lookup cannot use a cache
1062
     * because the resources they would use will collide.  As such, we ask
1063
     * each subtable to tell us how much it costs (which a cache would avoid),
1064
     * and we allocate the cache opportunity to the costliest subtable.
1065
     */
1066
74
    unsigned cost = cache_cost (obj, hb_prioritize);
1067
74
    if (cost > subtable_cache_user_cost)
1068
0
    {
1069
0
      subtable_cache_user_idx = i - 1;
1070
0
      subtable_cache_user_cost = cost;
1071
0
    }
1072
74
#endif
1073
1074
74
    return hb_empty_t ();
1075
74
  }
Unexecuted instantiation: hb_empty_t OT::hb_accelerate_subtables_context_t::dispatch<OT::Layout::GSUB_impl::ReverseChainSingleSubstFormat1>(OT::Layout::GSUB_impl::ReverseChainSingleSubstFormat1 const&)
1076
985
  static return_t default_return_value () { return hb_empty_t (); }
1077
1078
  hb_accelerate_subtables_context_t (hb_applicable_t *array_) :
1079
985
             array (array_) {}
1080
1081
  hb_applicable_t *array;
1082
  unsigned i = 0;
1083
1084
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
1085
  unsigned subtable_cache_user_idx = (unsigned) -1;
1086
  unsigned subtable_cache_user_cost = 0;
1087
#endif
1088
};
1089
1090
1091
typedef bool (*intersects_func_t) (const hb_set_t *glyphs, unsigned value, const void *data, void *cache);
1092
typedef void (*intersected_glyphs_func_t) (const hb_set_t *glyphs, const void *data, unsigned value, hb_set_t *intersected_glyphs, void *cache);
1093
typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, unsigned value, const void *data);
1094
typedef bool (*match_func_t) (hb_glyph_info_t &info, unsigned value, const void *data);
1095
1096
struct ContextClosureFuncs
1097
{
1098
  intersects_func_t intersects;
1099
  intersected_glyphs_func_t intersected_glyphs;
1100
};
1101
struct ContextCollectGlyphsFuncs
1102
{
1103
  collect_glyphs_func_t collect;
1104
};
1105
struct ContextApplyFuncs
1106
{
1107
  match_func_t match;
1108
};
1109
struct ChainContextApplyFuncs
1110
{
1111
  match_func_t match[3];
1112
};
1113
1114
1115
static inline bool intersects_glyph (const hb_set_t *glyphs, unsigned value, const void *data HB_UNUSED, void *cache HB_UNUSED)
1116
0
{
1117
0
  return glyphs->has (value);
1118
0
}
Unexecuted instantiation: hb-aat-layout.cc:OT::intersects_glyph(hb_set_t const*, unsigned int, void const*, void*)
Unexecuted instantiation: hb-ot-face.cc:OT::intersects_glyph(hb_set_t const*, unsigned int, void const*, void*)
Unexecuted instantiation: hb-ot-layout.cc:OT::intersects_glyph(hb_set_t const*, unsigned int, void const*, void*)
Unexecuted instantiation: hb-ot-shaper-arabic.cc:OT::intersects_glyph(hb_set_t const*, unsigned int, void const*, void*)
Unexecuted instantiation: hb-ot-shape-fallback.cc:OT::intersects_glyph(hb_set_t const*, unsigned int, void const*, void*)
1119
static inline bool intersects_class (const hb_set_t *glyphs, unsigned value, const void *data, void *cache)
1120
0
{
1121
0
  const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
1122
0
  hb_map_t *map = (hb_map_t *) cache;
1123
1124
0
  hb_codepoint_t *cached_v;
1125
0
  if (map->has (value, &cached_v))
1126
0
    return *cached_v;
1127
1128
0
  bool v = class_def.intersects_class (glyphs, value);
1129
0
  map->set (value, v);
1130
1131
0
  return v;
1132
0
}
Unexecuted instantiation: hb-aat-layout.cc:OT::intersects_class(hb_set_t const*, unsigned int, void const*, void*)
Unexecuted instantiation: hb-ot-face.cc:OT::intersects_class(hb_set_t const*, unsigned int, void const*, void*)
Unexecuted instantiation: hb-ot-layout.cc:OT::intersects_class(hb_set_t const*, unsigned int, void const*, void*)
Unexecuted instantiation: hb-ot-shaper-arabic.cc:OT::intersects_class(hb_set_t const*, unsigned int, void const*, void*)
Unexecuted instantiation: hb-ot-shape-fallback.cc:OT::intersects_class(hb_set_t const*, unsigned int, void const*, void*)
1133
static inline bool intersects_coverage (const hb_set_t *glyphs, unsigned value, const void *data, void *cache HB_UNUSED)
1134
0
{
1135
0
  Offset16To<Coverage> coverage;
1136
0
  coverage = value;
1137
0
  return (data+coverage).intersects (glyphs);
1138
0
}
Unexecuted instantiation: hb-aat-layout.cc:OT::intersects_coverage(hb_set_t const*, unsigned int, void const*, void*)
Unexecuted instantiation: hb-ot-face.cc:OT::intersects_coverage(hb_set_t const*, unsigned int, void const*, void*)
Unexecuted instantiation: hb-ot-layout.cc:OT::intersects_coverage(hb_set_t const*, unsigned int, void const*, void*)
Unexecuted instantiation: hb-ot-shaper-arabic.cc:OT::intersects_coverage(hb_set_t const*, unsigned int, void const*, void*)
Unexecuted instantiation: hb-ot-shape-fallback.cc:OT::intersects_coverage(hb_set_t const*, unsigned int, void const*, void*)
1139
1140
1141
static inline void intersected_glyph (const hb_set_t *glyphs HB_UNUSED, const void *data, unsigned value, hb_set_t *intersected_glyphs, HB_UNUSED void *cache)
1142
0
{
1143
0
  unsigned g = reinterpret_cast<const HBUINT16 *>(data)[value];
1144
0
  intersected_glyphs->add (g);
1145
0
}
Unexecuted instantiation: hb-aat-layout.cc:OT::intersected_glyph(hb_set_t const*, void const*, unsigned int, hb_set_t*, void*)
Unexecuted instantiation: hb-ot-face.cc:OT::intersected_glyph(hb_set_t const*, void const*, unsigned int, hb_set_t*, void*)
Unexecuted instantiation: hb-ot-layout.cc:OT::intersected_glyph(hb_set_t const*, void const*, unsigned int, hb_set_t*, void*)
Unexecuted instantiation: hb-ot-shaper-arabic.cc:OT::intersected_glyph(hb_set_t const*, void const*, unsigned int, hb_set_t*, void*)
Unexecuted instantiation: hb-ot-shape-fallback.cc:OT::intersected_glyph(hb_set_t const*, void const*, unsigned int, hb_set_t*, void*)
1146
1147
using intersected_class_cache_t = hb_hashmap_t<unsigned, hb_set_t>;
1148
1149
static inline void intersected_class_glyphs (const hb_set_t *glyphs, const void *data, unsigned value, hb_set_t *intersected_glyphs, void *cache)
1150
0
{
1151
0
  const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
1152
1153
0
  intersected_class_cache_t *map = (intersected_class_cache_t *) cache;
1154
1155
0
  hb_set_t *cached_v;
1156
0
  if (map->has (value, &cached_v))
1157
0
  {
1158
0
    intersected_glyphs->union_ (*cached_v);
1159
0
    return;
1160
0
  }
1161
1162
0
  hb_set_t v;
1163
0
  class_def.intersected_class_glyphs (glyphs, value, &v);
1164
1165
0
  intersected_glyphs->union_ (v);
1166
1167
0
  map->set (value, std::move (v));
1168
0
}
Unexecuted instantiation: hb-aat-layout.cc:OT::intersected_class_glyphs(hb_set_t const*, void const*, unsigned int, hb_set_t*, void*)
Unexecuted instantiation: hb-ot-face.cc:OT::intersected_class_glyphs(hb_set_t const*, void const*, unsigned int, hb_set_t*, void*)
Unexecuted instantiation: hb-ot-layout.cc:OT::intersected_class_glyphs(hb_set_t const*, void const*, unsigned int, hb_set_t*, void*)
Unexecuted instantiation: hb-ot-shaper-arabic.cc:OT::intersected_class_glyphs(hb_set_t const*, void const*, unsigned int, hb_set_t*, void*)
Unexecuted instantiation: hb-ot-shape-fallback.cc:OT::intersected_class_glyphs(hb_set_t const*, void const*, unsigned int, hb_set_t*, void*)
1169
1170
static inline void intersected_coverage_glyphs (const hb_set_t *glyphs, const void *data, unsigned value, hb_set_t *intersected_glyphs, HB_UNUSED void *cache)
1171
0
{
1172
0
  Offset16To<Coverage> coverage;
1173
0
  coverage = value;
1174
0
  (data+coverage).intersect_set (*glyphs, *intersected_glyphs);
1175
0
}
Unexecuted instantiation: hb-aat-layout.cc:OT::intersected_coverage_glyphs(hb_set_t const*, void const*, unsigned int, hb_set_t*, void*)
Unexecuted instantiation: hb-ot-face.cc:OT::intersected_coverage_glyphs(hb_set_t const*, void const*, unsigned int, hb_set_t*, void*)
Unexecuted instantiation: hb-ot-layout.cc:OT::intersected_coverage_glyphs(hb_set_t const*, void const*, unsigned int, hb_set_t*, void*)
Unexecuted instantiation: hb-ot-shaper-arabic.cc:OT::intersected_coverage_glyphs(hb_set_t const*, void const*, unsigned int, hb_set_t*, void*)
Unexecuted instantiation: hb-ot-shape-fallback.cc:OT::intersected_coverage_glyphs(hb_set_t const*, void const*, unsigned int, hb_set_t*, void*)
1176
1177
1178
template <typename HBUINT>
1179
static inline bool array_is_subset_of (const hb_set_t *glyphs,
1180
               unsigned int count,
1181
               const HBUINT values[],
1182
               intersects_func_t intersects_func,
1183
               const void *intersects_data,
1184
               void *cache)
1185
0
{
1186
0
  for (const auto &_ : + hb_iter (values, count))
1187
0
    if (!intersects_func (glyphs, _, intersects_data, cache)) return false;
1188
0
  return true;
1189
0
}
Unexecuted instantiation: hb-aat-layout.cc:bool OT::array_is_subset_of<OT::NumType<true, unsigned short, 2u> >(hb_set_t const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, bool (*)(hb_set_t const*, unsigned int, void const*, void*), void const*, void*)
Unexecuted instantiation: hb-ot-face.cc:bool OT::array_is_subset_of<OT::NumType<true, unsigned short, 2u> >(hb_set_t const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, bool (*)(hb_set_t const*, unsigned int, void const*, void*), void const*, void*)
Unexecuted instantiation: hb-ot-layout.cc:bool OT::array_is_subset_of<OT::NumType<true, unsigned short, 2u> >(hb_set_t const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, bool (*)(hb_set_t const*, unsigned int, void const*, void*), void const*, void*)
Unexecuted instantiation: hb-ot-shaper-arabic.cc:bool OT::array_is_subset_of<OT::NumType<true, unsigned short, 2u> >(hb_set_t const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, bool (*)(hb_set_t const*, unsigned int, void const*, void*), void const*, void*)
Unexecuted instantiation: hb-ot-shape-fallback.cc:bool OT::array_is_subset_of<OT::NumType<true, unsigned short, 2u> >(hb_set_t const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, bool (*)(hb_set_t const*, unsigned int, void const*, void*), void const*, void*)
1190
1191
1192
static inline void collect_glyph (hb_set_t *glyphs, unsigned value, const void *data HB_UNUSED)
1193
0
{
1194
0
  glyphs->add (value);
1195
0
}
Unexecuted instantiation: hb-aat-layout.cc:OT::collect_glyph(hb_set_t*, unsigned int, void const*)
Unexecuted instantiation: hb-ot-face.cc:OT::collect_glyph(hb_set_t*, unsigned int, void const*)
Unexecuted instantiation: hb-ot-layout.cc:OT::collect_glyph(hb_set_t*, unsigned int, void const*)
Unexecuted instantiation: hb-ot-shaper-arabic.cc:OT::collect_glyph(hb_set_t*, unsigned int, void const*)
Unexecuted instantiation: hb-ot-shape-fallback.cc:OT::collect_glyph(hb_set_t*, unsigned int, void const*)
1196
static inline void collect_class (hb_set_t *glyphs, unsigned value, const void *data)
1197
0
{
1198
0
  const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
1199
0
  class_def.collect_class (glyphs, value);
1200
0
}
Unexecuted instantiation: hb-aat-layout.cc:OT::collect_class(hb_set_t*, unsigned int, void const*)
Unexecuted instantiation: hb-ot-face.cc:OT::collect_class(hb_set_t*, unsigned int, void const*)
Unexecuted instantiation: hb-ot-layout.cc:OT::collect_class(hb_set_t*, unsigned int, void const*)
Unexecuted instantiation: hb-ot-shaper-arabic.cc:OT::collect_class(hb_set_t*, unsigned int, void const*)
Unexecuted instantiation: hb-ot-shape-fallback.cc:OT::collect_class(hb_set_t*, unsigned int, void const*)
1201
static inline void collect_coverage (hb_set_t *glyphs, unsigned value, const void *data)
1202
0
{
1203
0
  Offset16To<Coverage> coverage;
1204
0
  coverage = value;
1205
0
  (data+coverage).collect_coverage (glyphs);
1206
0
}
Unexecuted instantiation: hb-aat-layout.cc:OT::collect_coverage(hb_set_t*, unsigned int, void const*)
Unexecuted instantiation: hb-ot-face.cc:OT::collect_coverage(hb_set_t*, unsigned int, void const*)
Unexecuted instantiation: hb-ot-layout.cc:OT::collect_coverage(hb_set_t*, unsigned int, void const*)
Unexecuted instantiation: hb-ot-shaper-arabic.cc:OT::collect_coverage(hb_set_t*, unsigned int, void const*)
Unexecuted instantiation: hb-ot-shape-fallback.cc:OT::collect_coverage(hb_set_t*, unsigned int, void const*)
1207
template <typename HBUINT>
1208
static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED,
1209
          hb_set_t *glyphs,
1210
          unsigned int count,
1211
          const HBUINT values[],
1212
          collect_glyphs_func_t collect_func,
1213
          const void *collect_data)
1214
0
{
1215
0
  return
1216
0
  + hb_iter (values, count)
1217
0
  | hb_apply ([&] (const HBUINT &_) { collect_func (glyphs, _, collect_data); })
1218
0
  ;
1219
0
}
Unexecuted instantiation: hb-aat-layout.cc:void OT::collect_array<OT::NumType<true, unsigned short, 2u> >(OT::hb_collect_glyphs_context_t*, hb_set_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, void (*)(hb_set_t*, unsigned int, void const*), void const*)
Unexecuted instantiation: hb-ot-face.cc:void OT::collect_array<OT::NumType<true, unsigned short, 2u> >(OT::hb_collect_glyphs_context_t*, hb_set_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, void (*)(hb_set_t*, unsigned int, void const*), void const*)
Unexecuted instantiation: hb-ot-layout.cc:void OT::collect_array<OT::NumType<true, unsigned short, 2u> >(OT::hb_collect_glyphs_context_t*, hb_set_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, void (*)(hb_set_t*, unsigned int, void const*), void const*)
Unexecuted instantiation: hb-ot-shaper-arabic.cc:void OT::collect_array<OT::NumType<true, unsigned short, 2u> >(OT::hb_collect_glyphs_context_t*, hb_set_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, void (*)(hb_set_t*, unsigned int, void const*), void const*)
Unexecuted instantiation: hb-ot-shape-fallback.cc:void OT::collect_array<OT::NumType<true, unsigned short, 2u> >(OT::hb_collect_glyphs_context_t*, hb_set_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, void (*)(hb_set_t*, unsigned int, void const*), void const*)
1220
1221
1222
static inline bool match_always (hb_glyph_info_t &info HB_UNUSED, unsigned value HB_UNUSED, const void *data HB_UNUSED)
1223
24.3k
{
1224
24.3k
  return true;
1225
24.3k
}
Unexecuted instantiation: hb-aat-layout.cc:OT::match_always(hb_glyph_info_t&, unsigned int, void const*)
Unexecuted instantiation: hb-ot-face.cc:OT::match_always(hb_glyph_info_t&, unsigned int, void const*)
hb-ot-layout.cc:OT::match_always(hb_glyph_info_t&, unsigned int, void const*)
Line
Count
Source
1223
24.3k
{
1224
24.3k
  return true;
1225
24.3k
}
Unexecuted instantiation: hb-ot-shaper-arabic.cc:OT::match_always(hb_glyph_info_t&, unsigned int, void const*)
Unexecuted instantiation: hb-ot-shape-fallback.cc:OT::match_always(hb_glyph_info_t&, unsigned int, void const*)
1226
static inline bool match_glyph (hb_glyph_info_t &info, unsigned value, const void *data HB_UNUSED)
1227
147k
{
1228
147k
  return info.codepoint == value;
1229
147k
}
Unexecuted instantiation: hb-aat-layout.cc:OT::match_glyph(hb_glyph_info_t&, unsigned int, void const*)
Unexecuted instantiation: hb-ot-face.cc:OT::match_glyph(hb_glyph_info_t&, unsigned int, void const*)
hb-ot-layout.cc:OT::match_glyph(hb_glyph_info_t&, unsigned int, void const*)
Line
Count
Source
1227
147k
{
1228
147k
  return info.codepoint == value;
1229
147k
}
Unexecuted instantiation: hb-ot-shaper-arabic.cc:OT::match_glyph(hb_glyph_info_t&, unsigned int, void const*)
Unexecuted instantiation: hb-ot-shape-fallback.cc:OT::match_glyph(hb_glyph_info_t&, unsigned int, void const*)
1230
static inline bool match_class (hb_glyph_info_t &info, unsigned value, const void *data)
1231
0
{
1232
0
  const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
1233
0
  return class_def.get_class (info.codepoint) == value;
1234
0
}
Unexecuted instantiation: hb-aat-layout.cc:OT::match_class(hb_glyph_info_t&, unsigned int, void const*)
Unexecuted instantiation: hb-ot-face.cc:OT::match_class(hb_glyph_info_t&, unsigned int, void const*)
Unexecuted instantiation: hb-ot-layout.cc:OT::match_class(hb_glyph_info_t&, unsigned int, void const*)
Unexecuted instantiation: hb-ot-shaper-arabic.cc:OT::match_class(hb_glyph_info_t&, unsigned int, void const*)
Unexecuted instantiation: hb-ot-shape-fallback.cc:OT::match_class(hb_glyph_info_t&, unsigned int, void const*)
1235
static inline unsigned get_class_cached (const ClassDef &class_def, hb_glyph_info_t &info)
1236
0
{
1237
0
  unsigned klass = info.syllable();
1238
0
  if (klass < 255)
1239
0
    return klass;
1240
0
  klass = class_def.get_class (info.codepoint);
1241
0
  if (likely (klass < 255))
1242
0
    info.syllable() = klass;
1243
0
  return klass;
1244
0
}
Unexecuted instantiation: hb-aat-layout.cc:OT::get_class_cached(OT::ClassDef const&, hb_glyph_info_t&)
Unexecuted instantiation: hb-ot-face.cc:OT::get_class_cached(OT::ClassDef const&, hb_glyph_info_t&)
Unexecuted instantiation: hb-ot-layout.cc:OT::get_class_cached(OT::ClassDef const&, hb_glyph_info_t&)
Unexecuted instantiation: hb-ot-shaper-arabic.cc:OT::get_class_cached(OT::ClassDef const&, hb_glyph_info_t&)
Unexecuted instantiation: hb-ot-shape-fallback.cc:OT::get_class_cached(OT::ClassDef const&, hb_glyph_info_t&)
1245
static inline bool match_class_cached (hb_glyph_info_t &info, unsigned value, const void *data)
1246
0
{
1247
0
  const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
1248
0
  return get_class_cached (class_def, info) == value;
1249
0
}
Unexecuted instantiation: hb-aat-layout.cc:OT::match_class_cached(hb_glyph_info_t&, unsigned int, void const*)
Unexecuted instantiation: hb-ot-face.cc:OT::match_class_cached(hb_glyph_info_t&, unsigned int, void const*)
Unexecuted instantiation: hb-ot-layout.cc:OT::match_class_cached(hb_glyph_info_t&, unsigned int, void const*)
Unexecuted instantiation: hb-ot-shaper-arabic.cc:OT::match_class_cached(hb_glyph_info_t&, unsigned int, void const*)
Unexecuted instantiation: hb-ot-shape-fallback.cc:OT::match_class_cached(hb_glyph_info_t&, unsigned int, void const*)
1250
static inline unsigned get_class_cached1 (const ClassDef &class_def, hb_glyph_info_t &info)
1251
0
{
1252
0
  unsigned klass = info.syllable() & 0x0F;
1253
0
  if (klass < 15)
1254
0
    return klass;
1255
0
  klass = class_def.get_class (info.codepoint);
1256
0
  if (likely (klass < 15))
1257
0
    info.syllable() = (info.syllable() & 0xF0) | klass;
1258
0
  return klass;
1259
0
}
Unexecuted instantiation: hb-aat-layout.cc:OT::get_class_cached1(OT::ClassDef const&, hb_glyph_info_t&)
Unexecuted instantiation: hb-ot-face.cc:OT::get_class_cached1(OT::ClassDef const&, hb_glyph_info_t&)
Unexecuted instantiation: hb-ot-layout.cc:OT::get_class_cached1(OT::ClassDef const&, hb_glyph_info_t&)
Unexecuted instantiation: hb-ot-shaper-arabic.cc:OT::get_class_cached1(OT::ClassDef const&, hb_glyph_info_t&)
Unexecuted instantiation: hb-ot-shape-fallback.cc:OT::get_class_cached1(OT::ClassDef const&, hb_glyph_info_t&)
1260
static inline bool match_class_cached1 (hb_glyph_info_t &info, unsigned value, const void *data)
1261
0
{
1262
0
  const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
1263
0
  return get_class_cached1 (class_def, info) == value;
1264
0
}
Unexecuted instantiation: hb-aat-layout.cc:OT::match_class_cached1(hb_glyph_info_t&, unsigned int, void const*)
Unexecuted instantiation: hb-ot-face.cc:OT::match_class_cached1(hb_glyph_info_t&, unsigned int, void const*)
Unexecuted instantiation: hb-ot-layout.cc:OT::match_class_cached1(hb_glyph_info_t&, unsigned int, void const*)
Unexecuted instantiation: hb-ot-shaper-arabic.cc:OT::match_class_cached1(hb_glyph_info_t&, unsigned int, void const*)
Unexecuted instantiation: hb-ot-shape-fallback.cc:OT::match_class_cached1(hb_glyph_info_t&, unsigned int, void const*)
1265
static inline unsigned get_class_cached2 (const ClassDef &class_def, hb_glyph_info_t &info)
1266
0
{
1267
0
  unsigned klass = (info.syllable() & 0xF0) >> 4;
1268
0
  if (klass < 15)
1269
0
    return klass;
1270
0
  klass = class_def.get_class (info.codepoint);
1271
0
  if (likely (klass < 15))
1272
0
    info.syllable() = (info.syllable() & 0x0F) | (klass << 4);
1273
0
  return klass;
1274
0
}
Unexecuted instantiation: hb-aat-layout.cc:OT::get_class_cached2(OT::ClassDef const&, hb_glyph_info_t&)
Unexecuted instantiation: hb-ot-face.cc:OT::get_class_cached2(OT::ClassDef const&, hb_glyph_info_t&)
Unexecuted instantiation: hb-ot-layout.cc:OT::get_class_cached2(OT::ClassDef const&, hb_glyph_info_t&)
Unexecuted instantiation: hb-ot-shaper-arabic.cc:OT::get_class_cached2(OT::ClassDef const&, hb_glyph_info_t&)
Unexecuted instantiation: hb-ot-shape-fallback.cc:OT::get_class_cached2(OT::ClassDef const&, hb_glyph_info_t&)
1275
static inline bool match_class_cached2 (hb_glyph_info_t &info, unsigned value, const void *data)
1276
0
{
1277
0
  const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
1278
0
  return get_class_cached2 (class_def, info) == value;
1279
0
}
Unexecuted instantiation: hb-aat-layout.cc:OT::match_class_cached2(hb_glyph_info_t&, unsigned int, void const*)
Unexecuted instantiation: hb-ot-face.cc:OT::match_class_cached2(hb_glyph_info_t&, unsigned int, void const*)
Unexecuted instantiation: hb-ot-layout.cc:OT::match_class_cached2(hb_glyph_info_t&, unsigned int, void const*)
Unexecuted instantiation: hb-ot-shaper-arabic.cc:OT::match_class_cached2(hb_glyph_info_t&, unsigned int, void const*)
Unexecuted instantiation: hb-ot-shape-fallback.cc:OT::match_class_cached2(hb_glyph_info_t&, unsigned int, void const*)
1280
static inline bool match_coverage (hb_glyph_info_t &info, unsigned value, const void *data)
1281
718k
{
1282
718k
  Offset16To<Coverage> coverage;
1283
718k
  coverage = value;
1284
718k
  return (data+coverage).get_coverage (info.codepoint) != NOT_COVERED;
1285
718k
}
Unexecuted instantiation: hb-aat-layout.cc:OT::match_coverage(hb_glyph_info_t&, unsigned int, void const*)
Unexecuted instantiation: hb-ot-face.cc:OT::match_coverage(hb_glyph_info_t&, unsigned int, void const*)
hb-ot-layout.cc:OT::match_coverage(hb_glyph_info_t&, unsigned int, void const*)
Line
Count
Source
1281
718k
{
1282
718k
  Offset16To<Coverage> coverage;
1283
718k
  coverage = value;
1284
718k
  return (data+coverage).get_coverage (info.codepoint) != NOT_COVERED;
1285
718k
}
Unexecuted instantiation: hb-ot-shaper-arabic.cc:OT::match_coverage(hb_glyph_info_t&, unsigned int, void const*)
Unexecuted instantiation: hb-ot-shape-fallback.cc:OT::match_coverage(hb_glyph_info_t&, unsigned int, void const*)
1286
1287
template <typename HBUINT>
1288
static inline bool would_match_input (hb_would_apply_context_t *c,
1289
              unsigned int count, /* Including the first glyph (not matched) */
1290
              const HBUINT input[], /* Array of input values--start with second glyph */
1291
              match_func_t match_func,
1292
              const void *match_data)
1293
0
{
1294
0
  if (count != c->len)
1295
0
    return false;
1296
1297
0
  for (unsigned int i = 1; i < count; i++)
1298
0
  {
1299
0
    hb_glyph_info_t info;
1300
0
    info.codepoint = c->glyphs[i];
1301
0
    if (likely (!match_func (info, input[i - 1], match_data)))
1302
0
      return false;
1303
0
  }
1304
1305
0
  return true;
1306
0
}
Unexecuted instantiation: hb-aat-layout.cc:bool OT::would_match_input<OT::NumType<true, unsigned short, 2u> >(OT::hb_would_apply_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, bool (*)(hb_glyph_info_t&, unsigned int, void const*), void const*)
Unexecuted instantiation: hb-ot-face.cc:bool OT::would_match_input<OT::NumType<true, unsigned short, 2u> >(OT::hb_would_apply_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, bool (*)(hb_glyph_info_t&, unsigned int, void const*), void const*)
Unexecuted instantiation: hb-ot-layout.cc:bool OT::would_match_input<OT::NumType<true, unsigned short, 2u> >(OT::hb_would_apply_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, bool (*)(hb_glyph_info_t&, unsigned int, void const*), void const*)
Unexecuted instantiation: hb-ot-shaper-arabic.cc:bool OT::would_match_input<OT::NumType<true, unsigned short, 2u> >(OT::hb_would_apply_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, bool (*)(hb_glyph_info_t&, unsigned int, void const*), void const*)
Unexecuted instantiation: hb-ot-shape-fallback.cc:bool OT::would_match_input<OT::NumType<true, unsigned short, 2u> >(OT::hb_would_apply_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, bool (*)(hb_glyph_info_t&, unsigned int, void const*), void const*)
1307
template <typename HBUINT>
1308
#ifndef HB_OPTIMIZE_SIZE
1309
HB_ALWAYS_INLINE
1310
#endif
1311
static bool match_input (hb_ot_apply_context_t *c,
1312
       unsigned int count, /* Including the first glyph (not matched) */
1313
       const HBUINT input[], /* Array of input values--start with second glyph */
1314
       match_func_t match_func,
1315
       const void *match_data,
1316
       unsigned int *end_position,
1317
       unsigned int *p_total_component_count = nullptr)
1318
1.32M
{
1319
1.32M
  TRACE_APPLY (nullptr);
1320
1321
1.32M
  hb_buffer_t *buffer = c->buffer;
1322
1323
1.32M
  if (count == 1)
1324
955k
  {
1325
955k
    *end_position = buffer->idx + 1;
1326
955k
    c->match_positions[0] = buffer->idx;
1327
955k
    if (p_total_component_count)
1328
0
      *p_total_component_count = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
1329
955k
    return_trace (true);
1330
955k
  }
1331
1332
374k
  if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return_trace (false);
1333
1334
374k
  auto &skippy_iter = c->iter_input;
1335
374k
  skippy_iter.reset (buffer->idx);
1336
374k
  skippy_iter.set_match_func (match_func, match_data);
1337
374k
  skippy_iter.set_glyph_data (input);
1338
1339
  /*
1340
   * This is perhaps the trickiest part of OpenType...  Remarks:
1341
   *
1342
   * - If all components of the ligature were marks, we call this a mark ligature.
1343
   *
1344
   * - If there is no GDEF, and the ligature is NOT a mark ligature, we categorize
1345
   *   it as a ligature glyph.
1346
   *
1347
   * - Ligatures cannot be formed across glyphs attached to different components
1348
   *   of previous ligatures.  Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and
1349
   *   LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother.
1350
   *   However, it would be wrong to ligate that SHADDA,FATHA sequence.
1351
   *   There are a couple of exceptions to this:
1352
   *
1353
   *   o If a ligature tries ligating with marks that belong to it itself, go ahead,
1354
   *     assuming that the font designer knows what they are doing (otherwise it can
1355
   *     break Indic stuff when a matra wants to ligate with a conjunct,
1356
   *
1357
   *   o If two marks want to ligate and they belong to different components of the
1358
   *     same ligature glyph, and said ligature glyph is to be ignored according to
1359
   *     mark-filtering rules, then allow.
1360
   *     https://github.com/harfbuzz/harfbuzz/issues/545
1361
   */
1362
1363
374k
  unsigned int total_component_count = 0;
1364
1365
374k
  unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
1366
374k
  unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
1367
1368
374k
  enum {
1369
374k
    LIGBASE_NOT_CHECKED,
1370
374k
    LIGBASE_MAY_NOT_SKIP,
1371
374k
    LIGBASE_MAY_SKIP
1372
374k
  } ligbase = LIGBASE_NOT_CHECKED;
1373
1374
412k
  for (unsigned int i = 1; i < count; i++)
1375
374k
  {
1376
374k
    unsigned unsafe_to;
1377
374k
    if (!skippy_iter.next (&unsafe_to))
1378
337k
    {
1379
337k
      *end_position = unsafe_to;
1380
337k
      return_trace (false);
1381
337k
    }
1382
1383
37.3k
    if (unlikely (i + 1 > c->match_positions.length &&
1384
37.3k
      !c->match_positions.resize_dirty  (i + 1)))
1385
0
      return_trace (false);
1386
37.3k
    c->match_positions.arrayZ[i] = skippy_iter.idx;
1387
1388
37.3k
    unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]);
1389
37.3k
    unsigned int this_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]);
1390
1391
37.3k
    if (first_lig_id && first_lig_comp)
1392
0
    {
1393
      /* If first component was attached to a previous ligature component,
1394
       * all subsequent components should be attached to the same ligature
1395
       * component, otherwise we shouldn't ligate them... */
1396
0
      if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp)
1397
0
      {
1398
  /* ...unless, we are attached to a base ligature and that base
1399
   * ligature is ignorable. */
1400
0
  if (ligbase == LIGBASE_NOT_CHECKED)
1401
0
  {
1402
0
    bool found = false;
1403
0
    const auto *out = buffer->out_info;
1404
0
    unsigned int j = buffer->out_len;
1405
0
    while (j && _hb_glyph_info_get_lig_id (&out[j - 1]) == first_lig_id)
1406
0
    {
1407
0
      if (_hb_glyph_info_get_lig_comp (&out[j - 1]) == 0)
1408
0
      {
1409
0
        j--;
1410
0
        found = true;
1411
0
        break;
1412
0
      }
1413
0
      j--;
1414
0
    }
1415
1416
0
    if (found && skippy_iter.may_skip (out[j]) == matcher_t::SKIP_YES)
1417
0
      ligbase = LIGBASE_MAY_SKIP;
1418
0
    else
1419
0
      ligbase = LIGBASE_MAY_NOT_SKIP;
1420
0
  }
1421
1422
0
  if (ligbase == LIGBASE_MAY_NOT_SKIP)
1423
0
    return_trace (false);
1424
0
      }
1425
0
    }
1426
37.3k
    else
1427
37.3k
    {
1428
      /* If first component was NOT attached to a previous ligature component,
1429
       * all subsequent components should also NOT be attached to any ligature
1430
       * component, unless they are attached to the first component itself! */
1431
37.3k
      if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id))
1432
0
  return_trace (false);
1433
37.3k
    }
1434
1435
37.3k
    total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->info[skippy_iter.idx]);
1436
37.3k
  }
1437
1438
37.0k
  *end_position = skippy_iter.idx + 1;
1439
1440
37.0k
  if (p_total_component_count)
1441
22.6k
  {
1442
22.6k
    total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur());
1443
22.6k
    *p_total_component_count = total_component_count;
1444
22.6k
  }
1445
1446
37.0k
  c->match_positions.arrayZ[0] = buffer->idx;
1447
1448
37.0k
  return_trace (true);
1449
374k
}
Unexecuted instantiation: hb-aat-layout.cc:bool OT::match_input<OT::NumType<true, unsigned short, 2u> >(OT::hb_ot_apply_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, bool (*)(hb_glyph_info_t&, unsigned int, void const*), void const*, unsigned int*, unsigned int*)
Unexecuted instantiation: hb-aat-layout.cc:bool OT::match_input<OT::HBGlyphID16>(OT::hb_ot_apply_context_t*, unsigned int, OT::HBGlyphID16 const*, bool (*)(hb_glyph_info_t&, unsigned int, void const*), void const*, unsigned int*, unsigned int*)
Unexecuted instantiation: hb-ot-face.cc:bool OT::match_input<OT::NumType<true, unsigned short, 2u> >(OT::hb_ot_apply_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, bool (*)(hb_glyph_info_t&, unsigned int, void const*), void const*, unsigned int*, unsigned int*)
Unexecuted instantiation: hb-ot-face.cc:bool OT::match_input<OT::HBGlyphID16>(OT::hb_ot_apply_context_t*, unsigned int, OT::HBGlyphID16 const*, bool (*)(hb_glyph_info_t&, unsigned int, void const*), void const*, unsigned int*, unsigned int*)
hb-ot-layout.cc:bool OT::match_input<OT::HBGlyphID16>(OT::hb_ot_apply_context_t*, unsigned int, OT::HBGlyphID16 const*, bool (*)(hb_glyph_info_t&, unsigned int, void const*), void const*, unsigned int*, unsigned int*)
Line
Count
Source
1318
304k
{
1319
304k
  TRACE_APPLY (nullptr);
1320
1321
304k
  hb_buffer_t *buffer = c->buffer;
1322
1323
304k
  if (count == 1)
1324
0
  {
1325
0
    *end_position = buffer->idx + 1;
1326
0
    c->match_positions[0] = buffer->idx;
1327
0
    if (p_total_component_count)
1328
0
      *p_total_component_count = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
1329
0
    return_trace (true);
1330
0
  }
1331
1332
304k
  if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return_trace (false);
1333
1334
304k
  auto &skippy_iter = c->iter_input;
1335
304k
  skippy_iter.reset (buffer->idx);
1336
304k
  skippy_iter.set_match_func (match_func, match_data);
1337
304k
  skippy_iter.set_glyph_data (input);
1338
1339
  /*
1340
   * This is perhaps the trickiest part of OpenType...  Remarks:
1341
   *
1342
   * - If all components of the ligature were marks, we call this a mark ligature.
1343
   *
1344
   * - If there is no GDEF, and the ligature is NOT a mark ligature, we categorize
1345
   *   it as a ligature glyph.
1346
   *
1347
   * - Ligatures cannot be formed across glyphs attached to different components
1348
   *   of previous ligatures.  Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and
1349
   *   LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother.
1350
   *   However, it would be wrong to ligate that SHADDA,FATHA sequence.
1351
   *   There are a couple of exceptions to this:
1352
   *
1353
   *   o If a ligature tries ligating with marks that belong to it itself, go ahead,
1354
   *     assuming that the font designer knows what they are doing (otherwise it can
1355
   *     break Indic stuff when a matra wants to ligate with a conjunct,
1356
   *
1357
   *   o If two marks want to ligate and they belong to different components of the
1358
   *     same ligature glyph, and said ligature glyph is to be ignored according to
1359
   *     mark-filtering rules, then allow.
1360
   *     https://github.com/harfbuzz/harfbuzz/issues/545
1361
   */
1362
1363
304k
  unsigned int total_component_count = 0;
1364
1365
304k
  unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
1366
304k
  unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
1367
1368
304k
  enum {
1369
304k
    LIGBASE_NOT_CHECKED,
1370
304k
    LIGBASE_MAY_NOT_SKIP,
1371
304k
    LIGBASE_MAY_SKIP
1372
304k
  } ligbase = LIGBASE_NOT_CHECKED;
1373
1374
327k
  for (unsigned int i = 1; i < count; i++)
1375
304k
  {
1376
304k
    unsigned unsafe_to;
1377
304k
    if (!skippy_iter.next (&unsafe_to))
1378
281k
    {
1379
281k
      *end_position = unsafe_to;
1380
281k
      return_trace (false);
1381
281k
    }
1382
1383
22.9k
    if (unlikely (i + 1 > c->match_positions.length &&
1384
22.9k
      !c->match_positions.resize_dirty  (i + 1)))
1385
0
      return_trace (false);
1386
22.9k
    c->match_positions.arrayZ[i] = skippy_iter.idx;
1387
1388
22.9k
    unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]);
1389
22.9k
    unsigned int this_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]);
1390
1391
22.9k
    if (first_lig_id && first_lig_comp)
1392
0
    {
1393
      /* If first component was attached to a previous ligature component,
1394
       * all subsequent components should be attached to the same ligature
1395
       * component, otherwise we shouldn't ligate them... */
1396
0
      if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp)
1397
0
      {
1398
  /* ...unless, we are attached to a base ligature and that base
1399
   * ligature is ignorable. */
1400
0
  if (ligbase == LIGBASE_NOT_CHECKED)
1401
0
  {
1402
0
    bool found = false;
1403
0
    const auto *out = buffer->out_info;
1404
0
    unsigned int j = buffer->out_len;
1405
0
    while (j && _hb_glyph_info_get_lig_id (&out[j - 1]) == first_lig_id)
1406
0
    {
1407
0
      if (_hb_glyph_info_get_lig_comp (&out[j - 1]) == 0)
1408
0
      {
1409
0
        j--;
1410
0
        found = true;
1411
0
        break;
1412
0
      }
1413
0
      j--;
1414
0
    }
1415
1416
0
    if (found && skippy_iter.may_skip (out[j]) == matcher_t::SKIP_YES)
1417
0
      ligbase = LIGBASE_MAY_SKIP;
1418
0
    else
1419
0
      ligbase = LIGBASE_MAY_NOT_SKIP;
1420
0
  }
1421
1422
0
  if (ligbase == LIGBASE_MAY_NOT_SKIP)
1423
0
    return_trace (false);
1424
0
      }
1425
0
    }
1426
22.9k
    else
1427
22.9k
    {
1428
      /* If first component was NOT attached to a previous ligature component,
1429
       * all subsequent components should also NOT be attached to any ligature
1430
       * component, unless they are attached to the first component itself! */
1431
22.9k
      if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id))
1432
0
  return_trace (false);
1433
22.9k
    }
1434
1435
22.9k
    total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->info[skippy_iter.idx]);
1436
22.9k
  }
1437
1438
22.6k
  *end_position = skippy_iter.idx + 1;
1439
1440
22.6k
  if (p_total_component_count)
1441
22.6k
  {
1442
22.6k
    total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur());
1443
22.6k
    *p_total_component_count = total_component_count;
1444
22.6k
  }
1445
1446
22.6k
  c->match_positions.arrayZ[0] = buffer->idx;
1447
1448
22.6k
  return_trace (true);
1449
304k
}
hb-ot-layout.cc:bool OT::match_input<OT::NumType<true, unsigned short, 2u> >(OT::hb_ot_apply_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, bool (*)(hb_glyph_info_t&, unsigned int, void const*), void const*, unsigned int*, unsigned int*)
Line
Count
Source
1318
1.02M
{
1319
1.02M
  TRACE_APPLY (nullptr);
1320
1321
1.02M
  hb_buffer_t *buffer = c->buffer;
1322
1323
1.02M
  if (count == 1)
1324
955k
  {
1325
955k
    *end_position = buffer->idx + 1;
1326
955k
    c->match_positions[0] = buffer->idx;
1327
955k
    if (p_total_component_count)
1328
0
      *p_total_component_count = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
1329
955k
    return_trace (true);
1330
955k
  }
1331
1332
70.4k
  if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return_trace (false);
1333
1334
70.4k
  auto &skippy_iter = c->iter_input;
1335
70.4k
  skippy_iter.reset (buffer->idx);
1336
70.4k
  skippy_iter.set_match_func (match_func, match_data);
1337
70.4k
  skippy_iter.set_glyph_data (input);
1338
1339
  /*
1340
   * This is perhaps the trickiest part of OpenType...  Remarks:
1341
   *
1342
   * - If all components of the ligature were marks, we call this a mark ligature.
1343
   *
1344
   * - If there is no GDEF, and the ligature is NOT a mark ligature, we categorize
1345
   *   it as a ligature glyph.
1346
   *
1347
   * - Ligatures cannot be formed across glyphs attached to different components
1348
   *   of previous ligatures.  Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and
1349
   *   LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother.
1350
   *   However, it would be wrong to ligate that SHADDA,FATHA sequence.
1351
   *   There are a couple of exceptions to this:
1352
   *
1353
   *   o If a ligature tries ligating with marks that belong to it itself, go ahead,
1354
   *     assuming that the font designer knows what they are doing (otherwise it can
1355
   *     break Indic stuff when a matra wants to ligate with a conjunct,
1356
   *
1357
   *   o If two marks want to ligate and they belong to different components of the
1358
   *     same ligature glyph, and said ligature glyph is to be ignored according to
1359
   *     mark-filtering rules, then allow.
1360
   *     https://github.com/harfbuzz/harfbuzz/issues/545
1361
   */
1362
1363
70.4k
  unsigned int total_component_count = 0;
1364
1365
70.4k
  unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
1366
70.4k
  unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
1367
1368
70.4k
  enum {
1369
70.4k
    LIGBASE_NOT_CHECKED,
1370
70.4k
    LIGBASE_MAY_NOT_SKIP,
1371
70.4k
    LIGBASE_MAY_SKIP
1372
70.4k
  } ligbase = LIGBASE_NOT_CHECKED;
1373
1374
84.8k
  for (unsigned int i = 1; i < count; i++)
1375
70.4k
  {
1376
70.4k
    unsigned unsafe_to;
1377
70.4k
    if (!skippy_iter.next (&unsafe_to))
1378
56.0k
    {
1379
56.0k
      *end_position = unsafe_to;
1380
56.0k
      return_trace (false);
1381
56.0k
    }
1382
1383
14.4k
    if (unlikely (i + 1 > c->match_positions.length &&
1384
14.4k
      !c->match_positions.resize_dirty  (i + 1)))
1385
0
      return_trace (false);
1386
14.4k
    c->match_positions.arrayZ[i] = skippy_iter.idx;
1387
1388
14.4k
    unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]);
1389
14.4k
    unsigned int this_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]);
1390
1391
14.4k
    if (first_lig_id && first_lig_comp)
1392
0
    {
1393
      /* If first component was attached to a previous ligature component,
1394
       * all subsequent components should be attached to the same ligature
1395
       * component, otherwise we shouldn't ligate them... */
1396
0
      if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp)
1397
0
      {
1398
  /* ...unless, we are attached to a base ligature and that base
1399
   * ligature is ignorable. */
1400
0
  if (ligbase == LIGBASE_NOT_CHECKED)
1401
0
  {
1402
0
    bool found = false;
1403
0
    const auto *out = buffer->out_info;
1404
0
    unsigned int j = buffer->out_len;
1405
0
    while (j && _hb_glyph_info_get_lig_id (&out[j - 1]) == first_lig_id)
1406
0
    {
1407
0
      if (_hb_glyph_info_get_lig_comp (&out[j - 1]) == 0)
1408
0
      {
1409
0
        j--;
1410
0
        found = true;
1411
0
        break;
1412
0
      }
1413
0
      j--;
1414
0
    }
1415
1416
0
    if (found && skippy_iter.may_skip (out[j]) == matcher_t::SKIP_YES)
1417
0
      ligbase = LIGBASE_MAY_SKIP;
1418
0
    else
1419
0
      ligbase = LIGBASE_MAY_NOT_SKIP;
1420
0
  }
1421
1422
0
  if (ligbase == LIGBASE_MAY_NOT_SKIP)
1423
0
    return_trace (false);
1424
0
      }
1425
0
    }
1426
14.4k
    else
1427
14.4k
    {
1428
      /* If first component was NOT attached to a previous ligature component,
1429
       * all subsequent components should also NOT be attached to any ligature
1430
       * component, unless they are attached to the first component itself! */
1431
14.4k
      if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id))
1432
0
  return_trace (false);
1433
14.4k
    }
1434
1435
14.4k
    total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->info[skippy_iter.idx]);
1436
14.4k
  }
1437
1438
14.4k
  *end_position = skippy_iter.idx + 1;
1439
1440
14.4k
  if (p_total_component_count)
1441
0
  {
1442
0
    total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur());
1443
0
    *p_total_component_count = total_component_count;
1444
0
  }
1445
1446
14.4k
  c->match_positions.arrayZ[0] = buffer->idx;
1447
1448
14.4k
  return_trace (true);
1449
70.4k
}
Unexecuted instantiation: hb-ot-shaper-arabic.cc:bool OT::match_input<OT::HBGlyphID16>(OT::hb_ot_apply_context_t*, unsigned int, OT::HBGlyphID16 const*, bool (*)(hb_glyph_info_t&, unsigned int, void const*), void const*, unsigned int*, unsigned int*)
Unexecuted instantiation: hb-ot-shaper-arabic.cc:bool OT::match_input<OT::NumType<true, unsigned short, 2u> >(OT::hb_ot_apply_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, bool (*)(hb_glyph_info_t&, unsigned int, void const*), void const*, unsigned int*, unsigned int*)
Unexecuted instantiation: hb-ot-shape-fallback.cc:bool OT::match_input<OT::NumType<true, unsigned short, 2u> >(OT::hb_ot_apply_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, bool (*)(hb_glyph_info_t&, unsigned int, void const*), void const*, unsigned int*, unsigned int*)
1450
static inline bool ligate_input (hb_ot_apply_context_t *c,
1451
         unsigned int count, /* Including the first glyph */
1452
         unsigned int match_end,
1453
         hb_codepoint_t lig_glyph,
1454
         unsigned int total_component_count)
1455
22.6k
{
1456
22.6k
  TRACE_APPLY (nullptr);
1457
1458
22.6k
  hb_buffer_t *buffer = c->buffer;
1459
1460
22.6k
  buffer->merge_clusters (buffer->idx, match_end);
1461
1462
  /* - If a base and one or more marks ligate, consider that as a base, NOT
1463
   *   ligature, such that all following marks can still attach to it.
1464
   *   https://github.com/harfbuzz/harfbuzz/issues/1109
1465
   *
1466
   * - If all components of the ligature were marks, we call this a mark ligature.
1467
   *   If it *is* a mark ligature, we don't allocate a new ligature id, and leave
1468
   *   the ligature to keep its old ligature id.  This will allow it to attach to
1469
   *   a base ligature in GPOS.  Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH,
1470
   *   and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA with a
1471
   *   ligature id and component value of 2.  Then if SHADDA,FATHA form a ligature
1472
   *   later, we don't want them to lose their ligature id/component, otherwise
1473
   *   GPOS will fail to correctly position the mark ligature on top of the
1474
   *   LAM,LAM,HEH ligature.  See:
1475
   *     https://bugzilla.gnome.org/show_bug.cgi?id=676343
1476
   *
1477
   * - If a ligature is formed of components that some of which are also ligatures
1478
   *   themselves, and those ligature components had marks attached to *their*
1479
   *   components, we have to attach the marks to the new ligature component
1480
   *   positions!  Now *that*'s tricky!  And these marks may be following the
1481
   *   last component of the whole sequence, so we should loop forward looking
1482
   *   for them and update them.
1483
   *
1484
   *   Eg. the sequence is LAM,LAM,SHADDA,FATHA,HEH, and the font first forms a
1485
   *   'calt' ligature of LAM,HEH, leaving the SHADDA and FATHA with a ligature
1486
   *   id and component == 1.  Now, during 'liga', the LAM and the LAM-HEH ligature
1487
   *   form a LAM-LAM-HEH ligature.  We need to reassign the SHADDA and FATHA to
1488
   *   the new ligature with a component value of 2.
1489
   *
1490
   *   This in fact happened to a font...  See:
1491
   *   https://bugzilla.gnome.org/show_bug.cgi?id=437633
1492
   */
1493
1494
22.6k
  bool is_base_ligature = _hb_glyph_info_is_base_glyph (&buffer->info[c->match_positions.arrayZ[0]]);
1495
22.6k
  bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->info[c->match_positions.arrayZ[0]]);
1496
45.4k
  for (unsigned int i = 1; i < count; i++)
1497
22.7k
    if (!_hb_glyph_info_is_mark (&buffer->info[c->match_positions.arrayZ[i]]))
1498
0
    {
1499
0
      is_base_ligature = false;
1500
0
      is_mark_ligature = false;
1501
0
      break;
1502
0
    }
1503
22.6k
  bool is_ligature = !is_base_ligature && !is_mark_ligature;
1504
1505
22.6k
  unsigned int klass = is_ligature ? HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE : 0;
1506
22.6k
  unsigned int lig_id = is_ligature ? _hb_allocate_lig_id (buffer) : 0;
1507
22.6k
  unsigned int last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
1508
22.6k
  unsigned int last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
1509
22.6k
  unsigned int components_so_far = last_num_components;
1510
1511
22.6k
  if (is_ligature)
1512
0
  {
1513
0
    _hb_glyph_info_set_lig_props_for_ligature (&buffer->cur(), lig_id, total_component_count);
1514
0
    if (_hb_glyph_info_get_general_category (&buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
1515
0
    {
1516
0
      _hb_glyph_info_set_general_category (&buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER);
1517
0
    }
1518
0
  }
1519
22.6k
  c->replace_glyph_with_ligature (lig_glyph, klass);
1520
1521
45.4k
  for (unsigned int i = 1; i < count; i++)
1522
22.7k
  {
1523
22.7k
    while (buffer->idx < c->match_positions.arrayZ[i] && buffer->successful)
1524
0
    {
1525
0
      if (is_ligature)
1526
0
      {
1527
0
  unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
1528
0
  if (this_comp == 0)
1529
0
    this_comp = last_num_components;
1530
0
  assert (components_so_far >= last_num_components);
1531
0
  unsigned int new_lig_comp = components_so_far - last_num_components +
1532
0
            hb_min (this_comp, last_num_components);
1533
0
    _hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp);
1534
0
      }
1535
0
      (void) buffer->next_glyph ();
1536
0
    }
1537
1538
22.7k
    last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
1539
22.7k
    last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
1540
22.7k
    components_so_far += last_num_components;
1541
1542
    /* Skip the base glyph */
1543
22.7k
    buffer->idx++;
1544
22.7k
  }
1545
1546
22.6k
  if (!is_mark_ligature && last_lig_id)
1547
0
  {
1548
    /* Re-adjust components for any marks following. */
1549
0
    for (unsigned i = buffer->idx; i < buffer->len; ++i)
1550
0
    {
1551
0
      if (last_lig_id != _hb_glyph_info_get_lig_id (&buffer->info[i])) break;
1552
1553
0
      unsigned this_comp = _hb_glyph_info_get_lig_comp (&buffer->info[i]);
1554
0
      if (!this_comp) break;
1555
1556
0
      assert (components_so_far >= last_num_components);
1557
0
      unsigned new_lig_comp = components_so_far - last_num_components +
1558
0
            hb_min (this_comp, last_num_components);
1559
0
      _hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp);
1560
0
    }
1561
0
  }
1562
22.6k
  return_trace (true);
1563
22.6k
}
Unexecuted instantiation: hb-aat-layout.cc:OT::ligate_input(OT::hb_ot_apply_context_t*, unsigned int, unsigned int, unsigned int, unsigned int)
Unexecuted instantiation: hb-ot-face.cc:OT::ligate_input(OT::hb_ot_apply_context_t*, unsigned int, unsigned int, unsigned int, unsigned int)
hb-ot-layout.cc:OT::ligate_input(OT::hb_ot_apply_context_t*, unsigned int, unsigned int, unsigned int, unsigned int)
Line
Count
Source
1455
22.6k
{
1456
22.6k
  TRACE_APPLY (nullptr);
1457
1458
22.6k
  hb_buffer_t *buffer = c->buffer;
1459
1460
22.6k
  buffer->merge_clusters (buffer->idx, match_end);
1461
1462
  /* - If a base and one or more marks ligate, consider that as a base, NOT
1463
   *   ligature, such that all following marks can still attach to it.
1464
   *   https://github.com/harfbuzz/harfbuzz/issues/1109
1465
   *
1466
   * - If all components of the ligature were marks, we call this a mark ligature.
1467
   *   If it *is* a mark ligature, we don't allocate a new ligature id, and leave
1468
   *   the ligature to keep its old ligature id.  This will allow it to attach to
1469
   *   a base ligature in GPOS.  Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH,
1470
   *   and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA with a
1471
   *   ligature id and component value of 2.  Then if SHADDA,FATHA form a ligature
1472
   *   later, we don't want them to lose their ligature id/component, otherwise
1473
   *   GPOS will fail to correctly position the mark ligature on top of the
1474
   *   LAM,LAM,HEH ligature.  See:
1475
   *     https://bugzilla.gnome.org/show_bug.cgi?id=676343
1476
   *
1477
   * - If a ligature is formed of components that some of which are also ligatures
1478
   *   themselves, and those ligature components had marks attached to *their*
1479
   *   components, we have to attach the marks to the new ligature component
1480
   *   positions!  Now *that*'s tricky!  And these marks may be following the
1481
   *   last component of the whole sequence, so we should loop forward looking
1482
   *   for them and update them.
1483
   *
1484
   *   Eg. the sequence is LAM,LAM,SHADDA,FATHA,HEH, and the font first forms a
1485
   *   'calt' ligature of LAM,HEH, leaving the SHADDA and FATHA with a ligature
1486
   *   id and component == 1.  Now, during 'liga', the LAM and the LAM-HEH ligature
1487
   *   form a LAM-LAM-HEH ligature.  We need to reassign the SHADDA and FATHA to
1488
   *   the new ligature with a component value of 2.
1489
   *
1490
   *   This in fact happened to a font...  See:
1491
   *   https://bugzilla.gnome.org/show_bug.cgi?id=437633
1492
   */
1493
1494
22.6k
  bool is_base_ligature = _hb_glyph_info_is_base_glyph (&buffer->info[c->match_positions.arrayZ[0]]);
1495
22.6k
  bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->info[c->match_positions.arrayZ[0]]);
1496
45.4k
  for (unsigned int i = 1; i < count; i++)
1497
22.7k
    if (!_hb_glyph_info_is_mark (&buffer->info[c->match_positions.arrayZ[i]]))
1498
0
    {
1499
0
      is_base_ligature = false;
1500
0
      is_mark_ligature = false;
1501
0
      break;
1502
0
    }
1503
22.6k
  bool is_ligature = !is_base_ligature && !is_mark_ligature;
1504
1505
22.6k
  unsigned int klass = is_ligature ? HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE : 0;
1506
22.6k
  unsigned int lig_id = is_ligature ? _hb_allocate_lig_id (buffer) : 0;
1507
22.6k
  unsigned int last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
1508
22.6k
  unsigned int last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
1509
22.6k
  unsigned int components_so_far = last_num_components;
1510
1511
22.6k
  if (is_ligature)
1512
0
  {
1513
0
    _hb_glyph_info_set_lig_props_for_ligature (&buffer->cur(), lig_id, total_component_count);
1514
0
    if (_hb_glyph_info_get_general_category (&buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
1515
0
    {
1516
0
      _hb_glyph_info_set_general_category (&buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER);
1517
0
    }
1518
0
  }
1519
22.6k
  c->replace_glyph_with_ligature (lig_glyph, klass);
1520
1521
45.4k
  for (unsigned int i = 1; i < count; i++)
1522
22.7k
  {
1523
22.7k
    while (buffer->idx < c->match_positions.arrayZ[i] && buffer->successful)
1524
0
    {
1525
0
      if (is_ligature)
1526
0
      {
1527
0
  unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
1528
0
  if (this_comp == 0)
1529
0
    this_comp = last_num_components;
1530
0
  assert (components_so_far >= last_num_components);
1531
0
  unsigned int new_lig_comp = components_so_far - last_num_components +
1532
0
            hb_min (this_comp, last_num_components);
1533
0
    _hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp);
1534
0
      }
1535
0
      (void) buffer->next_glyph ();
1536
0
    }
1537
1538
22.7k
    last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
1539
22.7k
    last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
1540
22.7k
    components_so_far += last_num_components;
1541
1542
    /* Skip the base glyph */
1543
22.7k
    buffer->idx++;
1544
22.7k
  }
1545
1546
22.6k
  if (!is_mark_ligature && last_lig_id)
1547
0
  {
1548
    /* Re-adjust components for any marks following. */
1549
0
    for (unsigned i = buffer->idx; i < buffer->len; ++i)
1550
0
    {
1551
0
      if (last_lig_id != _hb_glyph_info_get_lig_id (&buffer->info[i])) break;
1552
1553
0
      unsigned this_comp = _hb_glyph_info_get_lig_comp (&buffer->info[i]);
1554
0
      if (!this_comp) break;
1555
1556
0
      assert (components_so_far >= last_num_components);
1557
0
      unsigned new_lig_comp = components_so_far - last_num_components +
1558
0
            hb_min (this_comp, last_num_components);
1559
0
      _hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp);
1560
0
    }
1561
0
  }
1562
22.6k
  return_trace (true);
1563
22.6k
}
Unexecuted instantiation: hb-ot-shaper-arabic.cc:OT::ligate_input(OT::hb_ot_apply_context_t*, unsigned int, unsigned int, unsigned int, unsigned int)
Unexecuted instantiation: hb-ot-shape-fallback.cc:OT::ligate_input(OT::hb_ot_apply_context_t*, unsigned int, unsigned int, unsigned int, unsigned int)
1564
1565
template <typename HBUINT>
1566
#ifndef HB_OPTIMIZE_SIZE
1567
HB_ALWAYS_INLINE
1568
#endif
1569
static bool match_backtrack (hb_ot_apply_context_t *c,
1570
           unsigned int count,
1571
           const HBUINT backtrack[],
1572
           match_func_t match_func,
1573
           const void *match_data,
1574
           unsigned int *match_start)
1575
570k
{
1576
570k
  TRACE_APPLY (nullptr);
1577
1578
570k
  if (!count)
1579
287
  {
1580
287
    *match_start = c->buffer->backtrack_len ();
1581
287
    return_trace (true);
1582
287
  }
1583
1584
569k
  auto &skippy_iter = c->iter_context;
1585
569k
  skippy_iter.reset_back (c->buffer->backtrack_len ());
1586
569k
  skippy_iter.set_match_func (match_func, match_data);
1587
569k
  skippy_iter.set_glyph_data (backtrack);
1588
1589
663k
  for (unsigned int i = 0; i < count; i++)
1590
652k
  {
1591
652k
    unsigned unsafe_from;
1592
652k
    if (!skippy_iter.prev (&unsafe_from))
1593
559k
    {
1594
559k
      *match_start = unsafe_from;
1595
559k
      return_trace (false);
1596
559k
    }
1597
652k
  }
1598
1599
10.7k
  *match_start = skippy_iter.idx;
1600
10.7k
  return_trace (true);
1601
569k
}
Unexecuted instantiation: hb-aat-layout.cc:bool OT::match_backtrack<OT::NumType<true, unsigned short, 2u> >(OT::hb_ot_apply_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, bool (*)(hb_glyph_info_t&, unsigned int, void const*), void const*, unsigned int*)
Unexecuted instantiation: hb-ot-face.cc:bool OT::match_backtrack<OT::NumType<true, unsigned short, 2u> >(OT::hb_ot_apply_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, bool (*)(hb_glyph_info_t&, unsigned int, void const*), void const*, unsigned int*)
hb-ot-layout.cc:bool OT::match_backtrack<OT::NumType<true, unsigned short, 2u> >(OT::hb_ot_apply_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, bool (*)(hb_glyph_info_t&, unsigned int, void const*), void const*, unsigned int*)
Line
Count
Source
1575
570k
{
1576
570k
  TRACE_APPLY (nullptr);
1577
1578
570k
  if (!count)
1579
287
  {
1580
287
    *match_start = c->buffer->backtrack_len ();
1581
287
    return_trace (true);
1582
287
  }
1583
1584
569k
  auto &skippy_iter = c->iter_context;
1585
569k
  skippy_iter.reset_back (c->buffer->backtrack_len ());
1586
569k
  skippy_iter.set_match_func (match_func, match_data);
1587
569k
  skippy_iter.set_glyph_data (backtrack);
1588
1589
663k
  for (unsigned int i = 0; i < count; i++)
1590
652k
  {
1591
652k
    unsigned unsafe_from;
1592
652k
    if (!skippy_iter.prev (&unsafe_from))
1593
559k
    {
1594
559k
      *match_start = unsafe_from;
1595
559k
      return_trace (false);
1596
559k
    }
1597
652k
  }
1598
1599
10.7k
  *match_start = skippy_iter.idx;
1600
10.7k
  return_trace (true);
1601
569k
}
Unexecuted instantiation: hb-ot-shaper-arabic.cc:bool OT::match_backtrack<OT::NumType<true, unsigned short, 2u> >(OT::hb_ot_apply_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, bool (*)(hb_glyph_info_t&, unsigned int, void const*), void const*, unsigned int*)
Unexecuted instantiation: hb-ot-shape-fallback.cc:bool OT::match_backtrack<OT::NumType<true, unsigned short, 2u> >(OT::hb_ot_apply_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, bool (*)(hb_glyph_info_t&, unsigned int, void const*), void const*, unsigned int*)
1602
1603
template <typename HBUINT>
1604
#ifndef HB_OPTIMIZE_SIZE
1605
HB_ALWAYS_INLINE
1606
#endif
1607
static bool match_lookahead (hb_ot_apply_context_t *c,
1608
           unsigned int count,
1609
           const HBUINT lookahead[],
1610
           match_func_t match_func,
1611
           const void *match_data,
1612
           unsigned int start_index,
1613
           unsigned int *end_index)
1614
969k
{
1615
969k
  TRACE_APPLY (nullptr);
1616
1617
969k
  if (!count)
1618
487k
  {
1619
487k
    *end_index = start_index;
1620
487k
    return_trace (true);
1621
487k
  }
1622
1623
482k
  auto &skippy_iter = c->iter_context;
1624
482k
  assert (start_index >= 1);
1625
482k
  skippy_iter.reset (start_index - 1);
1626
482k
  skippy_iter.set_match_func (match_func, match_data);
1627
482k
  skippy_iter.set_glyph_data (lookahead);
1628
1629
564k
  for (unsigned int i = 0; i < count; i++)
1630
482k
  {
1631
482k
    unsigned unsafe_to;
1632
482k
    if (!skippy_iter.next (&unsafe_to))
1633
399k
    {
1634
399k
      *end_index = unsafe_to;
1635
399k
      return_trace (false);
1636
399k
    }
1637
482k
  }
1638
1639
82.6k
  *end_index = skippy_iter.idx + 1;
1640
82.6k
  return_trace (true);
1641
482k
}
Unexecuted instantiation: hb-aat-layout.cc:bool OT::match_lookahead<OT::NumType<true, unsigned short, 2u> >(OT::hb_ot_apply_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, bool (*)(hb_glyph_info_t&, unsigned int, void const*), void const*, unsigned int, unsigned int*)
Unexecuted instantiation: hb-ot-face.cc:bool OT::match_lookahead<OT::NumType<true, unsigned short, 2u> >(OT::hb_ot_apply_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, bool (*)(hb_glyph_info_t&, unsigned int, void const*), void const*, unsigned int, unsigned int*)
hb-ot-layout.cc:bool OT::match_lookahead<OT::NumType<true, unsigned short, 2u> >(OT::hb_ot_apply_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, bool (*)(hb_glyph_info_t&, unsigned int, void const*), void const*, unsigned int, unsigned int*)
Line
Count
Source
1614
969k
{
1615
969k
  TRACE_APPLY (nullptr);
1616
1617
969k
  if (!count)
1618
487k
  {
1619
487k
    *end_index = start_index;
1620
487k
    return_trace (true);
1621
487k
  }
1622
1623
482k
  auto &skippy_iter = c->iter_context;
1624
482k
  assert (start_index >= 1);
1625
482k
  skippy_iter.reset (start_index - 1);
1626
482k
  skippy_iter.set_match_func (match_func, match_data);
1627
482k
  skippy_iter.set_glyph_data (lookahead);
1628
1629
564k
  for (unsigned int i = 0; i < count; i++)
1630
482k
  {
1631
482k
    unsigned unsafe_to;
1632
482k
    if (!skippy_iter.next (&unsafe_to))
1633
399k
    {
1634
399k
      *end_index = unsafe_to;
1635
399k
      return_trace (false);
1636
399k
    }
1637
482k
  }
1638
1639
82.6k
  *end_index = skippy_iter.idx + 1;
1640
82.6k
  return_trace (true);
1641
482k
}
Unexecuted instantiation: hb-ot-shaper-arabic.cc:bool OT::match_lookahead<OT::NumType<true, unsigned short, 2u> >(OT::hb_ot_apply_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, bool (*)(hb_glyph_info_t&, unsigned int, void const*), void const*, unsigned int, unsigned int*)
Unexecuted instantiation: hb-ot-shape-fallback.cc:bool OT::match_lookahead<OT::NumType<true, unsigned short, 2u> >(OT::hb_ot_apply_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, bool (*)(hb_glyph_info_t&, unsigned int, void const*), void const*, unsigned int, unsigned int*)
1642
1643
1644
1645
struct LookupRecord
1646
{
1647
  bool serialize (hb_serialize_context_t *c,
1648
      const hb_map_t         *lookup_map) const
1649
0
  {
1650
0
    TRACE_SERIALIZE (this);
1651
0
    auto *out = c->embed (*this);
1652
0
    if (unlikely (!out)) return_trace (false);
1653
0
1654
0
    return_trace (c->check_assign (out->lookupListIndex, lookup_map->get (lookupListIndex), HB_SERIALIZE_ERROR_INT_OVERFLOW));
1655
0
  }
1656
1657
  bool sanitize (hb_sanitize_context_t *c) const
1658
0
  {
1659
0
    TRACE_SANITIZE (this);
1660
0
    return_trace (c->check_struct (this));
1661
0
  }
1662
1663
  HBUINT16  sequenceIndex;    /* Index into current glyph
1664
           * sequence--first glyph = 0 */
1665
  HBUINT16  lookupListIndex;  /* Lookup to apply to that
1666
           * position--zero--based */
1667
  public:
1668
  DEFINE_SIZE_STATIC (4);
1669
};
1670
1671
static unsigned serialize_lookuprecord_array (hb_serialize_context_t *c,
1672
                const hb_array_t<const LookupRecord> lookupRecords,
1673
                const hb_map_t *lookup_map)
1674
0
{
1675
0
  unsigned count = 0;
1676
0
  for (const LookupRecord& r : lookupRecords)
1677
0
  {
1678
0
    if (!lookup_map->has (r.lookupListIndex))
1679
0
      continue;
1680
0
1681
0
    if (!r.serialize (c, lookup_map))
1682
0
      return 0;
1683
0
1684
0
    count++;
1685
0
  }
1686
0
  return count;
1687
0
}
Unexecuted instantiation: hb-aat-layout.cc:OT::serialize_lookuprecord_array(hb_serialize_context_t*, hb_array_t<OT::LookupRecord const>, hb_map_t const*)
Unexecuted instantiation: hb-ot-face.cc:OT::serialize_lookuprecord_array(hb_serialize_context_t*, hb_array_t<OT::LookupRecord const>, hb_map_t const*)
Unexecuted instantiation: hb-ot-layout.cc:OT::serialize_lookuprecord_array(hb_serialize_context_t*, hb_array_t<OT::LookupRecord const>, hb_map_t const*)
Unexecuted instantiation: hb-ot-shaper-arabic.cc:OT::serialize_lookuprecord_array(hb_serialize_context_t*, hb_array_t<OT::LookupRecord const>, hb_map_t const*)
Unexecuted instantiation: hb-ot-shape-fallback.cc:OT::serialize_lookuprecord_array(hb_serialize_context_t*, hb_array_t<OT::LookupRecord const>, hb_map_t const*)
1688
1689
enum ContextFormat { SimpleContext = 1, ClassBasedContext = 2, CoverageBasedContext = 3 };
1690
1691
template <typename HBUINT>
1692
static void context_closure_recurse_lookups (hb_closure_context_t *c,
1693
               unsigned inputCount, const HBUINT input[],
1694
               unsigned lookupCount,
1695
               const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */,
1696
               unsigned value,
1697
               ContextFormat context_format,
1698
               const void *data,
1699
               intersected_glyphs_func_t intersected_glyphs_func,
1700
               void *cache)
1701
0
{
1702
0
  hb_set_t covered_seq_indicies;
1703
0
  hb_set_t pos_glyphs;
1704
0
  for (unsigned int i = 0; i < lookupCount; i++)
1705
0
  {
1706
0
    unsigned seqIndex = lookupRecord[i].sequenceIndex;
1707
0
    if (seqIndex >= inputCount) continue;
1708
1709
0
    bool has_pos_glyphs = false;
1710
1711
0
    if (!covered_seq_indicies.has (seqIndex))
1712
0
    {
1713
0
      has_pos_glyphs = true;
1714
0
      pos_glyphs.clear ();
1715
0
      if (seqIndex == 0)
1716
0
      {
1717
0
        switch (context_format) {
1718
0
        case ContextFormat::SimpleContext:
1719
0
          pos_glyphs.add (value);
1720
0
          break;
1721
0
        case ContextFormat::ClassBasedContext:
1722
0
          intersected_glyphs_func (&c->parent_active_glyphs (), data, value, &pos_glyphs, cache);
1723
0
          break;
1724
0
        case ContextFormat::CoverageBasedContext:
1725
0
          pos_glyphs.set (c->parent_active_glyphs ());
1726
0
          break;
1727
0
        }
1728
0
      }
1729
0
      else
1730
0
      {
1731
0
        const void *input_data = input;
1732
0
        unsigned input_value = seqIndex - 1;
1733
0
        if (context_format != ContextFormat::SimpleContext)
1734
0
        {
1735
0
          input_data = data;
1736
0
          input_value = input[seqIndex - 1];
1737
0
        }
1738
1739
0
        intersected_glyphs_func (c->glyphs, input_data, input_value, &pos_glyphs, cache);
1740
0
      }
1741
0
    }
1742
1743
0
    covered_seq_indicies.add (seqIndex);
1744
0
    hb_set_t *cur_active_glyphs = c->push_cur_active_glyphs ();
1745
0
    if (unlikely (!cur_active_glyphs))
1746
0
      return;
1747
0
    if (has_pos_glyphs) {
1748
0
      *cur_active_glyphs = std::move (pos_glyphs);
1749
0
    } else {
1750
0
      *cur_active_glyphs = *c->glyphs;
1751
0
    }
1752
1753
0
    unsigned endIndex = inputCount;
1754
0
    if (context_format == ContextFormat::CoverageBasedContext)
1755
0
      endIndex += 1;
1756
1757
0
    c->recurse (lookupRecord[i].lookupListIndex, &covered_seq_indicies, seqIndex, endIndex);
1758
1759
0
    c->pop_cur_done_glyphs ();
1760
0
  }
1761
0
}
Unexecuted instantiation: hb-aat-layout.cc:void OT::context_closure_recurse_lookups<OT::NumType<true, unsigned short, 2u> >(OT::hb_closure_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::LookupRecord const*, unsigned int, OT::ContextFormat, void const*, void (*)(hb_set_t const*, void const*, unsigned int, hb_set_t*, void*), void*)
Unexecuted instantiation: hb-ot-face.cc:void OT::context_closure_recurse_lookups<OT::NumType<true, unsigned short, 2u> >(OT::hb_closure_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::LookupRecord const*, unsigned int, OT::ContextFormat, void const*, void (*)(hb_set_t const*, void const*, unsigned int, hb_set_t*, void*), void*)
Unexecuted instantiation: hb-ot-layout.cc:void OT::context_closure_recurse_lookups<OT::NumType<true, unsigned short, 2u> >(OT::hb_closure_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::LookupRecord const*, unsigned int, OT::ContextFormat, void const*, void (*)(hb_set_t const*, void const*, unsigned int, hb_set_t*, void*), void*)
Unexecuted instantiation: hb-ot-shaper-arabic.cc:void OT::context_closure_recurse_lookups<OT::NumType<true, unsigned short, 2u> >(OT::hb_closure_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::LookupRecord const*, unsigned int, OT::ContextFormat, void const*, void (*)(hb_set_t const*, void const*, unsigned int, hb_set_t*, void*), void*)
Unexecuted instantiation: hb-ot-shape-fallback.cc:void OT::context_closure_recurse_lookups<OT::NumType<true, unsigned short, 2u> >(OT::hb_closure_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::LookupRecord const*, unsigned int, OT::ContextFormat, void const*, void (*)(hb_set_t const*, void const*, unsigned int, hb_set_t*, void*), void*)
1762
1763
template <typename context_t>
1764
static inline void recurse_lookups (context_t *c,
1765
                                    unsigned int lookupCount,
1766
                                    const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
1767
0
{
1768
0
  for (unsigned int i = 0; i < lookupCount; i++)
1769
0
    c->recurse (lookupRecord[i].lookupListIndex);
1770
0
}
Unexecuted instantiation: hb-aat-layout.cc:void OT::recurse_lookups<OT::hb_closure_lookups_context_t>(OT::hb_closure_lookups_context_t*, unsigned int, OT::LookupRecord const*)
Unexecuted instantiation: hb-aat-layout.cc:void OT::recurse_lookups<OT::hb_collect_glyphs_context_t>(OT::hb_collect_glyphs_context_t*, unsigned int, OT::LookupRecord const*)
Unexecuted instantiation: hb-ot-face.cc:void OT::recurse_lookups<OT::hb_closure_lookups_context_t>(OT::hb_closure_lookups_context_t*, unsigned int, OT::LookupRecord const*)
Unexecuted instantiation: hb-ot-face.cc:void OT::recurse_lookups<OT::hb_collect_glyphs_context_t>(OT::hb_collect_glyphs_context_t*, unsigned int, OT::LookupRecord const*)
Unexecuted instantiation: hb-ot-layout.cc:void OT::recurse_lookups<OT::hb_collect_glyphs_context_t>(OT::hb_collect_glyphs_context_t*, unsigned int, OT::LookupRecord const*)
Unexecuted instantiation: hb-ot-layout.cc:void OT::recurse_lookups<OT::hb_closure_lookups_context_t>(OT::hb_closure_lookups_context_t*, unsigned int, OT::LookupRecord const*)
Unexecuted instantiation: hb-ot-shaper-arabic.cc:void OT::recurse_lookups<OT::hb_closure_lookups_context_t>(OT::hb_closure_lookups_context_t*, unsigned int, OT::LookupRecord const*)
Unexecuted instantiation: hb-ot-shaper-arabic.cc:void OT::recurse_lookups<OT::hb_collect_glyphs_context_t>(OT::hb_collect_glyphs_context_t*, unsigned int, OT::LookupRecord const*)
Unexecuted instantiation: hb-ot-shape-fallback.cc:void OT::recurse_lookups<OT::hb_closure_lookups_context_t>(OT::hb_closure_lookups_context_t*, unsigned int, OT::LookupRecord const*)
Unexecuted instantiation: hb-ot-shape-fallback.cc:void OT::recurse_lookups<OT::hb_collect_glyphs_context_t>(OT::hb_collect_glyphs_context_t*, unsigned int, OT::LookupRecord const*)
1771
1772
static inline void apply_lookup (hb_ot_apply_context_t *c,
1773
         unsigned int count, /* Including the first glyph */
1774
         unsigned int lookupCount,
1775
         const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
1776
         unsigned int match_end)
1777
10.9k
{
1778
10.9k
  hb_buffer_t *buffer = c->buffer;
1779
10.9k
  int end;
1780
1781
  /* All positions are distance from beginning of *output* buffer.
1782
   * Adjust. */
1783
10.9k
  {
1784
10.9k
    unsigned int bl = buffer->backtrack_len ();
1785
10.9k
    end = bl + match_end - buffer->idx;
1786
1787
10.9k
    int delta = bl - buffer->idx;
1788
    /* Convert positions to new indexing. */
1789
22.2k
    for (unsigned int j = 0; j < count; j++)
1790
11.2k
      c->match_positions.arrayZ[j] += delta;
1791
10.9k
  }
1792
1793
21.9k
  for (unsigned int i = 0; i < lookupCount && buffer->successful; i++)
1794
10.9k
  {
1795
10.9k
    unsigned int idx = lookupRecord[i].sequenceIndex;
1796
10.9k
    if (idx >= count)
1797
0
      continue;
1798
1799
10.9k
    unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
1800
1801
    /* This can happen if earlier recursed lookups deleted many entries. */
1802
10.9k
    if (unlikely (c->match_positions.arrayZ[idx] >= orig_len))
1803
0
      continue;
1804
1805
10.9k
    if (unlikely (!buffer->move_to (c->match_positions.arrayZ[idx])))
1806
0
      break;
1807
1808
10.9k
    if (unlikely (buffer->max_ops <= 0))
1809
0
      break;
1810
1811
10.9k
    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
1812
0
    {
1813
0
      if (buffer->have_output)
1814
0
        c->buffer->sync_so_far ();
1815
0
      c->buffer->message (c->font,
1816
0
        "recursing to lookup %u at %u",
1817
0
        (unsigned) lookupRecord[i].lookupListIndex,
1818
0
        buffer->idx);
1819
0
    }
1820
1821
10.9k
    if (!c->recurse (lookupRecord[i].lookupListIndex))
1822
282
      continue;
1823
1824
10.7k
    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
1825
0
    {
1826
0
      if (buffer->have_output)
1827
0
        c->buffer->sync_so_far ();
1828
0
      c->buffer->message (c->font,
1829
0
        "recursed to lookup %u",
1830
0
        (unsigned) lookupRecord[i].lookupListIndex);
1831
0
    }
1832
1833
10.7k
    unsigned int new_len = buffer->backtrack_len () + buffer->lookahead_len ();
1834
10.7k
    int delta = new_len - orig_len;
1835
1836
10.7k
    if (!delta)
1837
10.7k
      continue;
1838
1839
    /* Recursed lookup changed buffer len.  Adjust.
1840
     *
1841
     * TODO:
1842
     *
1843
     * Right now, if buffer length increased by n, we assume n new glyphs
1844
     * were added right after the current position, and if buffer length
1845
     * was decreased by n, we assume n match positions after the current
1846
     * one where removed.  The former (buffer length increased) case is
1847
     * fine, but the decrease case can be improved in at least two ways,
1848
     * both of which are significant:
1849
     *
1850
     *   - If recursed-to lookup is MultipleSubst and buffer length
1851
     *     decreased, then it's current match position that was deleted,
1852
     *     NOT the one after it.
1853
     *
1854
     *   - If buffer length was decreased by n, it does not necessarily
1855
     *     mean that n match positions where removed, as there recursed-to
1856
     *     lookup might had a different LookupFlag.  Here's a constructed
1857
     *     case of that:
1858
     *     https://github.com/harfbuzz/harfbuzz/discussions/3538
1859
     *
1860
     * It should be possible to construct tests for both of these cases.
1861
     */
1862
1863
5
    end += delta;
1864
5
    if (end < int (c->match_positions.arrayZ[idx]))
1865
0
    {
1866
      /* End might end up being smaller than match_positions.arrayZ[idx] if the recursed
1867
       * lookup ended up removing many items.
1868
       * Just never rewind end beyond start of current position, since that is
1869
       * not possible in the recursed lookup.  Also adjust delta as such.
1870
       *
1871
       * https://bugs.chromium.org/p/chromium/issues/detail?id=659496
1872
       * https://github.com/harfbuzz/harfbuzz/issues/1611
1873
       */
1874
0
      delta += c->match_positions.arrayZ[idx] - end;
1875
0
      end = c->match_positions.arrayZ[idx];
1876
0
    }
1877
1878
5
    unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */
1879
1880
5
    if (delta > 0)
1881
0
    {
1882
0
      if (unlikely (delta + count > HB_MAX_CONTEXT_LENGTH))
1883
0
  break;
1884
0
      if (unlikely (count + delta > c->match_positions.length &&
1885
0
        !c->match_positions.resize_dirty  (count + delta)))
1886
0
        return;
1887
0
    }
1888
5
    else
1889
5
    {
1890
      /* NOTE: delta is non-positive. */
1891
5
      delta = hb_max (delta, (int) next - (int) count);
1892
5
      next -= delta;
1893
5
    }
1894
1895
    /* Shift! */
1896
5
    memmove (c->match_positions + next + delta, c->match_positions + next,
1897
5
       (count - next) * sizeof (c->match_positions.arrayZ[0]));
1898
5
    next += delta;
1899
5
    count += delta;
1900
1901
    /* Fill in new entries. */
1902
5
    for (unsigned int j = idx + 1; j < next; j++)
1903
0
      c->match_positions.arrayZ[j] = c->match_positions.arrayZ[j - 1] + 1;
1904
1905
    /* And fixup the rest. */
1906
5
    for (; next < count; next++)
1907
0
      c->match_positions.arrayZ[next] += delta;
1908
5
  }
1909
1910
10.9k
  assert (end >= 0);
1911
10.9k
  (void) buffer->move_to (end);
1912
10.9k
}
Unexecuted instantiation: hb-aat-layout.cc:OT::apply_lookup(OT::hb_ot_apply_context_t*, unsigned int, unsigned int, OT::LookupRecord const*, unsigned int)
Unexecuted instantiation: hb-ot-face.cc:OT::apply_lookup(OT::hb_ot_apply_context_t*, unsigned int, unsigned int, OT::LookupRecord const*, unsigned int)
hb-ot-layout.cc:OT::apply_lookup(OT::hb_ot_apply_context_t*, unsigned int, unsigned int, OT::LookupRecord const*, unsigned int)
Line
Count
Source
1777
10.9k
{
1778
10.9k
  hb_buffer_t *buffer = c->buffer;
1779
10.9k
  int end;
1780
1781
  /* All positions are distance from beginning of *output* buffer.
1782
   * Adjust. */
1783
10.9k
  {
1784
10.9k
    unsigned int bl = buffer->backtrack_len ();
1785
10.9k
    end = bl + match_end - buffer->idx;
1786
1787
10.9k
    int delta = bl - buffer->idx;
1788
    /* Convert positions to new indexing. */
1789
22.2k
    for (unsigned int j = 0; j < count; j++)
1790
11.2k
      c->match_positions.arrayZ[j] += delta;
1791
10.9k
  }
1792
1793
21.9k
  for (unsigned int i = 0; i < lookupCount && buffer->successful; i++)
1794
10.9k
  {
1795
10.9k
    unsigned int idx = lookupRecord[i].sequenceIndex;
1796
10.9k
    if (idx >= count)
1797
0
      continue;
1798
1799
10.9k
    unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
1800
1801
    /* This can happen if earlier recursed lookups deleted many entries. */
1802
10.9k
    if (unlikely (c->match_positions.arrayZ[idx] >= orig_len))
1803
0
      continue;
1804
1805
10.9k
    if (unlikely (!buffer->move_to (c->match_positions.arrayZ[idx])))
1806
0
      break;
1807
1808
10.9k
    if (unlikely (buffer->max_ops <= 0))
1809
0
      break;
1810
1811
10.9k
    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
1812
0
    {
1813
0
      if (buffer->have_output)
1814
0
        c->buffer->sync_so_far ();
1815
0
      c->buffer->message (c->font,
1816
0
        "recursing to lookup %u at %u",
1817
0
        (unsigned) lookupRecord[i].lookupListIndex,
1818
0
        buffer->idx);
1819
0
    }
1820
1821
10.9k
    if (!c->recurse (lookupRecord[i].lookupListIndex))
1822
282
      continue;
1823
1824
10.7k
    if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
1825
0
    {
1826
0
      if (buffer->have_output)
1827
0
        c->buffer->sync_so_far ();
1828
0
      c->buffer->message (c->font,
1829
0
        "recursed to lookup %u",
1830
0
        (unsigned) lookupRecord[i].lookupListIndex);
1831
0
    }
1832
1833
10.7k
    unsigned int new_len = buffer->backtrack_len () + buffer->lookahead_len ();
1834
10.7k
    int delta = new_len - orig_len;
1835
1836
10.7k
    if (!delta)
1837
10.7k
      continue;
1838
1839
    /* Recursed lookup changed buffer len.  Adjust.
1840
     *
1841
     * TODO:
1842
     *
1843
     * Right now, if buffer length increased by n, we assume n new glyphs
1844
     * were added right after the current position, and if buffer length
1845
     * was decreased by n, we assume n match positions after the current
1846
     * one where removed.  The former (buffer length increased) case is
1847
     * fine, but the decrease case can be improved in at least two ways,
1848
     * both of which are significant:
1849
     *
1850
     *   - If recursed-to lookup is MultipleSubst and buffer length
1851
     *     decreased, then it's current match position that was deleted,
1852
     *     NOT the one after it.
1853
     *
1854
     *   - If buffer length was decreased by n, it does not necessarily
1855
     *     mean that n match positions where removed, as there recursed-to
1856
     *     lookup might had a different LookupFlag.  Here's a constructed
1857
     *     case of that:
1858
     *     https://github.com/harfbuzz/harfbuzz/discussions/3538
1859
     *
1860
     * It should be possible to construct tests for both of these cases.
1861
     */
1862
1863
5
    end += delta;
1864
5
    if (end < int (c->match_positions.arrayZ[idx]))
1865
0
    {
1866
      /* End might end up being smaller than match_positions.arrayZ[idx] if the recursed
1867
       * lookup ended up removing many items.
1868
       * Just never rewind end beyond start of current position, since that is
1869
       * not possible in the recursed lookup.  Also adjust delta as such.
1870
       *
1871
       * https://bugs.chromium.org/p/chromium/issues/detail?id=659496
1872
       * https://github.com/harfbuzz/harfbuzz/issues/1611
1873
       */
1874
0
      delta += c->match_positions.arrayZ[idx] - end;
1875
0
      end = c->match_positions.arrayZ[idx];
1876
0
    }
1877
1878
5
    unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */
1879
1880
5
    if (delta > 0)
1881
0
    {
1882
0
      if (unlikely (delta + count > HB_MAX_CONTEXT_LENGTH))
1883
0
  break;
1884
0
      if (unlikely (count + delta > c->match_positions.length &&
1885
0
        !c->match_positions.resize_dirty  (count + delta)))
1886
0
        return;
1887
0
    }
1888
5
    else
1889
5
    {
1890
      /* NOTE: delta is non-positive. */
1891
5
      delta = hb_max (delta, (int) next - (int) count);
1892
5
      next -= delta;
1893
5
    }
1894
1895
    /* Shift! */
1896
5
    memmove (c->match_positions + next + delta, c->match_positions + next,
1897
5
       (count - next) * sizeof (c->match_positions.arrayZ[0]));
1898
5
    next += delta;
1899
5
    count += delta;
1900
1901
    /* Fill in new entries. */
1902
5
    for (unsigned int j = idx + 1; j < next; j++)
1903
0
      c->match_positions.arrayZ[j] = c->match_positions.arrayZ[j - 1] + 1;
1904
1905
    /* And fixup the rest. */
1906
5
    for (; next < count; next++)
1907
0
      c->match_positions.arrayZ[next] += delta;
1908
5
  }
1909
1910
10.9k
  assert (end >= 0);
1911
10.9k
  (void) buffer->move_to (end);
1912
10.9k
}
Unexecuted instantiation: hb-ot-shaper-arabic.cc:OT::apply_lookup(OT::hb_ot_apply_context_t*, unsigned int, unsigned int, OT::LookupRecord const*, unsigned int)
Unexecuted instantiation: hb-ot-shape-fallback.cc:OT::apply_lookup(OT::hb_ot_apply_context_t*, unsigned int, unsigned int, OT::LookupRecord const*, unsigned int)
1913
1914
1915
1916
/* Contextual lookups */
1917
1918
struct ContextClosureLookupContext
1919
{
1920
  ContextClosureFuncs funcs;
1921
  ContextFormat context_format;
1922
  const void *intersects_data;
1923
  void *intersects_cache;
1924
  void *intersected_glyphs_cache;
1925
};
1926
1927
struct ContextCollectGlyphsLookupContext
1928
{
1929
  ContextCollectGlyphsFuncs funcs;
1930
  const void *collect_data;
1931
};
1932
1933
struct ContextApplyLookupContext
1934
{
1935
  ContextApplyFuncs funcs;
1936
  const void *match_data;
1937
};
1938
1939
template <typename HBUINT>
1940
static inline bool context_intersects (const hb_set_t *glyphs,
1941
               unsigned int inputCount, /* Including the first glyph (not matched) */
1942
               const HBUINT input[], /* Array of input values--start with second glyph */
1943
               ContextClosureLookupContext &lookup_context)
1944
0
{
1945
0
  return array_is_subset_of (glyphs,
1946
0
           inputCount ? inputCount - 1 : 0, input,
1947
0
           lookup_context.funcs.intersects,
1948
0
           lookup_context.intersects_data,
1949
0
           lookup_context.intersects_cache);
1950
0
}
Unexecuted instantiation: hb-aat-layout.cc:bool OT::context_intersects<OT::NumType<true, unsigned short, 2u> >(hb_set_t const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, OT::ContextClosureLookupContext&)
Unexecuted instantiation: hb-ot-face.cc:bool OT::context_intersects<OT::NumType<true, unsigned short, 2u> >(hb_set_t const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, OT::ContextClosureLookupContext&)
Unexecuted instantiation: hb-ot-layout.cc:bool OT::context_intersects<OT::NumType<true, unsigned short, 2u> >(hb_set_t const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, OT::ContextClosureLookupContext&)
Unexecuted instantiation: hb-ot-shaper-arabic.cc:bool OT::context_intersects<OT::NumType<true, unsigned short, 2u> >(hb_set_t const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, OT::ContextClosureLookupContext&)
Unexecuted instantiation: hb-ot-shape-fallback.cc:bool OT::context_intersects<OT::NumType<true, unsigned short, 2u> >(hb_set_t const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, OT::ContextClosureLookupContext&)
1951
1952
template <typename HBUINT>
1953
static inline void context_closure_lookup (hb_closure_context_t *c,
1954
             unsigned int inputCount, /* Including the first glyph (not matched) */
1955
             const HBUINT input[], /* Array of input values--start with second glyph */
1956
             unsigned int lookupCount,
1957
             const LookupRecord lookupRecord[],
1958
             unsigned value, /* Index of first glyph in Coverage or Class value in ClassDef table */
1959
             ContextClosureLookupContext &lookup_context)
1960
0
{
1961
0
  if (context_intersects (c->glyphs,
1962
0
        inputCount, input,
1963
0
        lookup_context))
1964
0
    context_closure_recurse_lookups (c,
1965
0
             inputCount, input,
1966
0
             lookupCount, lookupRecord,
1967
0
             value,
1968
0
             lookup_context.context_format,
1969
0
             lookup_context.intersects_data,
1970
0
             lookup_context.funcs.intersected_glyphs,
1971
0
             lookup_context.intersected_glyphs_cache);
1972
0
}
Unexecuted instantiation: hb-aat-layout.cc:void OT::context_closure_lookup<OT::NumType<true, unsigned short, 2u> >(OT::hb_closure_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::LookupRecord const*, unsigned int, OT::ContextClosureLookupContext&)
Unexecuted instantiation: hb-ot-face.cc:void OT::context_closure_lookup<OT::NumType<true, unsigned short, 2u> >(OT::hb_closure_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::LookupRecord const*, unsigned int, OT::ContextClosureLookupContext&)
Unexecuted instantiation: hb-ot-layout.cc:void OT::context_closure_lookup<OT::NumType<true, unsigned short, 2u> >(OT::hb_closure_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::LookupRecord const*, unsigned int, OT::ContextClosureLookupContext&)
Unexecuted instantiation: hb-ot-shaper-arabic.cc:void OT::context_closure_lookup<OT::NumType<true, unsigned short, 2u> >(OT::hb_closure_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::LookupRecord const*, unsigned int, OT::ContextClosureLookupContext&)
Unexecuted instantiation: hb-ot-shape-fallback.cc:void OT::context_closure_lookup<OT::NumType<true, unsigned short, 2u> >(OT::hb_closure_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::LookupRecord const*, unsigned int, OT::ContextClosureLookupContext&)
1973
1974
template <typename HBUINT>
1975
static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
1976
              unsigned int inputCount, /* Including the first glyph (not matched) */
1977
              const HBUINT input[], /* Array of input values--start with second glyph */
1978
              unsigned int lookupCount,
1979
              const LookupRecord lookupRecord[],
1980
              ContextCollectGlyphsLookupContext &lookup_context)
1981
0
{
1982
0
  collect_array (c, c->input,
1983
0
     inputCount ? inputCount - 1 : 0, input,
1984
0
     lookup_context.funcs.collect, lookup_context.collect_data);
1985
0
  recurse_lookups (c,
1986
0
       lookupCount, lookupRecord);
1987
0
}
Unexecuted instantiation: hb-aat-layout.cc:void OT::context_collect_glyphs_lookup<OT::NumType<true, unsigned short, 2u> >(OT::hb_collect_glyphs_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::LookupRecord const*, OT::ContextCollectGlyphsLookupContext&)
Unexecuted instantiation: hb-ot-face.cc:void OT::context_collect_glyphs_lookup<OT::NumType<true, unsigned short, 2u> >(OT::hb_collect_glyphs_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::LookupRecord const*, OT::ContextCollectGlyphsLookupContext&)
Unexecuted instantiation: hb-ot-layout.cc:void OT::context_collect_glyphs_lookup<OT::NumType<true, unsigned short, 2u> >(OT::hb_collect_glyphs_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::LookupRecord const*, OT::ContextCollectGlyphsLookupContext&)
Unexecuted instantiation: hb-ot-shaper-arabic.cc:void OT::context_collect_glyphs_lookup<OT::NumType<true, unsigned short, 2u> >(OT::hb_collect_glyphs_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::LookupRecord const*, OT::ContextCollectGlyphsLookupContext&)
Unexecuted instantiation: hb-ot-shape-fallback.cc:void OT::context_collect_glyphs_lookup<OT::NumType<true, unsigned short, 2u> >(OT::hb_collect_glyphs_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::LookupRecord const*, OT::ContextCollectGlyphsLookupContext&)
1988
1989
template <typename HBUINT>
1990
static inline bool context_would_apply_lookup (hb_would_apply_context_t *c,
1991
                 unsigned int inputCount, /* Including the first glyph (not matched) */
1992
                 const HBUINT input[], /* Array of input values--start with second glyph */
1993
                 unsigned int lookupCount HB_UNUSED,
1994
                 const LookupRecord lookupRecord[] HB_UNUSED,
1995
                 const ContextApplyLookupContext &lookup_context)
1996
0
{
1997
0
  return would_match_input (c,
1998
0
          inputCount, input,
1999
0
          lookup_context.funcs.match, lookup_context.match_data);
2000
0
}
Unexecuted instantiation: hb-aat-layout.cc:bool OT::context_would_apply_lookup<OT::NumType<true, unsigned short, 2u> >(OT::hb_would_apply_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::LookupRecord const*, OT::ContextApplyLookupContext const&)
Unexecuted instantiation: hb-ot-face.cc:bool OT::context_would_apply_lookup<OT::NumType<true, unsigned short, 2u> >(OT::hb_would_apply_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::LookupRecord const*, OT::ContextApplyLookupContext const&)
Unexecuted instantiation: hb-ot-layout.cc:bool OT::context_would_apply_lookup<OT::NumType<true, unsigned short, 2u> >(OT::hb_would_apply_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::LookupRecord const*, OT::ContextApplyLookupContext const&)
Unexecuted instantiation: hb-ot-shaper-arabic.cc:bool OT::context_would_apply_lookup<OT::NumType<true, unsigned short, 2u> >(OT::hb_would_apply_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::LookupRecord const*, OT::ContextApplyLookupContext const&)
Unexecuted instantiation: hb-ot-shape-fallback.cc:bool OT::context_would_apply_lookup<OT::NumType<true, unsigned short, 2u> >(OT::hb_would_apply_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::LookupRecord const*, OT::ContextApplyLookupContext const&)
2001
2002
template <typename HBUINT>
2003
static inline bool context_apply_lookup (hb_ot_apply_context_t *c,
2004
           unsigned int inputCount, /* Including the first glyph (not matched) */
2005
           const HBUINT input[], /* Array of input values--start with second glyph */
2006
           unsigned int lookupCount,
2007
           const LookupRecord lookupRecord[],
2008
           const ContextApplyLookupContext &lookup_context)
2009
0
{
2010
0
  if (unlikely (inputCount > HB_MAX_CONTEXT_LENGTH)) return false;
2011
2012
0
  unsigned match_end = 0;
2013
0
  bool ret = false;
2014
0
  if (match_input (c,
2015
0
       inputCount, input,
2016
0
       lookup_context.funcs.match, lookup_context.match_data,
2017
0
       &match_end))
2018
0
  {
2019
0
    c->buffer->unsafe_to_break (c->buffer->idx, match_end);
2020
0
    apply_lookup (c,
2021
0
      inputCount,
2022
0
      lookupCount, lookupRecord,
2023
0
      match_end);
2024
0
    ret = true;
2025
0
  }
2026
0
  else
2027
0
  {
2028
0
    c->buffer->unsafe_to_concat (c->buffer->idx, match_end);
2029
0
    ret = false;
2030
0
  }
2031
2032
0
  return ret;
2033
0
}
Unexecuted instantiation: hb-aat-layout.cc:bool OT::context_apply_lookup<OT::NumType<true, unsigned short, 2u> >(OT::hb_ot_apply_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::LookupRecord const*, OT::ContextApplyLookupContext const&)
Unexecuted instantiation: hb-ot-face.cc:bool OT::context_apply_lookup<OT::NumType<true, unsigned short, 2u> >(OT::hb_ot_apply_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::LookupRecord const*, OT::ContextApplyLookupContext const&)
Unexecuted instantiation: hb-ot-layout.cc:bool OT::context_apply_lookup<OT::NumType<true, unsigned short, 2u> >(OT::hb_ot_apply_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::LookupRecord const*, OT::ContextApplyLookupContext const&)
Unexecuted instantiation: hb-ot-shaper-arabic.cc:bool OT::context_apply_lookup<OT::NumType<true, unsigned short, 2u> >(OT::hb_ot_apply_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::LookupRecord const*, OT::ContextApplyLookupContext const&)
Unexecuted instantiation: hb-ot-shape-fallback.cc:bool OT::context_apply_lookup<OT::NumType<true, unsigned short, 2u> >(OT::hb_ot_apply_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::LookupRecord const*, OT::ContextApplyLookupContext const&)
2034
2035
static inline bool context_cache_func (hb_ot_apply_context_t *c, hb_ot_subtable_cache_op_t op)
2036
0
{
2037
0
  switch (op)
2038
0
  {
2039
0
    case hb_ot_subtable_cache_op_t::ENTER:
2040
0
    {
2041
0
      if (!HB_BUFFER_TRY_ALLOCATE_VAR (c->buffer, syllable))
2042
0
  return false;
2043
0
      auto &info = c->buffer->info;
2044
0
      unsigned count = c->buffer->len;
2045
0
      for (unsigned i = 0; i < count; i++)
2046
0
  info[i].syllable() = 255;
2047
0
      c->new_syllables = 255;
2048
0
      return true;
2049
0
    }
2050
0
    case hb_ot_subtable_cache_op_t::LEAVE:
2051
0
    {
2052
0
      c->new_syllables = (unsigned) -1;
2053
0
      HB_BUFFER_DEALLOCATE_VAR (c->buffer, syllable);
2054
0
      break;
2055
0
    }
2056
0
  }
2057
0
  return false;
2058
0
}
Unexecuted instantiation: hb-aat-layout.cc:OT::context_cache_func(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t)
Unexecuted instantiation: hb-ot-face.cc:OT::context_cache_func(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t)
Unexecuted instantiation: hb-ot-layout.cc:OT::context_cache_func(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t)
Unexecuted instantiation: hb-ot-shaper-arabic.cc:OT::context_cache_func(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t)
Unexecuted instantiation: hb-ot-shape-fallback.cc:OT::context_cache_func(OT::hb_ot_apply_context_t*, OT::hb_ot_subtable_cache_op_t)
2059
2060
template <typename Types>
2061
struct Rule
2062
{
2063
  template <typename T>
2064
  friend struct RuleSet;
2065
2066
  bool intersects (const hb_set_t *glyphs, ContextClosureLookupContext &lookup_context) const
2067
0
  {
2068
0
    return context_intersects (glyphs,
2069
0
             inputCount, inputZ.arrayZ,
2070
0
             lookup_context);
2071
0
  }
2072
2073
  void closure (hb_closure_context_t *c, unsigned value, ContextClosureLookupContext &lookup_context) const
2074
0
  {
2075
0
    if (unlikely (c->lookup_limit_exceeded ())) return;
2076
2077
0
    const auto &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
2078
0
             (inputZ.as_array ((inputCount ? inputCount - 1 : 0)));
2079
0
    context_closure_lookup (c,
2080
0
          inputCount, inputZ.arrayZ,
2081
0
          lookupCount, lookupRecord.arrayZ,
2082
0
          value, lookup_context);
2083
0
  }
2084
2085
  void closure_lookups (hb_closure_lookups_context_t *c,
2086
                        ContextClosureLookupContext &lookup_context) const
2087
0
  {
2088
0
    if (unlikely (c->lookup_limit_exceeded ())) return;
2089
0
    if (!intersects (c->glyphs, lookup_context)) return;
2090
0
2091
0
    const auto &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
2092
0
             (inputZ.as_array (inputCount ? inputCount - 1 : 0));
2093
0
    recurse_lookups (c, lookupCount, lookupRecord.arrayZ);
2094
0
  }
2095
2096
  void collect_glyphs (hb_collect_glyphs_context_t *c,
2097
           ContextCollectGlyphsLookupContext &lookup_context) const
2098
0
  {
2099
0
    const auto &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
2100
0
             (inputZ.as_array (inputCount ? inputCount - 1 : 0));
2101
0
    context_collect_glyphs_lookup (c,
2102
0
           inputCount, inputZ.arrayZ,
2103
0
           lookupCount, lookupRecord.arrayZ,
2104
0
           lookup_context);
2105
0
  }
2106
2107
  bool would_apply (hb_would_apply_context_t *c,
2108
        const ContextApplyLookupContext &lookup_context) const
2109
0
  {
2110
0
    const auto &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
2111
0
             (inputZ.as_array (inputCount ? inputCount - 1 : 0));
2112
0
    return context_would_apply_lookup (c,
2113
0
               inputCount, inputZ.arrayZ,
2114
0
               lookupCount, lookupRecord.arrayZ,
2115
0
               lookup_context);
2116
0
  }
2117
2118
  bool apply (hb_ot_apply_context_t *c,
2119
        const ContextApplyLookupContext &lookup_context) const
2120
0
  {
2121
0
    TRACE_APPLY (this);
2122
0
    const auto &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
2123
0
             (inputZ.as_array (inputCount ? inputCount - 1 : 0));
2124
0
    return_trace (context_apply_lookup (c, inputCount, inputZ.arrayZ, lookupCount, lookupRecord.arrayZ, lookup_context));
2125
0
  }
2126
2127
  bool serialize (hb_serialize_context_t *c,
2128
      const hb_map_t *input_mapping, /* old->new glyphid or class mapping */
2129
      const hb_map_t *lookup_map) const
2130
0
  {
2131
0
    TRACE_SERIALIZE (this);
2132
0
    auto *out = c->start_embed (this);
2133
0
    if (unlikely (!c->extend_min (out))) return_trace (false);
2134
0
2135
0
    out->inputCount = inputCount;
2136
0
    const auto input = inputZ.as_array (inputCount - 1);
2137
0
    for (const auto org : input)
2138
0
    {
2139
0
      HBUINT16 d;
2140
0
      d = input_mapping->get (org);
2141
0
      c->copy (d);
2142
0
    }
2143
0
2144
0
    const auto &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
2145
0
             (inputZ.as_array ((inputCount ? inputCount - 1 : 0)));
2146
0
2147
0
    unsigned count = serialize_lookuprecord_array (c, lookupRecord.as_array (lookupCount), lookup_map);
2148
0
    return_trace (c->check_assign (out->lookupCount, count, HB_SERIALIZE_ERROR_INT_OVERFLOW));
2149
0
  }
2150
2151
  bool subset (hb_subset_context_t *c,
2152
         const hb_map_t *lookup_map,
2153
         const hb_map_t *klass_map = nullptr) const
2154
0
  {
2155
0
    TRACE_SUBSET (this);
2156
0
    if (unlikely (!inputCount)) return_trace (false);
2157
0
    const auto input = inputZ.as_array (inputCount - 1);
2158
0
2159
0
    const hb_map_t *mapping = klass_map == nullptr ? c->plan->glyph_map : klass_map;
2160
0
    if (!hb_all (input, mapping)) return_trace (false);
2161
0
    return_trace (serialize (c->serializer, mapping, lookup_map));
2162
0
  }
2163
2164
  public:
2165
  bool sanitize (hb_sanitize_context_t *c) const
2166
0
  {
2167
0
    TRACE_SANITIZE (this);
2168
0
    return_trace (c->check_struct (this) &&
2169
0
      hb_barrier () &&
2170
0
      c->check_range (inputZ.arrayZ,
2171
0
          inputZ.item_size * (inputCount ? inputCount - 1 : 0) +
2172
0
          LookupRecord::static_size * lookupCount));
2173
0
  }
2174
2175
  protected:
2176
  HBUINT16  inputCount;   /* Total number of glyphs in input
2177
           * glyph sequence--includes the first
2178
           * glyph */
2179
  HBUINT16  lookupCount;    /* Number of LookupRecords */
2180
  UnsizedArrayOf<typename Types::HBUINT>
2181
    inputZ;     /* Array of match inputs--start with
2182
           * second glyph */
2183
/*UnsizedArrayOf<LookupRecord>
2184
    lookupRecordX;*/  /* Array of LookupRecords--in
2185
           * design order */
2186
  public:
2187
  DEFINE_SIZE_ARRAY (4, inputZ);
2188
};
2189
2190
template <typename Types>
2191
struct RuleSet
2192
{
2193
  using Rule = OT::Rule<Types>;
2194
2195
  bool intersects (const hb_set_t *glyphs,
2196
       ContextClosureLookupContext &lookup_context) const
2197
0
  {
2198
0
    return
2199
0
    + hb_iter (rule)
2200
0
    | hb_map (hb_add (this))
2201
0
    | hb_map ([&] (const Rule &_) { return _.intersects (glyphs, lookup_context); })
2202
0
    | hb_any
2203
0
    ;
2204
0
  }
2205
2206
  void closure (hb_closure_context_t *c, unsigned value,
2207
    ContextClosureLookupContext &lookup_context) const
2208
0
  {
2209
0
    if (unlikely (c->lookup_limit_exceeded ())) return;
2210
2211
0
    return
2212
0
    + hb_iter (rule)
2213
0
    | hb_map (hb_add (this))
2214
0
    | hb_apply ([&] (const Rule &_) { _.closure (c, value, lookup_context); })
2215
0
    ;
2216
0
  }
2217
2218
  void closure_lookups (hb_closure_lookups_context_t *c,
2219
                        ContextClosureLookupContext &lookup_context) const
2220
0
  {
2221
0
    if (unlikely (c->lookup_limit_exceeded ())) return;
2222
0
    + hb_iter (rule)
2223
0
    | hb_map (hb_add (this))
2224
0
    | hb_apply ([&] (const Rule &_) { _.closure_lookups (c, lookup_context); })
2225
0
    ;
2226
0
  }
2227
2228
  void collect_glyphs (hb_collect_glyphs_context_t *c,
2229
           ContextCollectGlyphsLookupContext &lookup_context) const
2230
0
  {
2231
0
    return
2232
0
    + hb_iter (rule)
2233
0
    | hb_map (hb_add (this))
2234
0
    | hb_apply ([&] (const Rule &_) { _.collect_glyphs (c, lookup_context); })
2235
0
    ;
2236
0
  }
2237
2238
  bool would_apply (hb_would_apply_context_t *c,
2239
        const ContextApplyLookupContext &lookup_context) const
2240
0
  {
2241
0
    return
2242
0
    + hb_iter (rule)
2243
0
    | hb_map (hb_add (this))
2244
0
    | hb_map ([&] (const Rule &_) { return _.would_apply (c, lookup_context); })
2245
0
    | hb_any
2246
0
    ;
2247
0
  }
2248
2249
  bool apply (hb_ot_apply_context_t *c,
2250
        const ContextApplyLookupContext &lookup_context) const
2251
0
  {
2252
0
    TRACE_APPLY (this);
2253
2254
0
    unsigned num_rules = rule.len;
2255
2256
0
#ifndef HB_NO_OT_RULESETS_FAST_PATH
2257
0
    if (HB_OPTIMIZE_SIZE_VAL || num_rules <= 4)
2258
0
#endif
2259
0
    {
2260
0
    slow:
2261
0
      return_trace (
2262
0
      + hb_iter (rule)
2263
0
      | hb_map (hb_add (this))
2264
0
      | hb_map ([&] (const Rule &_) { return _.apply (c, lookup_context); })
2265
0
      | hb_any
2266
0
      )
2267
0
      ;
2268
0
    }
2269
2270
    /* This version is optimized for speed by matching the first & second
2271
     * components of the rule here, instead of calling into the matching code.
2272
     *
2273
     * Replicated from LigatureSet::apply(). */
2274
2275
    /* We use the iter_context instead of iter_input, to avoid skipping
2276
     * default-ignorables and such.
2277
     *
2278
     * Related: https://github.com/harfbuzz/harfbuzz/issues/4813
2279
     */
2280
0
    auto &skippy_iter = c->iter_context;
2281
0
    skippy_iter.reset (c->buffer->idx);
2282
0
    skippy_iter.set_match_func (match_always, nullptr);
2283
0
    skippy_iter.set_glyph_data ((HBUINT16 *) nullptr);
2284
0
    unsigned unsafe_to = (unsigned) -1, unsafe_to1, unsafe_to2 = 0;
2285
0
    hb_glyph_info_t *first = nullptr, *second = nullptr;
2286
0
    bool matched = skippy_iter.next ();
2287
0
    if (likely (matched))
2288
0
    {
2289
0
      if (skippy_iter.may_skip (c->buffer->info[skippy_iter.idx]))
2290
0
      {
2291
  /* Can't use the fast path if eg. the next char is a default-ignorable
2292
   * or other skippable. */
2293
0
        goto slow;
2294
0
      }
2295
2296
0
      first = &c->buffer->info[skippy_iter.idx];
2297
0
      unsafe_to1 = skippy_iter.idx + 1;
2298
0
    }
2299
0
    else
2300
0
    {
2301
      /* Failed to match a next glyph. Only try applying rules that have
2302
       * no further input. */
2303
0
      return_trace (
2304
0
      + hb_iter (rule)
2305
0
      | hb_map (hb_add (this))
2306
0
      | hb_filter ([&] (const Rule &_) { return _.inputCount <= 1; })
2307
0
      | hb_map ([&] (const Rule &_) { return _.apply (c, lookup_context); })
2308
0
      | hb_any
2309
0
      )
2310
0
      ;
2311
0
    }
2312
0
    matched = skippy_iter.next ();
2313
0
    if (likely (matched))
2314
0
    {
2315
0
      if (skippy_iter.may_skip (c->buffer->info[skippy_iter.idx]))
2316
0
      {
2317
  /* Can't use the fast path if eg. the next char is a default-ignorable
2318
   * or other skippable. */
2319
0
        goto slow;
2320
0
      }
2321
2322
0
      second = &c->buffer->info[skippy_iter.idx];
2323
0
      unsafe_to2 = skippy_iter.idx + 1;
2324
0
    }
2325
2326
0
    auto match_input = lookup_context.funcs.match;
2327
0
    auto *input_data = lookup_context.match_data;
2328
0
    for (unsigned int i = 0; i < num_rules; i++)
2329
0
    {
2330
0
      const auto &r = this+rule.arrayZ[i];
2331
2332
0
      const auto &input = r.inputZ;
2333
2334
0
      if (r.inputCount <= 1 ||
2335
0
    (!match_input ||
2336
0
     match_input (*first, input.arrayZ[0], input_data)))
2337
0
      {
2338
0
        if (!second ||
2339
0
      (r.inputCount <= 2 ||
2340
0
       (!match_input ||
2341
0
        match_input (*second, input.arrayZ[1], input_data)))
2342
0
     )
2343
0
  {
2344
0
    if (r.apply (c, lookup_context))
2345
0
    {
2346
0
      if (unsafe_to != (unsigned) -1)
2347
0
        c->buffer->unsafe_to_concat (c->buffer->idx, unsafe_to);
2348
0
      return_trace (true);
2349
0
    }
2350
0
  }
2351
0
  else
2352
0
    unsafe_to = unsafe_to2;
2353
0
      }
2354
0
      else
2355
0
      {
2356
0
  if (unsafe_to == (unsigned) -1)
2357
0
    unsafe_to = unsafe_to1;
2358
2359
  // Skip ahead to next possible first glyph match.
2360
0
  for (; i + 1 < num_rules; i++)
2361
0
  {
2362
0
    const auto &r2 = this+rule.arrayZ[i + 1];
2363
0
    const auto &input2 = r2.inputZ;
2364
0
    if (r2.inputCount <= 1 || input2.arrayZ[0] != input.arrayZ[0])
2365
0
      break;
2366
0
  }
2367
0
      }
2368
0
    }
2369
0
    if (likely (unsafe_to != (unsigned) -1))
2370
0
      c->buffer->unsafe_to_concat (c->buffer->idx, unsafe_to);
2371
2372
0
    return_trace (false);
2373
0
  }
2374
2375
  bool subset (hb_subset_context_t *c,
2376
         const hb_map_t *lookup_map,
2377
         const hb_map_t *klass_map = nullptr) const
2378
0
  {
2379
0
    TRACE_SUBSET (this);
2380
0
2381
0
    auto snap = c->serializer->snapshot ();
2382
0
    auto *out = c->serializer->start_embed (*this);
2383
0
    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
2384
0
2385
0
    for (const Offset16To<Rule>& _ : rule)
2386
0
    {
2387
0
      if (!_) continue;
2388
0
      auto o_snap = c->serializer->snapshot ();
2389
0
      auto *o = out->rule.serialize_append (c->serializer);
2390
0
      if (unlikely (!o)) continue;
2391
0
2392
0
      if (!o->serialize_subset (c, _, this, lookup_map, klass_map))
2393
0
      {
2394
0
  out->rule.pop ();
2395
0
  c->serializer->revert (o_snap);
2396
0
      }
2397
0
    }
2398
0
2399
0
    bool ret = bool (out->rule);
2400
0
    if (!ret) c->serializer->revert (snap);
2401
0
2402
0
    return_trace (ret);
2403
0
  }
2404
2405
  bool sanitize (hb_sanitize_context_t *c) const
2406
0
  {
2407
0
    TRACE_SANITIZE (this);
2408
0
    return_trace (rule.sanitize (c, this));
2409
0
  }
2410
2411
  protected:
2412
  Array16OfOffset16To<Rule>
2413
    rule;     /* Array of Rule tables
2414
           * ordered by preference */
2415
  public:
2416
  DEFINE_SIZE_ARRAY (2, rule);
2417
};
2418
2419
2420
template <typename Types>
2421
struct ContextFormat1_4
2422
{
2423
  using RuleSet = OT::RuleSet<Types>;
2424
2425
  bool intersects (const hb_set_t *glyphs) const
2426
0
  {
2427
0
    struct ContextClosureLookupContext lookup_context = {
2428
0
      {intersects_glyph, intersected_glyph},
2429
0
      ContextFormat::SimpleContext,
2430
0
      nullptr
2431
0
    };
2432
0
2433
0
    return
2434
0
    + hb_zip (this+coverage, ruleSet)
2435
0
    | hb_filter (*glyphs, hb_first)
2436
0
    | hb_map (hb_second)
2437
0
    | hb_map (hb_add (this))
2438
0
    | hb_map ([&] (const RuleSet &_) { return _.intersects (glyphs, lookup_context); })
2439
0
    | hb_any
2440
0
    ;
2441
0
  }
2442
2443
  bool may_have_non_1to1 () const
2444
0
  { return true; }
2445
2446
  void closure (hb_closure_context_t *c) const
2447
0
  {
2448
0
    hb_set_t* cur_active_glyphs = c->push_cur_active_glyphs ();
2449
0
    if (unlikely (!cur_active_glyphs)) return;
2450
0
    get_coverage ().intersect_set (c->previous_parent_active_glyphs (), *cur_active_glyphs);
2451
2452
0
    struct ContextClosureLookupContext lookup_context = {
2453
0
      {intersects_glyph, intersected_glyph},
2454
0
      ContextFormat::SimpleContext,
2455
0
      nullptr
2456
0
    };
2457
2458
0
    + hb_zip (this+coverage, hb_range ((unsigned) ruleSet.len))
2459
0
    | hb_filter ([&] (hb_codepoint_t _) {
2460
0
      return c->previous_parent_active_glyphs ().has (_);
2461
0
    }, hb_first)
2462
0
    | hb_map ([&](const hb_pair_t<hb_codepoint_t, unsigned> _) { return hb_pair_t<unsigned, const RuleSet&> (_.first, this+ruleSet[_.second]); })
2463
0
    | hb_apply ([&] (const hb_pair_t<unsigned, const RuleSet&>& _) { _.second.closure (c, _.first, lookup_context); })
2464
0
    ;
2465
2466
0
    c->pop_cur_done_glyphs ();
2467
0
  }
2468
2469
  void closure_lookups (hb_closure_lookups_context_t *c) const
2470
0
  {
2471
0
    struct ContextClosureLookupContext lookup_context = {
2472
0
      {intersects_glyph, nullptr},
2473
0
      ContextFormat::SimpleContext,
2474
0
      nullptr
2475
0
    };
2476
0
2477
0
    + hb_zip (this+coverage, ruleSet)
2478
0
    | hb_filter (*c->glyphs, hb_first)
2479
0
    | hb_map (hb_second)
2480
0
    | hb_map (hb_add (this))
2481
0
    | hb_apply ([&] (const RuleSet &_) { _.closure_lookups (c, lookup_context); })
2482
0
    ;
2483
0
  }
2484
2485
0
  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
2486
2487
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
2488
0
  {
2489
0
    (this+coverage).collect_coverage (c->input);
2490
2491
0
    struct ContextCollectGlyphsLookupContext lookup_context = {
2492
0
      {collect_glyph},
2493
0
      nullptr
2494
0
    };
2495
2496
0
    + hb_iter (ruleSet)
2497
0
    | hb_map (hb_add (this))
2498
0
    | hb_apply ([&] (const RuleSet &_) { _.collect_glyphs (c, lookup_context); })
2499
0
    ;
2500
0
  }
2501
2502
  bool would_apply (hb_would_apply_context_t *c) const
2503
0
  {
2504
0
    const RuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
2505
0
    struct ContextApplyLookupContext lookup_context = {
2506
0
      {match_glyph},
2507
0
      nullptr
2508
0
    };
2509
0
    return rule_set.would_apply (c, lookup_context);
2510
0
  }
2511
2512
0
  const Coverage &get_coverage () const { return this+coverage; }
2513
2514
  bool apply (hb_ot_apply_context_t *c) const
2515
0
  {
2516
0
    TRACE_APPLY (this);
2517
0
    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
2518
0
    if (likely (index == NOT_COVERED))
2519
0
      return_trace (false);
2520
2521
0
    const RuleSet &rule_set = this+ruleSet[index];
2522
0
    struct ContextApplyLookupContext lookup_context = {
2523
0
      {match_glyph},
2524
0
      nullptr
2525
0
    };
2526
0
    return_trace (rule_set.apply (c, lookup_context));
2527
0
  }
2528
2529
  bool subset (hb_subset_context_t *c) const
2530
0
  {
2531
0
    TRACE_SUBSET (this);
2532
0
    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
2533
0
    const hb_map_t &glyph_map = *c->plan->glyph_map;
2534
0
2535
0
    auto *out = c->serializer->start_embed (*this);
2536
0
    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
2537
0
    out->format = format;
2538
0
2539
0
    const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? &c->plan->gsub_lookups : &c->plan->gpos_lookups;
2540
0
    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
2541
0
    + hb_zip (this+coverage, ruleSet)
2542
0
    | hb_filter (glyphset, hb_first)
2543
0
    | hb_filter (subset_offset_array (c, out->ruleSet, this, lookup_map), hb_second)
2544
0
    | hb_map (hb_first)
2545
0
    | hb_map (glyph_map)
2546
0
    | hb_sink (new_coverage)
2547
0
    ;
2548
0
2549
0
    out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
2550
0
    return_trace (bool (new_coverage));
2551
0
  }
2552
2553
  bool sanitize (hb_sanitize_context_t *c) const
2554
0
  {
2555
0
    TRACE_SANITIZE (this);
2556
0
    return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
2557
0
  }
2558
2559
  protected:
2560
  HBUINT16  format;     /* Format identifier--format = 1 */
2561
  typename Types::template OffsetTo<Coverage>
2562
    coverage;   /* Offset to Coverage table--from
2563
           * beginning of table */
2564
  Array16Of<typename Types::template OffsetTo<RuleSet>>
2565
    ruleSet;    /* Array of RuleSet tables
2566
           * ordered by Coverage Index */
2567
  public:
2568
  DEFINE_SIZE_ARRAY (2 + 2 * Types::size, ruleSet);
2569
};
2570
2571
2572
template <typename Types>
2573
struct ContextFormat2_5
2574
{
2575
  using RuleSet = OT::RuleSet<SmallTypes>;
2576
2577
  bool intersects (const hb_set_t *glyphs) const
2578
0
  {
2579
0
    if (!(this+coverage).intersects (glyphs))
2580
0
      return false;
2581
0
2582
0
    const ClassDef &class_def = this+classDef;
2583
0
2584
0
    hb_map_t cache;
2585
0
    struct ContextClosureLookupContext lookup_context = {
2586
0
      {intersects_class, nullptr},
2587
0
      ContextFormat::ClassBasedContext,
2588
0
      &class_def,
2589
0
      &cache
2590
0
    };
2591
0
2592
0
    hb_set_t retained_coverage_glyphs;
2593
0
    (this+coverage).intersect_set (*glyphs, retained_coverage_glyphs);
2594
0
2595
0
    hb_set_t coverage_glyph_classes;
2596
0
    class_def.intersected_classes (&retained_coverage_glyphs, &coverage_glyph_classes);
2597
0
2598
0
2599
0
    return
2600
0
    + hb_iter (ruleSet)
2601
0
    | hb_map (hb_add (this))
2602
0
    | hb_enumerate
2603
0
    | hb_map ([&] (const hb_pair_t<unsigned, const RuleSet &> p)
2604
0
        { return class_def.intersects_class (glyphs, p.first) &&
2605
0
           coverage_glyph_classes.has (p.first) &&
2606
0
           p.second.intersects (glyphs, lookup_context); })
2607
0
    | hb_any
2608
0
    ;
2609
0
  }
2610
2611
  bool may_have_non_1to1 () const
2612
0
  { return true; }
2613
2614
  void closure (hb_closure_context_t *c) const
2615
0
  {
2616
0
    if (!(this+coverage).intersects (c->glyphs))
2617
0
      return;
2618
2619
0
    hb_set_t* cur_active_glyphs = c->push_cur_active_glyphs ();
2620
0
    if (unlikely (!cur_active_glyphs)) return;
2621
0
    get_coverage ().intersect_set (c->previous_parent_active_glyphs (),
2622
0
           *cur_active_glyphs);
2623
2624
0
    const ClassDef &class_def = this+classDef;
2625
2626
0
    hb_map_t cache;
2627
0
    intersected_class_cache_t intersected_cache;
2628
0
    struct ContextClosureLookupContext lookup_context = {
2629
0
      {intersects_class, intersected_class_glyphs},
2630
0
      ContextFormat::ClassBasedContext,
2631
0
      &class_def,
2632
0
      &cache,
2633
0
      &intersected_cache
2634
0
    };
2635
2636
0
    + hb_enumerate (ruleSet)
2637
0
    | hb_filter ([&] (unsigned _)
2638
0
    { return class_def.intersects_class (&c->parent_active_glyphs (), _); },
2639
0
     hb_first)
2640
0
    | hb_apply ([&] (const hb_pair_t<unsigned, const typename Types::template OffsetTo<RuleSet>&> _)
2641
0
                {
2642
0
                  const RuleSet& rule_set = this+_.second;
2643
0
                  rule_set.closure (c, _.first, lookup_context);
2644
0
                })
2645
0
    ;
2646
2647
0
    c->pop_cur_done_glyphs ();
2648
0
  }
2649
2650
  void closure_lookups (hb_closure_lookups_context_t *c) const
2651
0
  {
2652
0
    if (!(this+coverage).intersects (c->glyphs))
2653
0
      return;
2654
0
2655
0
    const ClassDef &class_def = this+classDef;
2656
0
2657
0
    hb_map_t cache;
2658
0
    struct ContextClosureLookupContext lookup_context = {
2659
0
      {intersects_class, nullptr},
2660
0
      ContextFormat::ClassBasedContext,
2661
0
      &class_def,
2662
0
      &cache
2663
0
    };
2664
0
2665
0
    + hb_iter (ruleSet)
2666
0
    | hb_map (hb_add (this))
2667
0
    | hb_enumerate
2668
0
    | hb_filter ([&] (const hb_pair_t<unsigned, const RuleSet &> p)
2669
0
    { return class_def.intersects_class (c->glyphs, p.first); })
2670
0
    | hb_map (hb_second)
2671
0
    | hb_apply ([&] (const RuleSet & _)
2672
0
    { _.closure_lookups (c, lookup_context); });
2673
0
  }
2674
2675
0
  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
2676
2677
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
2678
0
  {
2679
0
    (this+coverage).collect_coverage (c->input);
2680
2681
0
    const ClassDef &class_def = this+classDef;
2682
0
    struct ContextCollectGlyphsLookupContext lookup_context = {
2683
0
      {collect_class},
2684
0
      &class_def
2685
0
    };
2686
2687
0
    + hb_iter (ruleSet)
2688
0
    | hb_map (hb_add (this))
2689
0
    | hb_apply ([&] (const RuleSet &_) { _.collect_glyphs (c, lookup_context); })
2690
0
    ;
2691
0
  }
2692
2693
  bool would_apply (hb_would_apply_context_t *c) const
2694
0
  {
2695
0
    const ClassDef &class_def = this+classDef;
2696
0
    unsigned int index = class_def.get_class (c->glyphs[0]);
2697
0
    const RuleSet &rule_set = this+ruleSet[index];
2698
0
    struct ContextApplyLookupContext lookup_context = {
2699
0
      {match_class},
2700
0
      &class_def
2701
0
    };
2702
0
    return rule_set.would_apply (c, lookup_context);
2703
0
  }
2704
2705
0
  const Coverage &get_coverage () const { return this+coverage; }
2706
2707
  unsigned cache_cost () const
2708
0
  {
2709
0
    return (this+classDef).cost ();
2710
0
  }
2711
  static bool cache_func (hb_ot_apply_context_t *c, hb_ot_subtable_cache_op_t op)
2712
0
  {
2713
0
    return context_cache_func (c, op);
2714
0
  }
2715
2716
  struct external_cache_t
2717
  {
2718
    hb_ot_layout_binary_cache_t coverage;
2719
  };
2720
  void *external_cache_create () const
2721
0
  {
2722
0
    external_cache_t *cache = (external_cache_t *) hb_malloc (sizeof (external_cache_t));
2723
0
    if (likely (cache))
2724
0
    {
2725
0
      cache->coverage.clear ();
2726
0
    }
2727
0
    return cache;
2728
0
  }
2729
0
  bool apply_cached (hb_ot_apply_context_t *c, void *external_cache) const { return _apply (c, true, external_cache); }
2730
0
  bool apply (hb_ot_apply_context_t *c, void *external_cache) const { return _apply (c, false, external_cache); }
2731
  bool _apply (hb_ot_apply_context_t *c, bool cached, void *external_cache) const
2732
0
  {
2733
0
    TRACE_APPLY (this);
2734
0
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
2735
0
    external_cache_t *cache = (external_cache_t *) external_cache;
2736
0
    unsigned int index = (this+coverage).get_coverage_binary (c->buffer->cur().codepoint, cache ? &cache->coverage : nullptr);
2737
#else
2738
    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
2739
#endif
2740
0
    if (index == NOT_COVERED) return_trace (false);
2741
2742
0
    const ClassDef &class_def = this+classDef;
2743
2744
0
    struct ContextApplyLookupContext lookup_context = {
2745
0
      {cached ? match_class_cached : match_class},
2746
0
      &class_def
2747
0
    };
2748
2749
0
    index = cached ? get_class_cached (class_def, c->buffer->cur()) : class_def.get_class (c->buffer->cur().codepoint);
2750
0
    const RuleSet &rule_set = this+ruleSet[index];
2751
0
    return_trace (rule_set.apply (c, lookup_context));
2752
0
  }
2753
2754
  bool subset (hb_subset_context_t *c) const
2755
0
  {
2756
0
    TRACE_SUBSET (this);
2757
0
    auto *out = c->serializer->start_embed (*this);
2758
0
    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
2759
0
    out->format = format;
2760
0
    if (unlikely (!out->coverage.serialize_subset (c, coverage, this)))
2761
0
      return_trace (false);
2762
0
2763
0
    hb_map_t klass_map;
2764
0
    out->classDef.serialize_subset (c, classDef, this, &klass_map);
2765
0
2766
0
    const hb_set_t* glyphset = c->plan->glyphset_gsub ();
2767
0
    hb_set_t retained_coverage_glyphs;
2768
0
    (this+coverage).intersect_set (*glyphset, retained_coverage_glyphs);
2769
0
2770
0
    hb_set_t coverage_glyph_classes;
2771
0
    (this+classDef).intersected_classes (&retained_coverage_glyphs, &coverage_glyph_classes);
2772
0
2773
0
    const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? &c->plan->gsub_lookups : &c->plan->gpos_lookups;
2774
0
    bool ret = true;
2775
0
    int non_zero_index = -1, index = 0;
2776
0
    auto snapshot = c->serializer->snapshot();
2777
0
    for (const auto& _ : + hb_enumerate (ruleSet)
2778
0
       | hb_filter (klass_map, hb_first))
2779
0
    {
2780
0
      auto *o = out->ruleSet.serialize_append (c->serializer);
2781
0
      if (unlikely (!o))
2782
0
      {
2783
0
  ret = false;
2784
0
  break;
2785
0
      }
2786
0
2787
0
      if (coverage_glyph_classes.has (_.first) &&
2788
0
    o->serialize_subset (c, _.second, this, lookup_map, &klass_map)) {
2789
0
  non_zero_index = index;
2790
0
        snapshot = c->serializer->snapshot();
2791
0
      }
2792
0
2793
0
      index++;
2794
0
    }
2795
0
2796
0
    if (!ret || non_zero_index == -1) return_trace (false);
2797
0
2798
0
    //prune empty trailing ruleSets
2799
0
    --index;
2800
0
    while (index > non_zero_index)
2801
0
    {
2802
0
      out->ruleSet.pop ();
2803
0
      index--;
2804
0
    }
2805
0
    c->serializer->revert (snapshot);
2806
0
2807
0
    return_trace (bool (out->ruleSet));
2808
0
  }
2809
2810
  bool sanitize (hb_sanitize_context_t *c) const
2811
0
  {
2812
0
    TRACE_SANITIZE (this);
2813
0
    return_trace (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this));
2814
0
  }
2815
2816
  protected:
2817
  HBUINT16  format;     /* Format identifier--format = 2 */
2818
  typename Types::template OffsetTo<Coverage>
2819
    coverage;   /* Offset to Coverage table--from
2820
           * beginning of table */
2821
  typename Types::template OffsetTo<ClassDef>
2822
    classDef;   /* Offset to glyph ClassDef table--from
2823
           * beginning of table */
2824
  Array16Of<typename Types::template OffsetTo<RuleSet>>
2825
    ruleSet;    /* Array of RuleSet tables
2826
           * ordered by class */
2827
  public:
2828
  DEFINE_SIZE_ARRAY (4 + 2 * Types::size, ruleSet);
2829
};
2830
2831
2832
struct ContextFormat3
2833
{
2834
  using RuleSet = OT::RuleSet<SmallTypes>;
2835
2836
  bool intersects (const hb_set_t *glyphs) const
2837
0
  {
2838
0
    if (!(this+coverageZ[0]).intersects (glyphs))
2839
0
      return false;
2840
0
2841
0
    struct ContextClosureLookupContext lookup_context = {
2842
0
      {intersects_coverage, nullptr},
2843
0
      ContextFormat::CoverageBasedContext,
2844
0
      this
2845
0
    };
2846
0
    return context_intersects (glyphs,
2847
0
             glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
2848
0
             lookup_context);
2849
0
  }
2850
2851
  bool may_have_non_1to1 () const
2852
0
  { return true; }
2853
2854
  void closure (hb_closure_context_t *c) const
2855
0
  {
2856
0
    if (!(this+coverageZ[0]).intersects (c->glyphs))
2857
0
      return;
2858
2859
0
    hb_set_t* cur_active_glyphs = c->push_cur_active_glyphs ();
2860
0
    if (unlikely (!cur_active_glyphs)) return;
2861
0
    get_coverage ().intersect_set (c->previous_parent_active_glyphs (),
2862
0
           *cur_active_glyphs);
2863
2864
0
    const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
2865
0
    struct ContextClosureLookupContext lookup_context = {
2866
0
      {intersects_coverage, intersected_coverage_glyphs},
2867
0
      ContextFormat::CoverageBasedContext,
2868
0
      this
2869
0
    };
2870
0
    context_closure_lookup (c,
2871
0
          glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
2872
0
          lookupCount, lookupRecord,
2873
0
          0, lookup_context);
2874
2875
0
    c->pop_cur_done_glyphs ();
2876
0
  }
2877
2878
  void closure_lookups (hb_closure_lookups_context_t *c) const
2879
0
  {
2880
0
    if (!intersects (c->glyphs))
2881
0
      return;
2882
0
    const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
2883
0
    recurse_lookups (c, lookupCount, lookupRecord);
2884
0
  }
2885
2886
0
  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
2887
2888
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
2889
0
  {
2890
0
    (this+coverageZ[0]).collect_coverage (c->input);
2891
2892
0
    const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
2893
0
    struct ContextCollectGlyphsLookupContext lookup_context = {
2894
0
      {collect_coverage},
2895
0
      this
2896
0
    };
2897
2898
0
    context_collect_glyphs_lookup (c,
2899
0
           glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
2900
0
           lookupCount, lookupRecord,
2901
0
           lookup_context);
2902
0
  }
2903
2904
  bool would_apply (hb_would_apply_context_t *c) const
2905
0
  {
2906
0
    const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
2907
0
    struct ContextApplyLookupContext lookup_context = {
2908
0
      {match_coverage},
2909
0
      this
2910
0
    };
2911
0
    return context_would_apply_lookup (c,
2912
0
               glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
2913
0
               lookupCount, lookupRecord,
2914
0
               lookup_context);
2915
0
  }
2916
2917
0
  const Coverage &get_coverage () const { return this+coverageZ[0]; }
2918
2919
  bool apply (hb_ot_apply_context_t *c) const
2920
0
  {
2921
0
    TRACE_APPLY (this);
2922
0
    unsigned int index = (this+coverageZ[0]).get_coverage (c->buffer->cur().codepoint);
2923
0
    if (index == NOT_COVERED) return_trace (false);
2924
2925
0
    const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
2926
0
    struct ContextApplyLookupContext lookup_context = {
2927
0
      {match_coverage},
2928
0
      this
2929
0
    };
2930
0
    return_trace (context_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), lookupCount, lookupRecord, lookup_context));
2931
0
  }
2932
2933
  bool subset (hb_subset_context_t *c) const
2934
0
  {
2935
0
    TRACE_SUBSET (this);
2936
0
    auto *out = c->serializer->start_embed (this);
2937
0
    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
2938
0
2939
0
    out->format = format;
2940
0
    out->glyphCount = glyphCount;
2941
0
2942
0
    auto coverages = coverageZ.as_array (glyphCount);
2943
0
2944
0
    for (const Offset16To<Coverage>& offset : coverages)
2945
0
    {
2946
0
      /* TODO(subset) This looks like should not be necessary to write this way. */
2947
0
      auto *o = c->serializer->allocate_size<Offset16To<Coverage>> (Offset16To<Coverage>::static_size);
2948
0
      if (unlikely (!o)) return_trace (false);
2949
0
      if (!o->serialize_subset (c, offset, this)) return_trace (false);
2950
0
    }
2951
0
2952
0
    const auto& lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>> (coverageZ.as_array (glyphCount));
2953
0
    const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? &c->plan->gsub_lookups : &c->plan->gpos_lookups;
2954
0
2955
0
2956
0
    unsigned count = serialize_lookuprecord_array (c->serializer, lookupRecord.as_array (lookupCount), lookup_map);
2957
0
    return_trace (c->serializer->check_assign (out->lookupCount, count, HB_SERIALIZE_ERROR_INT_OVERFLOW));
2958
0
  }
2959
2960
  bool sanitize (hb_sanitize_context_t *c) const
2961
0
  {
2962
0
    TRACE_SANITIZE (this);
2963
0
    if (unlikely (!c->check_struct (this))) return_trace (false);
2964
0
    hb_barrier ();
2965
0
    unsigned int count = glyphCount;
2966
0
    if (unlikely (!count)) return_trace (false); /* We want to access coverageZ[0] freely. */
2967
0
    if (unlikely (!c->check_array (coverageZ.arrayZ, count))) return_trace (false);
2968
0
    for (unsigned int i = 0; i < count; i++)
2969
0
      if (unlikely (!coverageZ[i].sanitize (c, this))) return_trace (false);
2970
0
    const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
2971
0
    return_trace (likely (c->check_array (lookupRecord, lookupCount)));
2972
0
  }
2973
2974
  protected:
2975
  HBUINT16  format;     /* Format identifier--format = 3 */
2976
  HBUINT16  glyphCount;   /* Number of glyphs in the input glyph
2977
           * sequence */
2978
  HBUINT16  lookupCount;    /* Number of LookupRecords */
2979
  UnsizedArrayOf<Offset16To<Coverage>>
2980
    coverageZ;    /* Array of offsets to Coverage
2981
           * table in glyph sequence order */
2982
/*UnsizedArrayOf<LookupRecord>
2983
    lookupRecordX;*/  /* Array of LookupRecords--in
2984
           * design order */
2985
  public:
2986
  DEFINE_SIZE_ARRAY (6, coverageZ);
2987
};
2988
2989
struct Context
2990
{
2991
  template <typename context_t, typename ...Ts>
2992
  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
2993
0
  {
2994
0
    if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value ();
2995
0
    TRACE_DISPATCH (this, u.format.v);
2996
0
    switch (u.format.v) {
2997
0
    case 1: hb_barrier (); return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
2998
0
    case 2: hb_barrier (); return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
2999
0
    case 3: hb_barrier (); return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
3000
#ifndef HB_NO_BEYOND_64K
3001
    case 4: hb_barrier (); return_trace (c->dispatch (u.format4, std::forward<Ts> (ds)...));
3002
    case 5: hb_barrier (); return_trace (c->dispatch (u.format5, std::forward<Ts> (ds)...));
3003
#endif
3004
0
    default:return_trace (c->default_return_value ());
3005
0
    }
3006
0
  }
Unexecuted instantiation: hb_sanitize_context_t::return_t OT::Context::dispatch<hb_sanitize_context_t>(hb_sanitize_context_t*) const
Unexecuted instantiation: OT::hb_intersects_context_t::return_t OT::Context::dispatch<OT::hb_intersects_context_t>(OT::hb_intersects_context_t*) const
Unexecuted instantiation: OT::hb_ot_apply_context_t::return_t OT::Context::dispatch<OT::hb_ot_apply_context_t>(OT::hb_ot_apply_context_t*) const
Unexecuted instantiation: OT::hb_collect_glyphs_context_t::return_t OT::Context::dispatch<OT::hb_collect_glyphs_context_t>(OT::hb_collect_glyphs_context_t*) const
Unexecuted instantiation: OT::hb_closure_lookups_context_t::return_t OT::Context::dispatch<OT::hb_closure_lookups_context_t>(OT::hb_closure_lookups_context_t*) const
Unexecuted instantiation: hb_subset_context_t::return_t OT::Context::dispatch<hb_subset_context_t>(hb_subset_context_t*) const
Unexecuted instantiation: OT::hb_collect_variation_indices_context_t::return_t OT::Context::dispatch<OT::hb_collect_variation_indices_context_t>(OT::hb_collect_variation_indices_context_t*) const
Unexecuted instantiation: OT::hb_accelerate_subtables_context_t::return_t OT::Context::dispatch<OT::hb_accelerate_subtables_context_t>(OT::hb_accelerate_subtables_context_t*) const
Unexecuted instantiation: OT::hb_have_non_1to1_context_t::return_t OT::Context::dispatch<OT::hb_have_non_1to1_context_t>(OT::hb_have_non_1to1_context_t*) const
Unexecuted instantiation: OT::hb_closure_context_t::return_t OT::Context::dispatch<OT::hb_closure_context_t>(OT::hb_closure_context_t*) const
Unexecuted instantiation: OT::hb_would_apply_context_t::return_t OT::Context::dispatch<OT::hb_would_apply_context_t>(OT::hb_would_apply_context_t*) const
Unexecuted instantiation: hb_get_glyph_alternates_dispatch_t::return_t OT::Context::dispatch<hb_get_glyph_alternates_dispatch_t, unsigned int&, unsigned int&, unsigned int*&, unsigned int*&>(hb_get_glyph_alternates_dispatch_t*, unsigned int&, unsigned int&, unsigned int*&, unsigned int*&) const
Unexecuted instantiation: hb_collect_glyph_alternates_dispatch_t::return_t OT::Context::dispatch<hb_collect_glyph_alternates_dispatch_t, hb_map_t*&, hb_map_t*&>(hb_collect_glyph_alternates_dispatch_t*, hb_map_t*&, hb_map_t*&) const
Unexecuted instantiation: hb_position_single_dispatch_t::return_t OT::Context::dispatch<hb_position_single_dispatch_t, hb_font_t*&, hb_blob_t*&, hb_direction_t&, unsigned int&, hb_glyph_position_t&>(hb_position_single_dispatch_t*, hb_font_t*&, hb_blob_t*&, hb_direction_t&, unsigned int&, hb_glyph_position_t&) const
3007
3008
  protected:
3009
  union {
3010
  struct { HBUINT16 v; }  format;   /* Format identifier */
3011
  ContextFormat1_4<SmallTypes>  format1;
3012
  ContextFormat2_5<SmallTypes>  format2;
3013
  ContextFormat3    format3;
3014
#ifndef HB_NO_BEYOND_64K
3015
  ContextFormat1_4<MediumTypes> format4;
3016
  ContextFormat2_5<MediumTypes> format5;
3017
#endif
3018
  } u;
3019
};
3020
3021
3022
/* Chaining Contextual lookups */
3023
3024
struct ChainContextClosureLookupContext
3025
{
3026
  ContextClosureFuncs funcs;
3027
  ContextFormat context_format;
3028
  const void *intersects_data[3];
3029
  void *intersects_cache[3];
3030
  void *intersected_glyphs_cache;
3031
};
3032
3033
struct ChainContextCollectGlyphsLookupContext
3034
{
3035
  ContextCollectGlyphsFuncs funcs;
3036
  const void *collect_data[3];
3037
};
3038
3039
struct ChainContextApplyLookupContext
3040
{
3041
  ChainContextApplyFuncs funcs;
3042
  const void *match_data[3];
3043
};
3044
3045
template <typename HBUINT>
3046
static inline bool chain_context_intersects (const hb_set_t *glyphs,
3047
               unsigned int backtrackCount,
3048
               const HBUINT backtrack[],
3049
               unsigned int inputCount, /* Including the first glyph (not matched) */
3050
               const HBUINT input[], /* Array of input values--start with second glyph */
3051
               unsigned int lookaheadCount,
3052
               const HBUINT lookahead[],
3053
               ChainContextClosureLookupContext &lookup_context)
3054
0
{
3055
0
  return array_is_subset_of (glyphs,
3056
0
           backtrackCount, backtrack,
3057
0
           lookup_context.funcs.intersects,
3058
0
           lookup_context.intersects_data[0],
3059
0
           lookup_context.intersects_cache[0])
3060
0
      && array_is_subset_of (glyphs,
3061
0
           inputCount ? inputCount - 1 : 0, input,
3062
0
           lookup_context.funcs.intersects,
3063
0
           lookup_context.intersects_data[1],
3064
0
           lookup_context.intersects_cache[1])
3065
0
      && array_is_subset_of (glyphs,
3066
0
           lookaheadCount, lookahead,
3067
0
           lookup_context.funcs.intersects,
3068
0
           lookup_context.intersects_data[2],
3069
0
           lookup_context.intersects_cache[2]);
3070
0
}
Unexecuted instantiation: hb-aat-layout.cc:bool OT::chain_context_intersects<OT::NumType<true, unsigned short, 2u> >(hb_set_t const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, OT::ChainContextClosureLookupContext&)
Unexecuted instantiation: hb-ot-face.cc:bool OT::chain_context_intersects<OT::NumType<true, unsigned short, 2u> >(hb_set_t const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, OT::ChainContextClosureLookupContext&)
Unexecuted instantiation: hb-ot-layout.cc:bool OT::chain_context_intersects<OT::NumType<true, unsigned short, 2u> >(hb_set_t const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, OT::ChainContextClosureLookupContext&)
Unexecuted instantiation: hb-ot-shaper-arabic.cc:bool OT::chain_context_intersects<OT::NumType<true, unsigned short, 2u> >(hb_set_t const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, OT::ChainContextClosureLookupContext&)
Unexecuted instantiation: hb-ot-shape-fallback.cc:bool OT::chain_context_intersects<OT::NumType<true, unsigned short, 2u> >(hb_set_t const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, OT::ChainContextClosureLookupContext&)
3071
3072
template <typename HBUINT>
3073
static inline void chain_context_closure_lookup (hb_closure_context_t *c,
3074
             unsigned int backtrackCount,
3075
             const HBUINT backtrack[],
3076
             unsigned int inputCount, /* Including the first glyph (not matched) */
3077
             const HBUINT input[], /* Array of input values--start with second glyph */
3078
             unsigned int lookaheadCount,
3079
             const HBUINT lookahead[],
3080
             unsigned int lookupCount,
3081
             const LookupRecord lookupRecord[],
3082
             unsigned value,
3083
             ChainContextClosureLookupContext &lookup_context)
3084
0
{
3085
0
  if (chain_context_intersects (c->glyphs,
3086
0
        backtrackCount, backtrack,
3087
0
        inputCount, input,
3088
0
        lookaheadCount, lookahead,
3089
0
        lookup_context))
3090
0
    context_closure_recurse_lookups (c,
3091
0
         inputCount, input,
3092
0
         lookupCount, lookupRecord,
3093
0
         value,
3094
0
         lookup_context.context_format,
3095
0
         lookup_context.intersects_data[1],
3096
0
         lookup_context.funcs.intersected_glyphs,
3097
0
         lookup_context.intersected_glyphs_cache);
3098
0
}
Unexecuted instantiation: hb-aat-layout.cc:void OT::chain_context_closure_lookup<OT::NumType<true, unsigned short, 2u> >(OT::hb_closure_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::LookupRecord const*, unsigned int, OT::ChainContextClosureLookupContext&)
Unexecuted instantiation: hb-ot-face.cc:void OT::chain_context_closure_lookup<OT::NumType<true, unsigned short, 2u> >(OT::hb_closure_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::LookupRecord const*, unsigned int, OT::ChainContextClosureLookupContext&)
Unexecuted instantiation: hb-ot-layout.cc:void OT::chain_context_closure_lookup<OT::NumType<true, unsigned short, 2u> >(OT::hb_closure_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::LookupRecord const*, unsigned int, OT::ChainContextClosureLookupContext&)
Unexecuted instantiation: hb-ot-shaper-arabic.cc:void OT::chain_context_closure_lookup<OT::NumType<true, unsigned short, 2u> >(OT::hb_closure_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::LookupRecord const*, unsigned int, OT::ChainContextClosureLookupContext&)
Unexecuted instantiation: hb-ot-shape-fallback.cc:void OT::chain_context_closure_lookup<OT::NumType<true, unsigned short, 2u> >(OT::hb_closure_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::LookupRecord const*, unsigned int, OT::ChainContextClosureLookupContext&)
3099
3100
template <typename HBUINT>
3101
static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
3102
              unsigned int backtrackCount,
3103
              const HBUINT backtrack[],
3104
              unsigned int inputCount, /* Including the first glyph (not matched) */
3105
              const HBUINT input[], /* Array of input values--start with second glyph */
3106
              unsigned int lookaheadCount,
3107
              const HBUINT lookahead[],
3108
              unsigned int lookupCount,
3109
              const LookupRecord lookupRecord[],
3110
              ChainContextCollectGlyphsLookupContext &lookup_context)
3111
0
{
3112
0
  collect_array (c, c->before,
3113
0
     backtrackCount, backtrack,
3114
0
     lookup_context.funcs.collect, lookup_context.collect_data[0]);
3115
0
  collect_array (c, c->input,
3116
0
     inputCount ? inputCount - 1 : 0, input,
3117
0
     lookup_context.funcs.collect, lookup_context.collect_data[1]);
3118
0
  collect_array (c, c->after,
3119
0
     lookaheadCount, lookahead,
3120
0
     lookup_context.funcs.collect, lookup_context.collect_data[2]);
3121
0
  recurse_lookups (c,
3122
0
       lookupCount, lookupRecord);
3123
0
}
Unexecuted instantiation: hb-aat-layout.cc:void OT::chain_context_collect_glyphs_lookup<OT::NumType<true, unsigned short, 2u> >(OT::hb_collect_glyphs_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::LookupRecord const*, OT::ChainContextCollectGlyphsLookupContext&)
Unexecuted instantiation: hb-ot-face.cc:void OT::chain_context_collect_glyphs_lookup<OT::NumType<true, unsigned short, 2u> >(OT::hb_collect_glyphs_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::LookupRecord const*, OT::ChainContextCollectGlyphsLookupContext&)
Unexecuted instantiation: hb-ot-layout.cc:void OT::chain_context_collect_glyphs_lookup<OT::NumType<true, unsigned short, 2u> >(OT::hb_collect_glyphs_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::LookupRecord const*, OT::ChainContextCollectGlyphsLookupContext&)
Unexecuted instantiation: hb-ot-shaper-arabic.cc:void OT::chain_context_collect_glyphs_lookup<OT::NumType<true, unsigned short, 2u> >(OT::hb_collect_glyphs_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::LookupRecord const*, OT::ChainContextCollectGlyphsLookupContext&)
Unexecuted instantiation: hb-ot-shape-fallback.cc:void OT::chain_context_collect_glyphs_lookup<OT::NumType<true, unsigned short, 2u> >(OT::hb_collect_glyphs_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::LookupRecord const*, OT::ChainContextCollectGlyphsLookupContext&)
3124
3125
template <typename HBUINT>
3126
static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c,
3127
                 unsigned int backtrackCount,
3128
                 const HBUINT backtrack[] HB_UNUSED,
3129
                 unsigned int inputCount, /* Including the first glyph (not matched) */
3130
                 const HBUINT input[], /* Array of input values--start with second glyph */
3131
                 unsigned int lookaheadCount,
3132
                 const HBUINT lookahead[] HB_UNUSED,
3133
                 unsigned int lookupCount HB_UNUSED,
3134
                 const LookupRecord lookupRecord[] HB_UNUSED,
3135
                 const ChainContextApplyLookupContext &lookup_context)
3136
0
{
3137
0
  return (c->zero_context ? !backtrackCount && !lookaheadCount : true)
3138
0
      && would_match_input (c,
3139
0
          inputCount, input,
3140
0
          lookup_context.funcs.match[1], lookup_context.match_data[1]);
3141
0
}
Unexecuted instantiation: hb-aat-layout.cc:bool OT::chain_context_would_apply_lookup<OT::NumType<true, unsigned short, 2u> >(OT::hb_would_apply_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::LookupRecord const*, OT::ChainContextApplyLookupContext const&)
Unexecuted instantiation: hb-ot-face.cc:bool OT::chain_context_would_apply_lookup<OT::NumType<true, unsigned short, 2u> >(OT::hb_would_apply_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::LookupRecord const*, OT::ChainContextApplyLookupContext const&)
Unexecuted instantiation: hb-ot-layout.cc:bool OT::chain_context_would_apply_lookup<OT::NumType<true, unsigned short, 2u> >(OT::hb_would_apply_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::LookupRecord const*, OT::ChainContextApplyLookupContext const&)
Unexecuted instantiation: hb-ot-shaper-arabic.cc:bool OT::chain_context_would_apply_lookup<OT::NumType<true, unsigned short, 2u> >(OT::hb_would_apply_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::LookupRecord const*, OT::ChainContextApplyLookupContext const&)
Unexecuted instantiation: hb-ot-shape-fallback.cc:bool OT::chain_context_would_apply_lookup<OT::NumType<true, unsigned short, 2u> >(OT::hb_would_apply_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::LookupRecord const*, OT::ChainContextApplyLookupContext const&)
3142
3143
template <typename HBUINT>
3144
static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
3145
                 unsigned int backtrackCount,
3146
                 const HBUINT backtrack[],
3147
                 unsigned int inputCount, /* Including the first glyph (not matched) */
3148
                 const HBUINT input[], /* Array of input values--start with second glyph */
3149
                 unsigned int lookaheadCount,
3150
                 const HBUINT lookahead[],
3151
                 unsigned int lookupCount,
3152
                 const LookupRecord lookupRecord[],
3153
                 const ChainContextApplyLookupContext &lookup_context)
3154
1.02M
{
3155
1.02M
  if (unlikely (inputCount > HB_MAX_CONTEXT_LENGTH)) return false;
3156
3157
1.02M
  unsigned start_index = c->buffer->out_len;
3158
1.02M
  unsigned end_index = c->buffer->idx;
3159
1.02M
  unsigned match_end = 0;
3160
1.02M
  bool ret = true;
3161
1.02M
  if (!(match_input (c,
3162
1.02M
         inputCount, input,
3163
1.02M
         lookup_context.funcs.match[1], lookup_context.match_data[1],
3164
1.02M
         &match_end) && (end_index = match_end)
3165
969k
       && match_lookahead (c,
3166
969k
         lookaheadCount, lookahead,
3167
969k
         lookup_context.funcs.match[2], lookup_context.match_data[2],
3168
969k
         match_end, &end_index)))
3169
455k
  {
3170
455k
    c->buffer->unsafe_to_concat (c->buffer->idx, end_index);
3171
455k
    return false;
3172
455k
  }
3173
3174
570k
  if (!match_backtrack (c,
3175
570k
      backtrackCount, backtrack,
3176
570k
      lookup_context.funcs.match[0], lookup_context.match_data[0],
3177
570k
      &start_index))
3178
559k
  {
3179
559k
    c->buffer->unsafe_to_concat_from_outbuffer (start_index, end_index);
3180
559k
    return false;
3181
559k
  }
3182
3183
10.9k
  c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index);
3184
10.9k
  apply_lookup (c,
3185
10.9k
    inputCount,
3186
10.9k
    lookupCount, lookupRecord,
3187
10.9k
    match_end);
3188
3189
10.9k
  return ret;
3190
570k
}
Unexecuted instantiation: hb-aat-layout.cc:bool OT::chain_context_apply_lookup<OT::NumType<true, unsigned short, 2u> >(OT::hb_ot_apply_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::LookupRecord const*, OT::ChainContextApplyLookupContext const&)
Unexecuted instantiation: hb-ot-face.cc:bool OT::chain_context_apply_lookup<OT::NumType<true, unsigned short, 2u> >(OT::hb_ot_apply_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::LookupRecord const*, OT::ChainContextApplyLookupContext const&)
hb-ot-layout.cc:bool OT::chain_context_apply_lookup<OT::NumType<true, unsigned short, 2u> >(OT::hb_ot_apply_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::LookupRecord const*, OT::ChainContextApplyLookupContext const&)
Line
Count
Source
3154
1.02M
{
3155
1.02M
  if (unlikely (inputCount > HB_MAX_CONTEXT_LENGTH)) return false;
3156
3157
1.02M
  unsigned start_index = c->buffer->out_len;
3158
1.02M
  unsigned end_index = c->buffer->idx;
3159
1.02M
  unsigned match_end = 0;
3160
1.02M
  bool ret = true;
3161
1.02M
  if (!(match_input (c,
3162
1.02M
         inputCount, input,
3163
1.02M
         lookup_context.funcs.match[1], lookup_context.match_data[1],
3164
1.02M
         &match_end) && (end_index = match_end)
3165
969k
       && match_lookahead (c,
3166
969k
         lookaheadCount, lookahead,
3167
969k
         lookup_context.funcs.match[2], lookup_context.match_data[2],
3168
969k
         match_end, &end_index)))
3169
455k
  {
3170
455k
    c->buffer->unsafe_to_concat (c->buffer->idx, end_index);
3171
455k
    return false;
3172
455k
  }
3173
3174
570k
  if (!match_backtrack (c,
3175
570k
      backtrackCount, backtrack,
3176
570k
      lookup_context.funcs.match[0], lookup_context.match_data[0],
3177
570k
      &start_index))
3178
559k
  {
3179
559k
    c->buffer->unsafe_to_concat_from_outbuffer (start_index, end_index);
3180
559k
    return false;
3181
559k
  }
3182
3183
10.9k
  c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index);
3184
10.9k
  apply_lookup (c,
3185
10.9k
    inputCount,
3186
10.9k
    lookupCount, lookupRecord,
3187
10.9k
    match_end);
3188
3189
10.9k
  return ret;
3190
570k
}
Unexecuted instantiation: hb-ot-shaper-arabic.cc:bool OT::chain_context_apply_lookup<OT::NumType<true, unsigned short, 2u> >(OT::hb_ot_apply_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::LookupRecord const*, OT::ChainContextApplyLookupContext const&)
Unexecuted instantiation: hb-ot-shape-fallback.cc:bool OT::chain_context_apply_lookup<OT::NumType<true, unsigned short, 2u> >(OT::hb_ot_apply_context_t*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::NumType<true, unsigned short, 2u> const*, unsigned int, OT::LookupRecord const*, OT::ChainContextApplyLookupContext const&)
3191
3192
template <typename Types>
3193
struct ChainRule
3194
{
3195
  template <typename T>
3196
  friend struct ChainRuleSet;
3197
3198
  bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
3199
0
  {
3200
0
    const auto &input = StructAfter<decltype (inputX)> (backtrack);
3201
0
    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
3202
0
    return chain_context_intersects (glyphs,
3203
0
             backtrack.len, backtrack.arrayZ,
3204
0
             input.lenP1, input.arrayZ,
3205
0
             lookahead.len, lookahead.arrayZ,
3206
0
             lookup_context);
3207
0
  }
3208
3209
  void closure (hb_closure_context_t *c, unsigned value,
3210
    ChainContextClosureLookupContext &lookup_context) const
3211
0
  {
3212
0
    if (unlikely (c->lookup_limit_exceeded ())) return;
3213
3214
0
    const auto &input = StructAfter<decltype (inputX)> (backtrack);
3215
0
    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
3216
0
    const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
3217
0
    chain_context_closure_lookup (c,
3218
0
          backtrack.len, backtrack.arrayZ,
3219
0
          input.lenP1, input.arrayZ,
3220
0
          lookahead.len, lookahead.arrayZ,
3221
0
          lookup.len, lookup.arrayZ,
3222
0
          value,
3223
0
          lookup_context);
3224
0
  }
3225
3226
  void closure_lookups (hb_closure_lookups_context_t *c,
3227
                        ChainContextClosureLookupContext &lookup_context) const
3228
0
  {
3229
0
    if (unlikely (c->lookup_limit_exceeded ())) return;
3230
0
    if (!intersects (c->glyphs, lookup_context)) return;
3231
0
3232
0
    const auto &input = StructAfter<decltype (inputX)> (backtrack);
3233
0
    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
3234
0
    const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
3235
0
    recurse_lookups (c, lookup.len, lookup.arrayZ);
3236
0
  }
3237
3238
  void collect_glyphs (hb_collect_glyphs_context_t *c,
3239
           ChainContextCollectGlyphsLookupContext &lookup_context) const
3240
0
  {
3241
0
    const auto &input = StructAfter<decltype (inputX)> (backtrack);
3242
0
    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
3243
0
    const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
3244
0
    chain_context_collect_glyphs_lookup (c,
3245
0
           backtrack.len, backtrack.arrayZ,
3246
0
           input.lenP1, input.arrayZ,
3247
0
           lookahead.len, lookahead.arrayZ,
3248
0
           lookup.len, lookup.arrayZ,
3249
0
           lookup_context);
3250
0
  }
3251
3252
  bool would_apply (hb_would_apply_context_t *c,
3253
        const ChainContextApplyLookupContext &lookup_context) const
3254
0
  {
3255
0
    const auto &input = StructAfter<decltype (inputX)> (backtrack);
3256
0
    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
3257
0
    const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
3258
0
    return chain_context_would_apply_lookup (c,
3259
0
               backtrack.len, backtrack.arrayZ,
3260
0
               input.lenP1, input.arrayZ,
3261
0
               lookahead.len, lookahead.arrayZ, lookup.len,
3262
0
               lookup.arrayZ, lookup_context);
3263
0
  }
3264
3265
  bool apply (hb_ot_apply_context_t *c,
3266
        const ChainContextApplyLookupContext &lookup_context) const
3267
0
  {
3268
0
    TRACE_APPLY (this);
3269
0
    const auto &input = StructAfter<decltype (inputX)> (backtrack);
3270
0
    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
3271
0
    const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
3272
0
    return_trace (chain_context_apply_lookup (c,
3273
0
                backtrack.len, backtrack.arrayZ,
3274
0
                input.lenP1, input.arrayZ,
3275
0
                lookahead.len, lookahead.arrayZ, lookup.len,
3276
0
                lookup.arrayZ, lookup_context));
3277
0
  }
3278
3279
  template<typename Iterator,
3280
     hb_requires (hb_is_iterator (Iterator))>
3281
  void serialize_array (hb_serialize_context_t *c,
3282
      HBUINT16 len,
3283
      Iterator it) const
3284
0
  {
3285
0
    c->copy (len);
3286
0
    for (const auto g : it)
3287
0
      c->copy ((HBUINT16) g);
3288
0
  }
3289
3290
  bool serialize (hb_serialize_context_t *c,
3291
      const hb_map_t *lookup_map,
3292
      const hb_map_t *backtrack_map,
3293
      const hb_map_t *input_map = nullptr,
3294
      const hb_map_t *lookahead_map = nullptr) const
3295
0
  {
3296
0
    TRACE_SERIALIZE (this);
3297
0
3298
0
    const hb_map_t *mapping = backtrack_map;
3299
0
    serialize_array (c, backtrack.len, + backtrack.iter ()
3300
0
               | hb_map (mapping));
3301
0
3302
0
    const auto &input = StructAfter<decltype (inputX)> (backtrack);
3303
0
    if (input_map) mapping = input_map;
3304
0
    serialize_array (c, input.lenP1, + input.iter ()
3305
0
             | hb_map (mapping));
3306
0
3307
0
    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
3308
0
    if (lookahead_map) mapping = lookahead_map;
3309
0
    serialize_array (c, lookahead.len, + lookahead.iter ()
3310
0
               | hb_map (mapping));
3311
0
3312
0
    const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
3313
0
3314
0
    HBUINT16* lookupCount = c->embed (&(lookup.len));
3315
0
    if (!lookupCount) return_trace (false);
3316
0
3317
0
    unsigned count = serialize_lookuprecord_array (c, lookup.as_array (), lookup_map);
3318
0
    return_trace (c->check_assign (*lookupCount, count, HB_SERIALIZE_ERROR_INT_OVERFLOW));
3319
0
  }
3320
3321
  bool subset (hb_subset_context_t *c,
3322
         const hb_map_t *lookup_map,
3323
         const hb_map_t *backtrack_map = nullptr,
3324
         const hb_map_t *input_map = nullptr,
3325
         const hb_map_t *lookahead_map = nullptr) const
3326
0
  {
3327
0
    TRACE_SUBSET (this);
3328
0
3329
0
    const auto &input = StructAfter<decltype (inputX)> (backtrack);
3330
0
    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
3331
0
3332
0
    if (!backtrack_map)
3333
0
    {
3334
0
      const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
3335
0
      if (!hb_all (backtrack, glyphset) ||
3336
0
    !hb_all (input, glyphset) ||
3337
0
    !hb_all (lookahead, glyphset))
3338
0
  return_trace (false);
3339
0
3340
0
      serialize (c->serializer, lookup_map, c->plan->glyph_map);
3341
0
    }
3342
0
    else
3343
0
    {
3344
0
      if (!hb_all (backtrack, backtrack_map) ||
3345
0
    !hb_all (input, input_map) ||
3346
0
    !hb_all (lookahead, lookahead_map))
3347
0
  return_trace (false);
3348
0
3349
0
      serialize (c->serializer, lookup_map, backtrack_map, input_map, lookahead_map);
3350
0
    }
3351
0
3352
0
    return_trace (true);
3353
0
  }
3354
3355
  bool sanitize (hb_sanitize_context_t *c) const
3356
0
  {
3357
0
    TRACE_SANITIZE (this);
3358
    /* Hyper-optimized sanitized because this is really hot. */
3359
0
    if (unlikely (!backtrack.len.sanitize (c))) return_trace (false);
3360
0
    hb_barrier ();
3361
0
    const auto &input = StructAfter<decltype (inputX)> (backtrack);
3362
0
    if (unlikely (!input.lenP1.sanitize (c))) return_trace (false);
3363
0
    hb_barrier ();
3364
0
    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
3365
0
    if (unlikely (!lookahead.len.sanitize (c))) return_trace (false);
3366
0
    hb_barrier ();
3367
0
    const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
3368
0
    return_trace (likely (lookup.sanitize (c)));
3369
0
  }
3370
3371
  protected:
3372
  Array16Of<typename Types::HBUINT>
3373
    backtrack;    /* Array of backtracking values
3374
           * (to be matched before the input
3375
           * sequence) */
3376
  HeadlessArray16Of<typename Types::HBUINT>
3377
    inputX;     /* Array of input values (start with
3378
           * second glyph) */
3379
  Array16Of<typename Types::HBUINT>
3380
    lookaheadX;   /* Array of lookahead values's (to be
3381
           * matched after the input sequence) */
3382
  Array16Of<LookupRecord>
3383
    lookupX;    /* Array of LookupRecords--in
3384
           * design order) */
3385
  public:
3386
  DEFINE_SIZE_MIN (8);
3387
};
3388
3389
template <typename Types>
3390
struct ChainRuleSet
3391
{
3392
  using ChainRule = OT::ChainRule<Types>;
3393
3394
  bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
3395
0
  {
3396
0
    return
3397
0
    + hb_iter (rule)
3398
0
    | hb_map (hb_add (this))
3399
0
    | hb_map ([&] (const ChainRule &_) { return _.intersects (glyphs, lookup_context); })
3400
0
    | hb_any
3401
0
    ;
3402
0
  }
3403
  void closure (hb_closure_context_t *c, unsigned value, ChainContextClosureLookupContext &lookup_context) const
3404
0
  {
3405
0
    if (unlikely (c->lookup_limit_exceeded ())) return;
3406
3407
0
    return
3408
0
    + hb_iter (rule)
3409
0
    | hb_map (hb_add (this))
3410
0
    | hb_apply ([&] (const ChainRule &_) { _.closure (c, value, lookup_context); })
3411
0
    ;
3412
0
  }
3413
3414
  void closure_lookups (hb_closure_lookups_context_t *c,
3415
                        ChainContextClosureLookupContext &lookup_context) const
3416
0
  {
3417
0
    if (unlikely (c->lookup_limit_exceeded ())) return;
3418
0
3419
0
    + hb_iter (rule)
3420
0
    | hb_map (hb_add (this))
3421
0
    | hb_apply ([&] (const ChainRule &_) { _.closure_lookups (c, lookup_context); })
3422
0
    ;
3423
0
  }
3424
3425
  void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
3426
0
  {
3427
0
    return
3428
0
    + hb_iter (rule)
3429
0
    | hb_map (hb_add (this))
3430
0
    | hb_apply ([&] (const ChainRule &_) { _.collect_glyphs (c, lookup_context); })
3431
0
    ;
3432
0
  }
3433
3434
  bool would_apply (hb_would_apply_context_t *c,
3435
        const ChainContextApplyLookupContext &lookup_context) const
3436
0
  {
3437
0
    return
3438
0
    + hb_iter (rule)
3439
0
    | hb_map (hb_add (this))
3440
0
    | hb_map ([&] (const ChainRule &_) { return _.would_apply (c, lookup_context); })
3441
0
    | hb_any
3442
0
    ;
3443
0
  }
3444
3445
  bool apply (hb_ot_apply_context_t *c,
3446
        const ChainContextApplyLookupContext &lookup_context) const
3447
0
  {
3448
0
    TRACE_APPLY (this);
3449
3450
0
    unsigned num_rules = rule.len;
3451
3452
0
#ifndef HB_NO_OT_RULESETS_FAST_PATH
3453
0
    if (HB_OPTIMIZE_SIZE_VAL || num_rules <= 4)
3454
0
#endif
3455
0
    {
3456
0
    slow:
3457
0
      return_trace (
3458
0
      + hb_iter (rule)
3459
0
      | hb_map (hb_add (this))
3460
0
      | hb_map ([&] (const ChainRule &_) { return _.apply (c, lookup_context); })
3461
0
      | hb_any
3462
0
      )
3463
0
      ;
3464
0
    }
3465
3466
    /* This version is optimized for speed by matching the first & second
3467
     * components of the rule here, instead of calling into the matching code.
3468
     *
3469
     * Replicated from LigatureSet::apply(). */
3470
3471
    /* We use the iter_context instead of iter_input, to avoid skipping
3472
     * default-ignorables and such.
3473
     *
3474
     * Related: https://github.com/harfbuzz/harfbuzz/issues/4813
3475
     */
3476
0
    auto &skippy_iter = c->iter_context;
3477
0
    skippy_iter.reset (c->buffer->idx);
3478
0
    skippy_iter.set_match_func (match_always, nullptr);
3479
0
    skippy_iter.set_glyph_data ((HBUINT16 *) nullptr);
3480
0
    unsigned unsafe_to = (unsigned) -1, unsafe_to1, unsafe_to2 = 0;
3481
0
    hb_glyph_info_t *first = nullptr, *second = nullptr;
3482
0
    bool matched = skippy_iter.next ();
3483
0
    if (likely (matched))
3484
0
    {
3485
0
      if (skippy_iter.may_skip (c->buffer->info[skippy_iter.idx]))
3486
0
      {
3487
  /* Can't use the fast path if eg. the next char is a default-ignorable
3488
   * or other skippable. */
3489
0
        goto slow;
3490
0
      }
3491
3492
0
      first = &c->buffer->info[skippy_iter.idx];
3493
0
      unsafe_to1 = skippy_iter.idx + 1;
3494
0
    }
3495
0
    else
3496
0
    {
3497
      /* Failed to match a next glyph. Only try applying rules that have
3498
       * no further input and lookahead. */
3499
0
      return_trace (
3500
0
      + hb_iter (rule)
3501
0
      | hb_map (hb_add (this))
3502
0
      | hb_filter ([&] (const ChainRule &_)
3503
0
       {
3504
0
         const auto &input = StructAfter<decltype (_.inputX)> (_.backtrack);
3505
0
         const auto &lookahead = StructAfter<decltype (_.lookaheadX)> (input);
3506
0
         return input.lenP1 <= 1 && lookahead.len == 0;
3507
0
       })
3508
0
      | hb_map ([&] (const ChainRule &_) { return _.apply (c, lookup_context); })
3509
0
      | hb_any
3510
0
      )
3511
0
      ;
3512
0
    }
3513
0
    matched = skippy_iter.next ();
3514
0
    if (likely (matched))
3515
0
    {
3516
0
      if (skippy_iter.may_skip (c->buffer->info[skippy_iter.idx]))
3517
0
      {
3518
  /* Can't use the fast path if eg. the next char is a default-ignorable
3519
   * or other skippable. */
3520
0
        goto slow;
3521
0
      }
3522
3523
0
      second = &c->buffer->info[skippy_iter.idx];
3524
0
      unsafe_to2 = skippy_iter.idx + 1;
3525
0
    }
3526
3527
0
    auto match_input = lookup_context.funcs.match[1];
3528
0
    auto match_lookahead = lookup_context.funcs.match[2];
3529
0
    auto *input_data = lookup_context.match_data[1];
3530
0
    auto *lookahead_data = lookup_context.match_data[2];
3531
0
    for (unsigned int i = 0; i < num_rules; i++)
3532
0
    {
3533
0
      const auto &r = this+rule.arrayZ[i];
3534
3535
0
      const auto &input = StructAfter<decltype (r.inputX)> (r.backtrack);
3536
0
      const auto &lookahead = StructAfter<decltype (r.lookaheadX)> (input);
3537
3538
0
      unsigned lenP1 = input.lenP1;
3539
0
      if (lenP1 > 1 ?
3540
0
     (!match_input ||
3541
0
      match_input (*first, input.arrayZ[0], input_data))
3542
0
    :
3543
0
     (!lookahead.len || !match_lookahead ||
3544
0
      match_lookahead (*first, lookahead.arrayZ[0], lookahead_data)))
3545
0
      {
3546
0
  lenP1 = hb_max (lenP1, 1u);
3547
0
        if (!second ||
3548
0
      (lenP1 > 2 ?
3549
0
       (!match_input ||
3550
0
        match_input (*second, input.arrayZ[1], input_data))
3551
0
       :
3552
0
       (lookahead.len <= 2 - lenP1 || !match_lookahead ||
3553
0
        match_lookahead (*second, lookahead.arrayZ[2 - lenP1], lookahead_data))))
3554
0
  {
3555
0
    if (r.apply (c, lookup_context))
3556
0
    {
3557
0
      if (unsafe_to != (unsigned) -1)
3558
0
        c->buffer->unsafe_to_concat (c->buffer->idx, unsafe_to);
3559
0
      return_trace (true);
3560
0
    }
3561
0
  }
3562
0
  else
3563
0
    unsafe_to = unsafe_to2;
3564
0
      }
3565
0
      else
3566
0
      {
3567
0
  if (unsafe_to == (unsigned) -1)
3568
0
    unsafe_to = unsafe_to1;
3569
3570
0
  if (lenP1 > 1)
3571
0
  {
3572
    // Skip ahead to next possible first glyph match.
3573
0
    for (; i + 1 < num_rules; i++)
3574
0
    {
3575
0
      const auto &r2 = this+rule.arrayZ[i + 1];
3576
0
      const auto &input2 = StructAfter<decltype (r2.inputX)> (r2.backtrack);
3577
0
      if (input2.lenP1 <= 1 || input2.arrayZ[0] != input.arrayZ[0])
3578
0
        break;
3579
0
    }
3580
0
  }
3581
0
      }
3582
0
    }
3583
0
    if (likely (unsafe_to != (unsigned) -1))
3584
0
      c->buffer->unsafe_to_concat (c->buffer->idx, unsafe_to);
3585
3586
0
    return_trace (false);
3587
0
  }
3588
3589
  bool subset (hb_subset_context_t *c,
3590
         const hb_map_t *lookup_map,
3591
         const hb_map_t *backtrack_klass_map = nullptr,
3592
         const hb_map_t *input_klass_map = nullptr,
3593
         const hb_map_t *lookahead_klass_map = nullptr) const
3594
0
  {
3595
0
    TRACE_SUBSET (this);
3596
0
3597
0
    auto snap = c->serializer->snapshot ();
3598
0
    auto *out = c->serializer->start_embed (*this);
3599
0
    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
3600
0
3601
0
    for (const Offset16To<ChainRule>& _ : rule)
3602
0
    {
3603
0
      if (!_) continue;
3604
0
      auto o_snap = c->serializer->snapshot ();
3605
0
      auto *o = out->rule.serialize_append (c->serializer);
3606
0
      if (unlikely (!o)) continue;
3607
0
3608
0
      if (!o->serialize_subset (c, _, this,
3609
0
        lookup_map,
3610
0
        backtrack_klass_map,
3611
0
        input_klass_map,
3612
0
        lookahead_klass_map))
3613
0
      {
3614
0
  out->rule.pop ();
3615
0
  c->serializer->revert (o_snap);
3616
0
      }
3617
0
    }
3618
0
3619
0
    bool ret = bool (out->rule);
3620
0
    if (!ret) c->serializer->revert (snap);
3621
0
3622
0
    return_trace (ret);
3623
0
  }
3624
3625
  bool sanitize (hb_sanitize_context_t *c) const
3626
0
  {
3627
0
    TRACE_SANITIZE (this);
3628
0
    return_trace (rule.sanitize (c, this));
3629
0
  }
3630
3631
  protected:
3632
  Array16OfOffset16To<ChainRule>
3633
    rule;     /* Array of ChainRule tables
3634
           * ordered by preference */
3635
  public:
3636
  DEFINE_SIZE_ARRAY (2, rule);
3637
};
3638
3639
template <typename Types>
3640
struct ChainContextFormat1_4
3641
{
3642
  using ChainRuleSet = OT::ChainRuleSet<Types>;
3643
3644
  bool intersects (const hb_set_t *glyphs) const
3645
0
  {
3646
0
    struct ChainContextClosureLookupContext lookup_context = {
3647
0
      {intersects_glyph, intersected_glyph},
3648
0
      ContextFormat::SimpleContext,
3649
0
      {nullptr, nullptr, nullptr}
3650
0
    };
3651
0
3652
0
    return
3653
0
    + hb_zip (this+coverage, ruleSet)
3654
0
    | hb_filter (*glyphs, hb_first)
3655
0
    | hb_map (hb_second)
3656
0
    | hb_map (hb_add (this))
3657
0
    | hb_map ([&] (const ChainRuleSet &_) { return _.intersects (glyphs, lookup_context); })
3658
0
    | hb_any
3659
0
    ;
3660
0
  }
3661
3662
  bool may_have_non_1to1 () const
3663
0
  { return true; }
3664
3665
  void closure (hb_closure_context_t *c) const
3666
0
  {
3667
0
    hb_set_t* cur_active_glyphs = c->push_cur_active_glyphs ();
3668
0
    if (unlikely (!cur_active_glyphs)) return;
3669
0
    get_coverage ().intersect_set (c->previous_parent_active_glyphs (),
3670
0
           *cur_active_glyphs);
3671
3672
0
    struct ChainContextClosureLookupContext lookup_context = {
3673
0
      {intersects_glyph, intersected_glyph},
3674
0
      ContextFormat::SimpleContext,
3675
0
      {nullptr, nullptr, nullptr}
3676
0
    };
3677
3678
0
    + hb_zip (this+coverage, hb_range ((unsigned) ruleSet.len))
3679
0
    | hb_filter ([&] (hb_codepoint_t _) {
3680
0
      return c->previous_parent_active_glyphs ().has (_);
3681
0
    }, hb_first)
3682
0
    | hb_map ([&](const hb_pair_t<hb_codepoint_t, unsigned> _) { return hb_pair_t<unsigned, const ChainRuleSet&> (_.first, this+ruleSet[_.second]); })
3683
0
    | hb_apply ([&] (const hb_pair_t<unsigned, const ChainRuleSet&>& _) { _.second.closure (c, _.first, lookup_context); })
3684
0
    ;
3685
3686
0
    c->pop_cur_done_glyphs ();
3687
0
  }
3688
3689
  void closure_lookups (hb_closure_lookups_context_t *c) const
3690
0
  {
3691
0
    struct ChainContextClosureLookupContext lookup_context = {
3692
0
      {intersects_glyph, nullptr},
3693
0
      ContextFormat::SimpleContext,
3694
0
      {nullptr, nullptr, nullptr}
3695
0
    };
3696
0
3697
0
    + hb_zip (this+coverage, ruleSet)
3698
0
    | hb_filter (*c->glyphs, hb_first)
3699
0
    | hb_map (hb_second)
3700
0
    | hb_map (hb_add (this))
3701
0
    | hb_apply ([&] (const ChainRuleSet &_) { _.closure_lookups (c, lookup_context); })
3702
0
    ;
3703
0
  }
3704
3705
0
  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
3706
3707
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
3708
0
  {
3709
0
    (this+coverage).collect_coverage (c->input);
3710
3711
0
    struct ChainContextCollectGlyphsLookupContext lookup_context = {
3712
0
      {collect_glyph},
3713
0
      {nullptr, nullptr, nullptr}
3714
0
    };
3715
3716
0
    + hb_iter (ruleSet)
3717
0
    | hb_map (hb_add (this))
3718
0
    | hb_apply ([&] (const ChainRuleSet &_) { _.collect_glyphs (c, lookup_context); })
3719
0
    ;
3720
0
  }
3721
3722
  bool would_apply (hb_would_apply_context_t *c) const
3723
0
  {
3724
0
    const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
3725
0
    struct ChainContextApplyLookupContext lookup_context = {
3726
0
      {{match_glyph, match_glyph, match_glyph}},
3727
0
      {nullptr, nullptr, nullptr}
3728
0
    };
3729
0
    return rule_set.would_apply (c, lookup_context);
3730
0
  }
3731
3732
0
  const Coverage &get_coverage () const { return this+coverage; }
3733
3734
  bool apply (hb_ot_apply_context_t *c) const
3735
0
  {
3736
0
    TRACE_APPLY (this);
3737
0
    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
3738
0
    if (index == NOT_COVERED) return_trace (false);
3739
3740
0
    const ChainRuleSet &rule_set = this+ruleSet[index];
3741
0
    struct ChainContextApplyLookupContext lookup_context = {
3742
0
      {{match_glyph, match_glyph, match_glyph}},
3743
0
      {nullptr, nullptr, nullptr}
3744
0
    };
3745
0
    return_trace (rule_set.apply (c, lookup_context));
3746
0
  }
3747
3748
  bool subset (hb_subset_context_t *c) const
3749
0
  {
3750
0
    TRACE_SUBSET (this);
3751
0
    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
3752
0
    const hb_map_t &glyph_map = *c->plan->glyph_map;
3753
0
3754
0
    auto *out = c->serializer->start_embed (*this);
3755
0
    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
3756
0
    out->format = format;
3757
0
3758
0
    const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? &c->plan->gsub_lookups : &c->plan->gpos_lookups;
3759
0
    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
3760
0
    + hb_zip (this+coverage, ruleSet)
3761
0
    | hb_filter (glyphset, hb_first)
3762
0
    | hb_filter (subset_offset_array (c, out->ruleSet, this, lookup_map), hb_second)
3763
0
    | hb_map (hb_first)
3764
0
    | hb_map (glyph_map)
3765
0
    | hb_sink (new_coverage)
3766
0
    ;
3767
0
3768
0
    out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
3769
0
    return_trace (bool (new_coverage));
3770
0
  }
3771
3772
  bool sanitize (hb_sanitize_context_t *c) const
3773
0
  {
3774
0
    TRACE_SANITIZE (this);
3775
0
    return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
3776
0
  }
3777
3778
  protected:
3779
  HBUINT16  format;     /* Format identifier--format = 1 */
3780
  typename Types::template OffsetTo<Coverage>
3781
    coverage;   /* Offset to Coverage table--from
3782
           * beginning of table */
3783
  Array16Of<typename Types::template OffsetTo<ChainRuleSet>>
3784
    ruleSet;    /* Array of ChainRuleSet tables
3785
           * ordered by Coverage Index */
3786
  public:
3787
  DEFINE_SIZE_ARRAY (2 + 2 * Types::size, ruleSet);
3788
};
3789
3790
template <typename Types>
3791
struct ChainContextFormat2_5
3792
{
3793
  using ChainRuleSet = OT::ChainRuleSet<SmallTypes>;
3794
3795
  bool intersects (const hb_set_t *glyphs) const
3796
0
  {
3797
0
    if (!(this+coverage).intersects (glyphs))
3798
0
      return false;
3799
0
3800
0
    const ClassDef &backtrack_class_def = this+backtrackClassDef;
3801
0
    const ClassDef &input_class_def = this+inputClassDef;
3802
0
    const ClassDef &lookahead_class_def = this+lookaheadClassDef;
3803
0
3804
0
    hb_map_t caches[3] = {};
3805
0
    struct ChainContextClosureLookupContext lookup_context = {
3806
0
      {intersects_class, nullptr},
3807
0
      ContextFormat::ClassBasedContext,
3808
0
      {&backtrack_class_def,
3809
0
       &input_class_def,
3810
0
       &lookahead_class_def},
3811
0
      {&caches[0], &caches[1], &caches[2]}
3812
0
    };
3813
0
3814
0
    hb_set_t retained_coverage_glyphs;
3815
0
    (this+coverage).intersect_set (*glyphs, retained_coverage_glyphs);
3816
0
3817
0
    hb_set_t coverage_glyph_classes;
3818
0
    input_class_def.intersected_classes (&retained_coverage_glyphs, &coverage_glyph_classes);
3819
0
3820
0
    return
3821
0
    + hb_iter (ruleSet)
3822
0
    | hb_map (hb_add (this))
3823
0
    | hb_enumerate
3824
0
    | hb_map ([&] (const hb_pair_t<unsigned, const ChainRuleSet &> p)
3825
0
        { return input_class_def.intersects_class (glyphs, p.first) &&
3826
0
           coverage_glyph_classes.has (p.first) &&
3827
0
           p.second.intersects (glyphs, lookup_context); })
3828
0
    | hb_any
3829
0
    ;
3830
0
  }
3831
3832
  bool may_have_non_1to1 () const
3833
0
  { return true; }
3834
3835
  void closure (hb_closure_context_t *c) const
3836
0
  {
3837
0
    if (!(this+coverage).intersects (c->glyphs))
3838
0
      return;
3839
3840
0
    hb_set_t* cur_active_glyphs = c->push_cur_active_glyphs ();
3841
0
    if (unlikely (!cur_active_glyphs)) return;
3842
0
    get_coverage ().intersect_set (c->previous_parent_active_glyphs (),
3843
0
           *cur_active_glyphs);
3844
3845
0
    const ClassDef &backtrack_class_def = this+backtrackClassDef;
3846
0
    const ClassDef &input_class_def = this+inputClassDef;
3847
0
    const ClassDef &lookahead_class_def = this+lookaheadClassDef;
3848
3849
0
    hb_map_t caches[3] = {};
3850
0
    intersected_class_cache_t intersected_cache;
3851
0
    struct ChainContextClosureLookupContext lookup_context = {
3852
0
      {intersects_class, intersected_class_glyphs},
3853
0
      ContextFormat::ClassBasedContext,
3854
0
      {&backtrack_class_def,
3855
0
       &input_class_def,
3856
0
       &lookahead_class_def},
3857
0
      {&caches[0], &caches[1], &caches[2]},
3858
0
      &intersected_cache
3859
0
    };
3860
3861
0
    + hb_enumerate (ruleSet)
3862
0
    | hb_filter ([&] (unsigned _)
3863
0
    { return input_class_def.intersects_class (&c->parent_active_glyphs (), _); },
3864
0
     hb_first)
3865
0
    | hb_apply ([&] (const hb_pair_t<unsigned, const typename Types::template OffsetTo<ChainRuleSet>&> _)
3866
0
                {
3867
0
                  const ChainRuleSet& chainrule_set = this+_.second;
3868
0
                  chainrule_set.closure (c, _.first, lookup_context);
3869
0
                })
3870
0
    ;
3871
3872
0
    c->pop_cur_done_glyphs ();
3873
0
  }
3874
3875
  void closure_lookups (hb_closure_lookups_context_t *c) const
3876
0
  {
3877
0
    if (!(this+coverage).intersects (c->glyphs))
3878
0
      return;
3879
0
3880
0
    const ClassDef &backtrack_class_def = this+backtrackClassDef;
3881
0
    const ClassDef &input_class_def = this+inputClassDef;
3882
0
    const ClassDef &lookahead_class_def = this+lookaheadClassDef;
3883
0
3884
0
    hb_map_t caches[3] = {};
3885
0
    struct ChainContextClosureLookupContext lookup_context = {
3886
0
      {intersects_class, nullptr},
3887
0
      ContextFormat::ClassBasedContext,
3888
0
      {&backtrack_class_def,
3889
0
       &input_class_def,
3890
0
       &lookahead_class_def},
3891
0
      {&caches[0], &caches[1], &caches[2]}
3892
0
    };
3893
0
3894
0
    + hb_iter (ruleSet)
3895
0
    | hb_map (hb_add (this))
3896
0
    | hb_enumerate
3897
0
    | hb_filter([&] (unsigned klass)
3898
0
    { return input_class_def.intersects_class (c->glyphs, klass); }, hb_first)
3899
0
    | hb_map (hb_second)
3900
0
    | hb_apply ([&] (const ChainRuleSet &_)
3901
0
    { _.closure_lookups (c, lookup_context); })
3902
0
    ;
3903
0
  }
3904
3905
0
  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
3906
3907
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
3908
0
  {
3909
0
    (this+coverage).collect_coverage (c->input);
3910
3911
0
    const ClassDef &backtrack_class_def = this+backtrackClassDef;
3912
0
    const ClassDef &input_class_def = this+inputClassDef;
3913
0
    const ClassDef &lookahead_class_def = this+lookaheadClassDef;
3914
3915
0
    struct ChainContextCollectGlyphsLookupContext lookup_context = {
3916
0
      {collect_class},
3917
0
      {&backtrack_class_def,
3918
0
       &input_class_def,
3919
0
       &lookahead_class_def}
3920
0
    };
3921
3922
0
    + hb_iter (ruleSet)
3923
0
    | hb_map (hb_add (this))
3924
0
    | hb_apply ([&] (const ChainRuleSet &_) { _.collect_glyphs (c, lookup_context); })
3925
0
    ;
3926
0
  }
3927
3928
  bool would_apply (hb_would_apply_context_t *c) const
3929
0
  {
3930
0
    const ClassDef &backtrack_class_def = this+backtrackClassDef;
3931
0
    const ClassDef &input_class_def = this+inputClassDef;
3932
0
    const ClassDef &lookahead_class_def = this+lookaheadClassDef;
3933
3934
0
    unsigned int index = input_class_def.get_class (c->glyphs[0]);
3935
0
    const ChainRuleSet &rule_set = this+ruleSet[index];
3936
0
    struct ChainContextApplyLookupContext lookup_context = {
3937
0
      {{match_class, match_class, match_class}},
3938
0
      {&backtrack_class_def,
3939
0
       &input_class_def,
3940
0
       &lookahead_class_def}
3941
0
    };
3942
0
    return rule_set.would_apply (c, lookup_context);
3943
0
  }
3944
3945
0
  const Coverage &get_coverage () const { return this+coverage; }
3946
3947
  unsigned cache_cost () const
3948
0
  {
3949
0
    return (this+inputClassDef).cost () + (this+lookaheadClassDef).cost ();
3950
0
  }
3951
  static bool cache_func (hb_ot_apply_context_t *c, hb_ot_subtable_cache_op_t op)
3952
0
  {
3953
0
    return context_cache_func (c, op);
3954
0
  }
3955
3956
  struct external_cache_t
3957
  {
3958
    hb_ot_layout_binary_cache_t coverage;
3959
  };
3960
  void *external_cache_create () const
3961
0
  {
3962
0
    external_cache_t *cache = (external_cache_t *) hb_malloc (sizeof (external_cache_t));
3963
0
    if (likely (cache))
3964
0
    {
3965
0
      cache->coverage.clear ();
3966
0
    }
3967
0
    return cache;
3968
0
  }
3969
0
  bool apply_cached (hb_ot_apply_context_t *c, void *external_cache) const { return _apply (c, true, external_cache); }
3970
0
  bool apply (hb_ot_apply_context_t *c, void *external_cache) const { return _apply (c, false, external_cache); }
3971
  bool _apply (hb_ot_apply_context_t *c, bool cached, void *external_cache) const
3972
0
  {
3973
0
    TRACE_APPLY (this);
3974
0
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
3975
0
    external_cache_t *cache = (external_cache_t *) external_cache;
3976
0
    unsigned int index = (this+coverage).get_coverage_binary (c->buffer->cur().codepoint, cache ? &cache->coverage : nullptr);
3977
#else
3978
    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
3979
#endif
3980
0
    if (index == NOT_COVERED) return_trace (false);
3981
3982
0
    const ClassDef &backtrack_class_def = this+backtrackClassDef;
3983
0
    const ClassDef &input_class_def = this+inputClassDef;
3984
0
    const ClassDef &lookahead_class_def = this+lookaheadClassDef;
3985
3986
    /* match_class_caches1 is slightly faster. Use it for lookahead,
3987
     * which is typically longer. */
3988
0
    struct ChainContextApplyLookupContext lookup_context = {
3989
0
      {{cached && &backtrack_class_def == &lookahead_class_def ? match_class_cached1 : match_class,
3990
0
        cached ? match_class_cached2 : match_class,
3991
0
        cached ? match_class_cached1 : match_class}},
3992
0
      {&backtrack_class_def,
3993
0
       &input_class_def,
3994
0
       &lookahead_class_def}
3995
0
    };
3996
3997
0
    index = cached
3998
0
         ? get_class_cached2 (input_class_def, c->buffer->cur())
3999
0
          : input_class_def.get_class (c->buffer->cur().codepoint);
4000
0
    const ChainRuleSet &rule_set = this+ruleSet[index];
4001
0
    return_trace (rule_set.apply (c, lookup_context));
4002
0
  }
4003
4004
  bool subset (hb_subset_context_t *c) const
4005
0
  {
4006
0
    TRACE_SUBSET (this);
4007
0
    auto *out = c->serializer->start_embed (*this);
4008
0
    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
4009
0
    out->format = format;
4010
0
    out->coverage.serialize_subset (c, coverage, this);
4011
0
4012
0
    hb_map_t backtrack_klass_map;
4013
0
    hb_map_t input_klass_map;
4014
0
    hb_map_t lookahead_klass_map;
4015
0
4016
0
    out->backtrackClassDef.serialize_subset (c, backtrackClassDef, this, &backtrack_klass_map);
4017
0
    // TODO: subset inputClassDef based on glyphs survived in Coverage subsetting
4018
0
    out->inputClassDef.serialize_subset (c, inputClassDef, this, &input_klass_map);
4019
0
    out->lookaheadClassDef.serialize_subset (c, lookaheadClassDef, this, &lookahead_klass_map);
4020
0
4021
0
    if (unlikely (!c->serializer->propagate_error (backtrack_klass_map,
4022
0
               input_klass_map,
4023
0
               lookahead_klass_map)))
4024
0
      return_trace (false);
4025
0
4026
0
    const hb_set_t* glyphset = c->plan->glyphset_gsub ();
4027
0
    hb_set_t retained_coverage_glyphs;
4028
0
    (this+coverage).intersect_set (*glyphset, retained_coverage_glyphs);
4029
0
4030
0
    hb_set_t coverage_glyph_classes;
4031
0
    (this+inputClassDef).intersected_classes (&retained_coverage_glyphs, &coverage_glyph_classes);
4032
0
4033
0
    int non_zero_index = -1, index = 0;
4034
0
    bool ret = true;
4035
0
    const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? &c->plan->gsub_lookups : &c->plan->gpos_lookups;
4036
0
    auto last_non_zero = c->serializer->snapshot ();
4037
0
    for (const auto& _ : + hb_enumerate (ruleSet)
4038
0
       | hb_filter (input_klass_map, hb_first))
4039
0
    {
4040
0
      auto *o = out->ruleSet.serialize_append (c->serializer);
4041
0
      if (unlikely (!o))
4042
0
      {
4043
0
  ret = false;
4044
0
  break;
4045
0
      }
4046
0
      if (coverage_glyph_classes.has (_.first) &&
4047
0
          o->serialize_subset (c, _.second, this,
4048
0
             lookup_map,
4049
0
             &backtrack_klass_map,
4050
0
             &input_klass_map,
4051
0
             &lookahead_klass_map))
4052
0
      {
4053
0
        last_non_zero = c->serializer->snapshot ();
4054
0
  non_zero_index = index;
4055
0
      }
4056
0
4057
0
      index++;
4058
0
    }
4059
0
4060
0
    if (!ret || non_zero_index == -1) return_trace (false);
4061
0
4062
0
    // prune empty trailing ruleSets
4063
0
    if (index > non_zero_index) {
4064
0
      c->serializer->revert (last_non_zero);
4065
0
      out->ruleSet.len = non_zero_index + 1;
4066
0
    }
4067
0
4068
0
    return_trace (bool (out->ruleSet));
4069
0
  }
4070
4071
  bool sanitize (hb_sanitize_context_t *c) const
4072
0
  {
4073
0
    TRACE_SANITIZE (this);
4074
0
    return_trace (coverage.sanitize (c, this) &&
4075
0
      backtrackClassDef.sanitize (c, this) &&
4076
0
      inputClassDef.sanitize (c, this) &&
4077
0
      lookaheadClassDef.sanitize (c, this) &&
4078
0
      ruleSet.sanitize (c, this));
4079
0
  }
4080
4081
  protected:
4082
  HBUINT16  format;     /* Format identifier--format = 2 */
4083
  typename Types::template OffsetTo<Coverage>
4084
    coverage;   /* Offset to Coverage table--from
4085
           * beginning of table */
4086
  typename Types::template OffsetTo<ClassDef>
4087
    backtrackClassDef;  /* Offset to glyph ClassDef table
4088
           * containing backtrack sequence
4089
           * data--from beginning of table */
4090
  typename Types::template OffsetTo<ClassDef>
4091
    inputClassDef;    /* Offset to glyph ClassDef
4092
           * table containing input sequence
4093
           * data--from beginning of table */
4094
  typename Types::template OffsetTo<ClassDef>
4095
    lookaheadClassDef;  /* Offset to glyph ClassDef table
4096
           * containing lookahead sequence
4097
           * data--from beginning of table */
4098
  Array16Of<typename Types::template OffsetTo<ChainRuleSet>>
4099
    ruleSet;    /* Array of ChainRuleSet tables
4100
           * ordered by class */
4101
  public:
4102
  DEFINE_SIZE_ARRAY (4 + 4 * Types::size, ruleSet);
4103
};
4104
4105
struct ChainContextFormat3
4106
{
4107
  using RuleSet = OT::RuleSet<SmallTypes>;
4108
4109
  bool intersects (const hb_set_t *glyphs) const
4110
0
  {
4111
0
    const auto &input = StructAfter<decltype (inputX)> (backtrack);
4112
0
4113
0
    if (!(this+input[0]).intersects (glyphs))
4114
0
      return false;
4115
0
4116
0
    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
4117
0
    struct ChainContextClosureLookupContext lookup_context = {
4118
0
      {intersects_coverage, nullptr},
4119
0
      ContextFormat::CoverageBasedContext,
4120
0
      {this, this, this}
4121
0
    };
4122
0
    return chain_context_intersects (glyphs,
4123
0
             backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
4124
0
             input.len, (const HBUINT16 *) input.arrayZ + 1,
4125
0
             lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
4126
0
             lookup_context);
4127
0
  }
4128
4129
  bool may_have_non_1to1 () const
4130
0
  { return true; }
4131
4132
  void closure (hb_closure_context_t *c) const
4133
0
  {
4134
0
    const auto &input = StructAfter<decltype (inputX)> (backtrack);
4135
4136
0
    if (!(this+input[0]).intersects (c->glyphs))
4137
0
      return;
4138
4139
0
    hb_set_t* cur_active_glyphs = c->push_cur_active_glyphs ();
4140
0
    if (unlikely (!cur_active_glyphs))
4141
0
      return;
4142
0
    get_coverage ().intersect_set (c->previous_parent_active_glyphs (),
4143
0
           *cur_active_glyphs);
4144
4145
0
    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
4146
0
    const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
4147
0
    struct ChainContextClosureLookupContext lookup_context = {
4148
0
      {intersects_coverage, intersected_coverage_glyphs},
4149
0
      ContextFormat::CoverageBasedContext,
4150
0
      {this, this, this}
4151
0
    };
4152
0
    chain_context_closure_lookup (c,
4153
0
          backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
4154
0
          input.len, (const HBUINT16 *) input.arrayZ + 1,
4155
0
          lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
4156
0
          lookup.len, lookup.arrayZ,
4157
0
          0, lookup_context);
4158
4159
0
    c->pop_cur_done_glyphs ();
4160
0
  }
4161
4162
  void closure_lookups (hb_closure_lookups_context_t *c) const
4163
0
  {
4164
0
    if (!intersects (c->glyphs))
4165
0
      return;
4166
0
4167
0
    const auto &input = StructAfter<decltype (inputX)> (backtrack);
4168
0
    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
4169
0
    const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
4170
0
    recurse_lookups (c, lookup.len, lookup.arrayZ);
4171
0
  }
4172
4173
0
  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
4174
4175
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
4176
0
  {
4177
0
    const auto &input = StructAfter<decltype (inputX)> (backtrack);
4178
4179
0
    (this+input[0]).collect_coverage (c->input);
4180
4181
0
    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
4182
0
    const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
4183
4184
0
    struct ChainContextCollectGlyphsLookupContext lookup_context = {
4185
0
      {collect_coverage},
4186
0
      {this, this, this}
4187
0
    };
4188
0
    chain_context_collect_glyphs_lookup (c,
4189
0
           backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
4190
0
           input.len, (const HBUINT16 *) input.arrayZ + 1,
4191
0
           lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
4192
0
           lookup.len, lookup.arrayZ,
4193
0
           lookup_context);
4194
0
  }
4195
4196
  bool would_apply (hb_would_apply_context_t *c) const
4197
0
  {
4198
0
    const auto &input = StructAfter<decltype (inputX)> (backtrack);
4199
0
    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
4200
0
    const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
4201
0
    struct ChainContextApplyLookupContext lookup_context = {
4202
0
      {{match_coverage, match_coverage, match_coverage}},
4203
0
      {this, this, this}
4204
0
    };
4205
0
    return chain_context_would_apply_lookup (c,
4206
0
               backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
4207
0
               input.len, (const HBUINT16 *) input.arrayZ + 1,
4208
0
               lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
4209
0
               lookup.len, lookup.arrayZ, lookup_context);
4210
0
  }
4211
4212
  const Coverage &get_coverage () const
4213
902
  {
4214
902
    const auto &input = StructAfter<decltype (inputX)> (backtrack);
4215
902
    return this+input[0];
4216
902
  }
4217
4218
  bool apply (hb_ot_apply_context_t *c) const
4219
1.32M
  {
4220
1.32M
    TRACE_APPLY (this);
4221
1.32M
    const auto &input = StructAfter<decltype (inputX)> (backtrack);
4222
4223
1.32M
    unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint);
4224
1.32M
    if (index == NOT_COVERED) return_trace (false);
4225
4226
1.02M
    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
4227
1.02M
    const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
4228
1.02M
    struct ChainContextApplyLookupContext lookup_context = {
4229
1.02M
      {{match_coverage, match_coverage, match_coverage}},
4230
1.02M
      {this, this, this}
4231
1.02M
    };
4232
1.02M
    return_trace (chain_context_apply_lookup (c,
4233
1.32M
                backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
4234
1.32M
                input.len, (const HBUINT16 *) input.arrayZ + 1,
4235
1.32M
                lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
4236
1.32M
                lookup.len, lookup.arrayZ, lookup_context));
4237
1.32M
  }
4238
4239
  template<typename Iterator,
4240
     hb_requires (hb_is_iterator (Iterator))>
4241
  bool serialize_coverage_offsets (hb_subset_context_t *c, Iterator it, const void* base) const
4242
0
  {
4243
0
    TRACE_SERIALIZE (this);
4244
0
    auto *out = c->serializer->start_embed<Array16OfOffset16To<Coverage>> ();
4245
0
4246
0
    if (unlikely (!c->serializer->allocate_size<HBUINT16> (HBUINT16::static_size)))
4247
0
      return_trace (false);
4248
0
4249
0
    for (auto& offset : it) {
4250
0
      auto *o = out->serialize_append (c->serializer);
4251
0
      if (unlikely (!o) || !o->serialize_subset (c, offset, base))
4252
0
        return_trace (false);
4253
0
    }
4254
0
4255
0
    return_trace (true);
4256
0
  }
4257
4258
  bool subset (hb_subset_context_t *c) const
4259
0
  {
4260
0
    TRACE_SUBSET (this);
4261
0
4262
0
    if (unlikely (!c->serializer->embed (this->format))) return_trace (false);
4263
0
4264
0
    if (!serialize_coverage_offsets (c, backtrack.iter (), this))
4265
0
      return_trace (false);
4266
0
4267
0
    const auto &input = StructAfter<decltype (inputX)> (backtrack);
4268
0
    if (!serialize_coverage_offsets (c, input.iter (), this))
4269
0
      return_trace (false);
4270
0
4271
0
    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
4272
0
    if (!serialize_coverage_offsets (c, lookahead.iter (), this))
4273
0
      return_trace (false);
4274
0
4275
0
    const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
4276
0
    const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? &c->plan->gsub_lookups : &c->plan->gpos_lookups;
4277
0
4278
0
    HBUINT16 *lookupCount = c->serializer->copy<HBUINT16> (lookup.len);
4279
0
    if (!lookupCount) return_trace (false);
4280
0
4281
0
    unsigned count = serialize_lookuprecord_array (c->serializer, lookup.as_array (), lookup_map);
4282
0
    return_trace (c->serializer->check_assign (*lookupCount, count, HB_SERIALIZE_ERROR_INT_OVERFLOW));
4283
0
  }
4284
4285
  bool sanitize (hb_sanitize_context_t *c) const
4286
2.58k
  {
4287
2.58k
    TRACE_SANITIZE (this);
4288
2.58k
    if (unlikely (!backtrack.sanitize (c, this))) return_trace (false);
4289
2.58k
    hb_barrier ();
4290
2.58k
    const auto &input = StructAfter<decltype (inputX)> (backtrack);
4291
2.58k
    if (unlikely (!input.sanitize (c, this))) return_trace (false);
4292
2.58k
    hb_barrier ();
4293
2.58k
    if (unlikely (!input.len)) return_trace (false); /* To be consistent with Context. */
4294
2.58k
    const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
4295
2.58k
    if (unlikely (!lookahead.sanitize (c, this))) return_trace (false);
4296
2.58k
    hb_barrier ();
4297
2.58k
    const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
4298
2.58k
    return_trace (likely (lookup.sanitize (c)));
4299
2.58k
  }
4300
4301
  protected:
4302
  HBUINT16  format;     /* Format identifier--format = 3 */
4303
  Array16OfOffset16To<Coverage>
4304
    backtrack;    /* Array of coverage tables
4305
           * in backtracking sequence, in  glyph
4306
           * sequence order */
4307
  Array16OfOffset16To<Coverage>
4308
    inputX    ; /* Array of coverage
4309
           * tables in input sequence, in glyph
4310
           * sequence order */
4311
  Array16OfOffset16To<Coverage>
4312
    lookaheadX;   /* Array of coverage tables
4313
           * in lookahead sequence, in glyph
4314
           * sequence order */
4315
  Array16Of<LookupRecord>
4316
    lookupX;    /* Array of LookupRecords--in
4317
           * design order) */
4318
  public:
4319
  DEFINE_SIZE_MIN (10);
4320
};
4321
4322
struct ChainContext
4323
{
4324
  template <typename context_t, typename ...Ts>
4325
  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
4326
3.48k
  {
4327
3.48k
    if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value ();
4328
3.48k
    TRACE_DISPATCH (this, u.format.v);
4329
3.48k
    switch (u.format.v) {
4330
0
    case 1: hb_barrier (); return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
4331
0
    case 2: hb_barrier (); return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
4332
3.48k
    case 3: hb_barrier (); return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
4333
#ifndef HB_NO_BEYOND_64K
4334
    case 4: hb_barrier (); return_trace (c->dispatch (u.format4, std::forward<Ts> (ds)...));
4335
    case 5: hb_barrier (); return_trace (c->dispatch (u.format5, std::forward<Ts> (ds)...));
4336
#endif
4337
0
    default:return_trace (c->default_return_value ());
4338
3.48k
    }
4339
3.48k
  }
hb_sanitize_context_t::return_t OT::ChainContext::dispatch<hb_sanitize_context_t>(hb_sanitize_context_t*) const
Line
Count
Source
4326
2.58k
  {
4327
2.58k
    if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value ();
4328
2.58k
    TRACE_DISPATCH (this, u.format.v);
4329
2.58k
    switch (u.format.v) {
4330
0
    case 1: hb_barrier (); return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
4331
0
    case 2: hb_barrier (); return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
4332
2.58k
    case 3: hb_barrier (); return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
4333
#ifndef HB_NO_BEYOND_64K
4334
    case 4: hb_barrier (); return_trace (c->dispatch (u.format4, std::forward<Ts> (ds)...));
4335
    case 5: hb_barrier (); return_trace (c->dispatch (u.format5, std::forward<Ts> (ds)...));
4336
#endif
4337
0
    default:return_trace (c->default_return_value ());
4338
2.58k
    }
4339
2.58k
  }
Unexecuted instantiation: OT::hb_intersects_context_t::return_t OT::ChainContext::dispatch<OT::hb_intersects_context_t>(OT::hb_intersects_context_t*) const
Unexecuted instantiation: OT::hb_ot_apply_context_t::return_t OT::ChainContext::dispatch<OT::hb_ot_apply_context_t>(OT::hb_ot_apply_context_t*) const
Unexecuted instantiation: OT::hb_collect_glyphs_context_t::return_t OT::ChainContext::dispatch<OT::hb_collect_glyphs_context_t>(OT::hb_collect_glyphs_context_t*) const
Unexecuted instantiation: OT::hb_closure_lookups_context_t::return_t OT::ChainContext::dispatch<OT::hb_closure_lookups_context_t>(OT::hb_closure_lookups_context_t*) const
Unexecuted instantiation: hb_subset_context_t::return_t OT::ChainContext::dispatch<hb_subset_context_t>(hb_subset_context_t*) const
Unexecuted instantiation: OT::hb_collect_variation_indices_context_t::return_t OT::ChainContext::dispatch<OT::hb_collect_variation_indices_context_t>(OT::hb_collect_variation_indices_context_t*) const
OT::hb_accelerate_subtables_context_t::return_t OT::ChainContext::dispatch<OT::hb_accelerate_subtables_context_t>(OT::hb_accelerate_subtables_context_t*) const
Line
Count
Source
4326
902
  {
4327
902
    if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value ();
4328
902
    TRACE_DISPATCH (this, u.format.v);
4329
902
    switch (u.format.v) {
4330
0
    case 1: hb_barrier (); return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
4331
0
    case 2: hb_barrier (); return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
4332
902
    case 3: hb_barrier (); return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
4333
#ifndef HB_NO_BEYOND_64K
4334
    case 4: hb_barrier (); return_trace (c->dispatch (u.format4, std::forward<Ts> (ds)...));
4335
    case 5: hb_barrier (); return_trace (c->dispatch (u.format5, std::forward<Ts> (ds)...));
4336
#endif
4337
0
    default:return_trace (c->default_return_value ());
4338
902
    }
4339
902
  }
Unexecuted instantiation: OT::hb_have_non_1to1_context_t::return_t OT::ChainContext::dispatch<OT::hb_have_non_1to1_context_t>(OT::hb_have_non_1to1_context_t*) const
Unexecuted instantiation: OT::hb_closure_context_t::return_t OT::ChainContext::dispatch<OT::hb_closure_context_t>(OT::hb_closure_context_t*) const
Unexecuted instantiation: OT::hb_would_apply_context_t::return_t OT::ChainContext::dispatch<OT::hb_would_apply_context_t>(OT::hb_would_apply_context_t*) const
Unexecuted instantiation: hb_get_glyph_alternates_dispatch_t::return_t OT::ChainContext::dispatch<hb_get_glyph_alternates_dispatch_t, unsigned int&, unsigned int&, unsigned int*&, unsigned int*&>(hb_get_glyph_alternates_dispatch_t*, unsigned int&, unsigned int&, unsigned int*&, unsigned int*&) const
Unexecuted instantiation: hb_collect_glyph_alternates_dispatch_t::return_t OT::ChainContext::dispatch<hb_collect_glyph_alternates_dispatch_t, hb_map_t*&, hb_map_t*&>(hb_collect_glyph_alternates_dispatch_t*, hb_map_t*&, hb_map_t*&) const
Unexecuted instantiation: hb_position_single_dispatch_t::return_t OT::ChainContext::dispatch<hb_position_single_dispatch_t, hb_font_t*&, hb_blob_t*&, hb_direction_t&, unsigned int&, hb_glyph_position_t&>(hb_position_single_dispatch_t*, hb_font_t*&, hb_blob_t*&, hb_direction_t&, unsigned int&, hb_glyph_position_t&) const
4340
4341
  protected:
4342
  union {
4343
  struct { HBUINT16 v; }    format; /* Format identifier */
4344
  ChainContextFormat1_4<SmallTypes> format1;
4345
  ChainContextFormat2_5<SmallTypes> format2;
4346
  ChainContextFormat3     format3;
4347
#ifndef HB_NO_BEYOND_64K
4348
  ChainContextFormat1_4<MediumTypes>  format4;
4349
  ChainContextFormat2_5<MediumTypes>  format5;
4350
#endif
4351
  } u;
4352
};
4353
4354
4355
template <typename T>
4356
struct ExtensionFormat1
4357
{
4358
0
  unsigned int get_type () const { return extensionLookupType; }
Unexecuted instantiation: OT::ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>::get_type() const
Unexecuted instantiation: OT::ExtensionFormat1<OT::Layout::GPOS_impl::ExtensionPos>::get_type() const
4359
4360
  template <typename X>
4361
  const X& get_subtable () const
4362
0
  { return this + reinterpret_cast<const Offset32To<typename T::SubTable> &> (extensionOffset); }
Unexecuted instantiation: OT::Layout::GSUB_impl::SubstLookupSubTable const& OT::ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>::get_subtable<OT::Layout::GSUB_impl::SubstLookupSubTable>() const
Unexecuted instantiation: OT::Layout::GPOS_impl::PosLookupSubTable const& OT::ExtensionFormat1<OT::Layout::GPOS_impl::ExtensionPos>::get_subtable<OT::Layout::GPOS_impl::PosLookupSubTable>() const
4363
4364
  template <typename context_t, typename ...Ts>
4365
  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
4366
0
  {
4367
0
    if (unlikely (!c->may_dispatch (this, this))) return c->no_dispatch_return_value ();
4368
0
    TRACE_DISPATCH (this, format);
4369
0
    return_trace (get_subtable<typename T::SubTable> ().dispatch (c, get_type (), std::forward<Ts> (ds)...));
4370
0
  }
Unexecuted instantiation: hb_sanitize_context_t::return_t OT::ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>::dispatch<hb_sanitize_context_t>(hb_sanitize_context_t*) const
Unexecuted instantiation: OT::hb_intersects_context_t::return_t OT::ExtensionFormat1<OT::Layout::GPOS_impl::ExtensionPos>::dispatch<OT::hb_intersects_context_t>(OT::hb_intersects_context_t*) const
Unexecuted instantiation: OT::hb_ot_apply_context_t::return_t OT::ExtensionFormat1<OT::Layout::GPOS_impl::ExtensionPos>::dispatch<OT::hb_ot_apply_context_t>(OT::hb_ot_apply_context_t*) const
Unexecuted instantiation: OT::hb_collect_glyphs_context_t::return_t OT::ExtensionFormat1<OT::Layout::GPOS_impl::ExtensionPos>::dispatch<OT::hb_collect_glyphs_context_t>(OT::hb_collect_glyphs_context_t*) const
Unexecuted instantiation: OT::hb_closure_lookups_context_t::return_t OT::ExtensionFormat1<OT::Layout::GPOS_impl::ExtensionPos>::dispatch<OT::hb_closure_lookups_context_t>(OT::hb_closure_lookups_context_t*) const
Unexecuted instantiation: hb_sanitize_context_t::return_t OT::ExtensionFormat1<OT::Layout::GPOS_impl::ExtensionPos>::dispatch<hb_sanitize_context_t>(hb_sanitize_context_t*) const
Unexecuted instantiation: OT::hb_collect_variation_indices_context_t::return_t OT::ExtensionFormat1<OT::Layout::GPOS_impl::ExtensionPos>::dispatch<OT::hb_collect_variation_indices_context_t>(OT::hb_collect_variation_indices_context_t*) const
Unexecuted instantiation: OT::hb_accelerate_subtables_context_t::return_t OT::ExtensionFormat1<OT::Layout::GPOS_impl::ExtensionPos>::dispatch<OT::hb_accelerate_subtables_context_t>(OT::hb_accelerate_subtables_context_t*) const
Unexecuted instantiation: OT::hb_intersects_context_t::return_t OT::ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>::dispatch<OT::hb_intersects_context_t>(OT::hb_intersects_context_t*) const
Unexecuted instantiation: OT::hb_have_non_1to1_context_t::return_t OT::ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>::dispatch<OT::hb_have_non_1to1_context_t>(OT::hb_have_non_1to1_context_t*) const
Unexecuted instantiation: OT::hb_ot_apply_context_t::return_t OT::ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>::dispatch<OT::hb_ot_apply_context_t>(OT::hb_ot_apply_context_t*) const
Unexecuted instantiation: OT::hb_closure_context_t::return_t OT::ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>::dispatch<OT::hb_closure_context_t>(OT::hb_closure_context_t*) const
Unexecuted instantiation: OT::hb_closure_lookups_context_t::return_t OT::ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>::dispatch<OT::hb_closure_lookups_context_t>(OT::hb_closure_lookups_context_t*) const
Unexecuted instantiation: OT::hb_collect_glyphs_context_t::return_t OT::ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>::dispatch<OT::hb_collect_glyphs_context_t>(OT::hb_collect_glyphs_context_t*) const
Unexecuted instantiation: OT::hb_would_apply_context_t::return_t OT::ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>::dispatch<OT::hb_would_apply_context_t>(OT::hb_would_apply_context_t*) const
Unexecuted instantiation: OT::hb_accelerate_subtables_context_t::return_t OT::ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>::dispatch<OT::hb_accelerate_subtables_context_t>(OT::hb_accelerate_subtables_context_t*) const
Unexecuted instantiation: hb_get_glyph_alternates_dispatch_t::return_t OT::ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>::dispatch<hb_get_glyph_alternates_dispatch_t, unsigned int&, unsigned int&, unsigned int*&, unsigned int*&>(hb_get_glyph_alternates_dispatch_t*, unsigned int&, unsigned int&, unsigned int*&, unsigned int*&) const
Unexecuted instantiation: hb_collect_glyph_alternates_dispatch_t::return_t OT::ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>::dispatch<hb_collect_glyph_alternates_dispatch_t, hb_map_t*&, hb_map_t*&>(hb_collect_glyph_alternates_dispatch_t*, hb_map_t*&, hb_map_t*&) const
Unexecuted instantiation: hb_position_single_dispatch_t::return_t OT::ExtensionFormat1<OT::Layout::GPOS_impl::ExtensionPos>::dispatch<hb_position_single_dispatch_t, hb_font_t*&, hb_blob_t*&, hb_direction_t&, unsigned int&, hb_glyph_position_t&>(hb_position_single_dispatch_t*, hb_font_t*&, hb_blob_t*&, hb_direction_t&, unsigned int&, hb_glyph_position_t&) const
4371
4372
  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
4373
  { dispatch (c); }
4374
4375
  /* This is called from may_dispatch() above with hb_sanitize_context_t. */
4376
  bool sanitize (hb_sanitize_context_t *c) const
4377
0
  {
4378
0
    TRACE_SANITIZE (this);
4379
0
    return_trace (c->check_struct (this) &&
4380
0
      hb_barrier () &&
4381
0
      extensionLookupType != T::SubTable::Extension);
4382
0
  }
Unexecuted instantiation: OT::ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>::sanitize(hb_sanitize_context_t*) const
Unexecuted instantiation: OT::ExtensionFormat1<OT::Layout::GPOS_impl::ExtensionPos>::sanitize(hb_sanitize_context_t*) const
4383
4384
  bool subset (hb_subset_context_t *c) const
4385
0
  {
4386
0
    TRACE_SUBSET (this);
4387
0
4388
0
    auto *out = c->serializer->start_embed (this);
4389
0
    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
4390
0
4391
0
    out->format = format;
4392
0
    out->extensionLookupType = extensionLookupType;
4393
0
4394
0
    const auto& src_offset =
4395
0
        reinterpret_cast<const Offset32To<typename T::SubTable> &> (extensionOffset);
4396
0
    auto& dest_offset =
4397
0
        reinterpret_cast<Offset32To<typename T::SubTable> &> (out->extensionOffset);
4398
0
4399
0
    return_trace (dest_offset.serialize_subset (c, src_offset, this, get_type ()));
4400
0
  }
Unexecuted instantiation: OT::ExtensionFormat1<OT::Layout::GPOS_impl::ExtensionPos>::subset(hb_subset_context_t*) const
Unexecuted instantiation: OT::ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>::subset(hb_subset_context_t*) const
4401
4402
  protected:
4403
  HBUINT16  format;     /* Format identifier. Set to 1. */
4404
  HBUINT16  extensionLookupType;  /* Lookup type of subtable referenced
4405
           * by ExtensionOffset (i.e. the
4406
           * extension subtable). */
4407
  Offset32  extensionOffset;  /* Offset to the extension subtable,
4408
           * of lookup type subtable. */
4409
  public:
4410
  DEFINE_SIZE_STATIC (8);
4411
};
4412
4413
template <typename T>
4414
struct Extension
4415
{
4416
  unsigned int get_type () const
4417
0
  {
4418
0
    switch (u.format.v) {
4419
0
    case 1: hb_barrier (); return u.format1.get_type ();
4420
0
    default:return 0;
4421
0
    }
4422
0
  }
Unexecuted instantiation: OT::Extension<OT::Layout::GSUB_impl::ExtensionSubst>::get_type() const
Unexecuted instantiation: OT::Extension<OT::Layout::GPOS_impl::ExtensionPos>::get_type() const
4423
  template <typename X>
4424
  const X& get_subtable () const
4425
  {
4426
    switch (u.format.v) {
4427
    case 1: hb_barrier (); return u.format1.template get_subtable<typename T::SubTable> ();
4428
    default:return Null (typename T::SubTable);
4429
    }
4430
  }
4431
4432
  // Specialization of dispatch for subset. dispatch() normally just
4433
  // dispatches to the sub table this points too, but for subset
4434
  // we need to run subset on this subtable too.
4435
  template <typename ...Ts>
4436
  typename hb_subset_context_t::return_t dispatch (hb_subset_context_t *c, Ts&&... ds) const
4437
0
  {
4438
0
    switch (u.format.v) {
4439
0
    case 1: hb_barrier (); return u.format1.subset (c);
4440
0
    default: return c->default_return_value ();
4441
0
    }
4442
0
  }
Unexecuted instantiation: bool OT::Extension<OT::Layout::GPOS_impl::ExtensionPos>::dispatch<>(hb_subset_context_t*) const
Unexecuted instantiation: bool OT::Extension<OT::Layout::GSUB_impl::ExtensionSubst>::dispatch<>(hb_subset_context_t*) const
4443
4444
  template <typename context_t, typename ...Ts>
4445
  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
4446
0
  {
4447
0
    if (unlikely (!c->may_dispatch (this, &u.format.v))) return c->no_dispatch_return_value ();
4448
0
    TRACE_DISPATCH (this, u.format.v);
4449
0
    switch (u.format.v) {
4450
0
    case 1: hb_barrier (); return_trace (u.format1.dispatch (c, std::forward<Ts> (ds)...));
4451
0
    default:return_trace (c->default_return_value ());
4452
0
    }
4453
0
  }
Unexecuted instantiation: hb_sanitize_context_t::return_t OT::Extension<OT::Layout::GSUB_impl::ExtensionSubst>::dispatch<hb_sanitize_context_t>(hb_sanitize_context_t*) const
Unexecuted instantiation: OT::hb_intersects_context_t::return_t OT::Extension<OT::Layout::GPOS_impl::ExtensionPos>::dispatch<OT::hb_intersects_context_t>(OT::hb_intersects_context_t*) const
Unexecuted instantiation: OT::hb_ot_apply_context_t::return_t OT::Extension<OT::Layout::GPOS_impl::ExtensionPos>::dispatch<OT::hb_ot_apply_context_t>(OT::hb_ot_apply_context_t*) const
Unexecuted instantiation: OT::hb_collect_glyphs_context_t::return_t OT::Extension<OT::Layout::GPOS_impl::ExtensionPos>::dispatch<OT::hb_collect_glyphs_context_t>(OT::hb_collect_glyphs_context_t*) const
Unexecuted instantiation: OT::hb_closure_lookups_context_t::return_t OT::Extension<OT::Layout::GPOS_impl::ExtensionPos>::dispatch<OT::hb_closure_lookups_context_t>(OT::hb_closure_lookups_context_t*) const
Unexecuted instantiation: hb_sanitize_context_t::return_t OT::Extension<OT::Layout::GPOS_impl::ExtensionPos>::dispatch<hb_sanitize_context_t>(hb_sanitize_context_t*) const
Unexecuted instantiation: OT::hb_collect_variation_indices_context_t::return_t OT::Extension<OT::Layout::GPOS_impl::ExtensionPos>::dispatch<OT::hb_collect_variation_indices_context_t>(OT::hb_collect_variation_indices_context_t*) const
Unexecuted instantiation: OT::hb_accelerate_subtables_context_t::return_t OT::Extension<OT::Layout::GPOS_impl::ExtensionPos>::dispatch<OT::hb_accelerate_subtables_context_t>(OT::hb_accelerate_subtables_context_t*) const
Unexecuted instantiation: OT::hb_intersects_context_t::return_t OT::Extension<OT::Layout::GSUB_impl::ExtensionSubst>::dispatch<OT::hb_intersects_context_t>(OT::hb_intersects_context_t*) const
Unexecuted instantiation: OT::hb_have_non_1to1_context_t::return_t OT::Extension<OT::Layout::GSUB_impl::ExtensionSubst>::dispatch<OT::hb_have_non_1to1_context_t>(OT::hb_have_non_1to1_context_t*) const
Unexecuted instantiation: OT::hb_ot_apply_context_t::return_t OT::Extension<OT::Layout::GSUB_impl::ExtensionSubst>::dispatch<OT::hb_ot_apply_context_t>(OT::hb_ot_apply_context_t*) const
Unexecuted instantiation: OT::hb_closure_context_t::return_t OT::Extension<OT::Layout::GSUB_impl::ExtensionSubst>::dispatch<OT::hb_closure_context_t>(OT::hb_closure_context_t*) const
Unexecuted instantiation: OT::hb_closure_lookups_context_t::return_t OT::Extension<OT::Layout::GSUB_impl::ExtensionSubst>::dispatch<OT::hb_closure_lookups_context_t>(OT::hb_closure_lookups_context_t*) const
Unexecuted instantiation: OT::hb_collect_glyphs_context_t::return_t OT::Extension<OT::Layout::GSUB_impl::ExtensionSubst>::dispatch<OT::hb_collect_glyphs_context_t>(OT::hb_collect_glyphs_context_t*) const
Unexecuted instantiation: OT::hb_would_apply_context_t::return_t OT::Extension<OT::Layout::GSUB_impl::ExtensionSubst>::dispatch<OT::hb_would_apply_context_t>(OT::hb_would_apply_context_t*) const
Unexecuted instantiation: OT::hb_accelerate_subtables_context_t::return_t OT::Extension<OT::Layout::GSUB_impl::ExtensionSubst>::dispatch<OT::hb_accelerate_subtables_context_t>(OT::hb_accelerate_subtables_context_t*) const
Unexecuted instantiation: hb_get_glyph_alternates_dispatch_t::return_t OT::Extension<OT::Layout::GSUB_impl::ExtensionSubst>::dispatch<hb_get_glyph_alternates_dispatch_t, unsigned int&, unsigned int&, unsigned int*&, unsigned int*&>(hb_get_glyph_alternates_dispatch_t*, unsigned int&, unsigned int&, unsigned int*&, unsigned int*&) const
Unexecuted instantiation: hb_collect_glyph_alternates_dispatch_t::return_t OT::Extension<OT::Layout::GSUB_impl::ExtensionSubst>::dispatch<hb_collect_glyph_alternates_dispatch_t, hb_map_t*&, hb_map_t*&>(hb_collect_glyph_alternates_dispatch_t*, hb_map_t*&, hb_map_t*&) const
Unexecuted instantiation: hb_position_single_dispatch_t::return_t OT::Extension<OT::Layout::GPOS_impl::ExtensionPos>::dispatch<hb_position_single_dispatch_t, hb_font_t*&, hb_blob_t*&, hb_direction_t&, unsigned int&, hb_glyph_position_t&>(hb_position_single_dispatch_t*, hb_font_t*&, hb_blob_t*&, hb_direction_t&, unsigned int&, hb_glyph_position_t&) const
4454
4455
  protected:
4456
  union {
4457
  struct { HBUINT16 v; }  format;   /* Format identifier */
4458
  ExtensionFormat1<T> format1;
4459
  } u;
4460
};
4461
4462
4463
/*
4464
 * GSUB/GPOS Common
4465
 */
4466
4467
struct hb_ot_layout_lookup_accelerator_t
4468
{
4469
  template <typename TLookup>
4470
  static hb_ot_layout_lookup_accelerator_t *create (const TLookup &lookup)
4471
985
  {
4472
985
    unsigned count = lookup.get_subtable_count ();
4473
4474
985
    unsigned size = sizeof (hb_ot_layout_lookup_accelerator_t) -
4475
985
        HB_VAR_ARRAY * sizeof (hb_accelerate_subtables_context_t::hb_applicable_t) +
4476
985
        count * sizeof (hb_accelerate_subtables_context_t::hb_applicable_t);
4477
4478
    /* The following is a calloc because when we are collecting subtables,
4479
     * some of them might be invalid and hence not collect; as a result,
4480
     * we might not fill in all the count entries of the subtables array.
4481
     * Zeroing it allows the set digest to gatekeep it without having to
4482
     * initialize it further. */
4483
985
    auto *thiz = (hb_ot_layout_lookup_accelerator_t *) hb_calloc (1, size);
4484
985
    if (unlikely (!thiz))
4485
0
      return nullptr;
4486
4487
985
    hb_accelerate_subtables_context_t c_accelerate_subtables (thiz->subtables);
4488
985
    lookup.dispatch (&c_accelerate_subtables);
4489
4490
985
    thiz->digest.init ();
4491
985
    for (auto& subtable : hb_iter (thiz->subtables, count))
4492
1.68k
      thiz->digest.union_ (subtable.digest);
4493
4494
985
    thiz->count = count;
4495
4496
985
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
4497
985
    thiz->subtable_cache_user_idx = c_accelerate_subtables.subtable_cache_user_idx;
4498
4499
2.67k
    for (unsigned i = 0; i < count; i++)
4500
1.68k
      if (i != thiz->subtable_cache_user_idx)
4501
1.68k
       thiz->subtables[i].apply_cached_func = thiz->subtables[i].apply_func;
4502
985
#endif
4503
4504
985
    return thiz;
4505
985
  }
OT::hb_ot_layout_lookup_accelerator_t* OT::hb_ot_layout_lookup_accelerator_t::create<OT::Layout::GPOS_impl::PosLookup>(OT::Layout::GPOS_impl::PosLookup const&)
Line
Count
Source
4471
889
  {
4472
889
    unsigned count = lookup.get_subtable_count ();
4473
4474
889
    unsigned size = sizeof (hb_ot_layout_lookup_accelerator_t) -
4475
889
        HB_VAR_ARRAY * sizeof (hb_accelerate_subtables_context_t::hb_applicable_t) +
4476
889
        count * sizeof (hb_accelerate_subtables_context_t::hb_applicable_t);
4477
4478
    /* The following is a calloc because when we are collecting subtables,
4479
     * some of them might be invalid and hence not collect; as a result,
4480
     * we might not fill in all the count entries of the subtables array.
4481
     * Zeroing it allows the set digest to gatekeep it without having to
4482
     * initialize it further. */
4483
889
    auto *thiz = (hb_ot_layout_lookup_accelerator_t *) hb_calloc (1, size);
4484
889
    if (unlikely (!thiz))
4485
0
      return nullptr;
4486
4487
889
    hb_accelerate_subtables_context_t c_accelerate_subtables (thiz->subtables);
4488
889
    lookup.dispatch (&c_accelerate_subtables);
4489
4490
889
    thiz->digest.init ();
4491
889
    for (auto& subtable : hb_iter (thiz->subtables, count))
4492
1.59k
      thiz->digest.union_ (subtable.digest);
4493
4494
889
    thiz->count = count;
4495
4496
889
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
4497
889
    thiz->subtable_cache_user_idx = c_accelerate_subtables.subtable_cache_user_idx;
4498
4499
2.48k
    for (unsigned i = 0; i < count; i++)
4500
1.59k
      if (i != thiz->subtable_cache_user_idx)
4501
1.59k
       thiz->subtables[i].apply_cached_func = thiz->subtables[i].apply_func;
4502
889
#endif
4503
4504
889
    return thiz;
4505
889
  }
OT::hb_ot_layout_lookup_accelerator_t* OT::hb_ot_layout_lookup_accelerator_t::create<OT::Layout::GSUB_impl::SubstLookup>(OT::Layout::GSUB_impl::SubstLookup const&)
Line
Count
Source
4471
96
  {
4472
96
    unsigned count = lookup.get_subtable_count ();
4473
4474
96
    unsigned size = sizeof (hb_ot_layout_lookup_accelerator_t) -
4475
96
        HB_VAR_ARRAY * sizeof (hb_accelerate_subtables_context_t::hb_applicable_t) +
4476
96
        count * sizeof (hb_accelerate_subtables_context_t::hb_applicable_t);
4477
4478
    /* The following is a calloc because when we are collecting subtables,
4479
     * some of them might be invalid and hence not collect; as a result,
4480
     * we might not fill in all the count entries of the subtables array.
4481
     * Zeroing it allows the set digest to gatekeep it without having to
4482
     * initialize it further. */
4483
96
    auto *thiz = (hb_ot_layout_lookup_accelerator_t *) hb_calloc (1, size);
4484
96
    if (unlikely (!thiz))
4485
0
      return nullptr;
4486
4487
96
    hb_accelerate_subtables_context_t c_accelerate_subtables (thiz->subtables);
4488
96
    lookup.dispatch (&c_accelerate_subtables);
4489
4490
96
    thiz->digest.init ();
4491
96
    for (auto& subtable : hb_iter (thiz->subtables, count))
4492
96
      thiz->digest.union_ (subtable.digest);
4493
4494
96
    thiz->count = count;
4495
4496
96
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
4497
96
    thiz->subtable_cache_user_idx = c_accelerate_subtables.subtable_cache_user_idx;
4498
4499
192
    for (unsigned i = 0; i < count; i++)
4500
96
      if (i != thiz->subtable_cache_user_idx)
4501
96
       thiz->subtables[i].apply_cached_func = thiz->subtables[i].apply_func;
4502
96
#endif
4503
4504
96
    return thiz;
4505
96
  }
4506
4507
  void fini ()
4508
0
  {
4509
0
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
4510
0
    for (unsigned i = 0; i < count; i++)
4511
0
      hb_free (subtables[i].external_cache);
4512
0
#endif
4513
0
  }
4514
4515
  bool may_have (hb_codepoint_t g) const
4516
0
  { return digest.may_have (g); }
4517
4518
#ifndef HB_OPTIMIZE_SIZE
4519
  HB_ALWAYS_INLINE
4520
#endif
4521
  bool apply (hb_ot_apply_context_t *c, bool use_cache) const
4522
117M
  {
4523
117M
    c->lookup_accel = this;
4524
117M
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
4525
117M
    if (use_cache)
4526
0
    {
4527
0
      return
4528
0
      + hb_iter (hb_iter (subtables, count))
4529
0
      | hb_map ([&c] (const hb_accelerate_subtables_context_t::hb_applicable_t &_) { return _.apply_cached (c); })
4530
0
      | hb_any
4531
0
      ;
4532
0
    }
4533
117M
    else
4534
117M
#endif
4535
117M
    {
4536
117M
      return
4537
117M
      + hb_iter (hb_iter (subtables, count))
4538
118M
      | hb_map ([&c] (const hb_accelerate_subtables_context_t::hb_applicable_t &_) { return _.apply (c); })
4539
117M
      | hb_any
4540
117M
      ;
4541
117M
    }
4542
0
    return false;
4543
117M
  }
4544
4545
  bool cache_enter (hb_ot_apply_context_t *c) const
4546
6.15M
  {
4547
6.15M
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
4548
6.15M
    return subtable_cache_user_idx != (unsigned) -1 &&
4549
0
     subtables[subtable_cache_user_idx].cache_enter (c);
4550
#else
4551
    return false;
4552
#endif
4553
6.15M
  }
4554
  void cache_leave (hb_ot_apply_context_t *c) const
4555
0
  {
4556
0
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
4557
0
    subtables[subtable_cache_user_idx].cache_leave (c);
4558
0
#endif
4559
0
  }
4560
4561
4562
  hb_set_digest_t digest;
4563
  private:
4564
  unsigned count = 0; /* Number of subtables in the array. */
4565
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
4566
  unsigned subtable_cache_user_idx = (unsigned) -1;
4567
#endif
4568
  hb_accelerate_subtables_context_t::hb_applicable_t subtables[HB_VAR_ARRAY];
4569
};
4570
4571
template <typename Types>
4572
struct GSUBGPOSVersion1_2
4573
{
4574
  friend struct GSUBGPOS;
4575
4576
  protected:
4577
  FixedVersion<>version;  /* Version of the GSUB/GPOS table--initially set
4578
         * to 0x00010000u */
4579
  typename Types:: template OffsetTo<ScriptList>
4580
    scriptList; /* ScriptList table */
4581
  typename Types::template OffsetTo<FeatureList>
4582
    featureList;  /* FeatureList table */
4583
  typename Types::template OffsetTo<LookupList<Types>>
4584
    lookupList; /* LookupList table */
4585
  Offset32To<FeatureVariations>
4586
    featureVars;  /* Offset to Feature Variations
4587
           table--from beginning of table
4588
         * (may be NULL).  Introduced
4589
         * in version 0x00010001. */
4590
  public:
4591
  DEFINE_SIZE_MIN (4 + 3 * Types::size);
4592
4593
  unsigned int get_size () const
4594
0
  {
4595
0
    return min_size +
4596
0
     (version.to_int () >= 0x00010001u ? featureVars.static_size : 0);
4597
0
  }
4598
4599
  const typename Types::template OffsetTo<LookupList<Types>>* get_lookup_list_offset () const
4600
  {
4601
    return &lookupList;
4602
  }
4603
4604
  template <typename TLookup>
4605
  bool sanitize (hb_sanitize_context_t *c) const
4606
126
  {
4607
126
    TRACE_SANITIZE (this);
4608
126
    typedef List16OfOffsetTo<TLookup, typename Types::HBUINT> TLookupList;
4609
126
    if (unlikely (!(scriptList.sanitize (c, this) &&
4610
126
        featureList.sanitize (c, this) &&
4611
126
        reinterpret_cast<const typename Types::template OffsetTo<TLookupList> &> (lookupList).sanitize (c, this))))
4612
0
      return_trace (false);
4613
4614
126
#ifndef HB_NO_VAR
4615
126
    if (unlikely (!(version.to_int () < 0x00010001u || featureVars.sanitize (c, this))))
4616
0
      return_trace (false);
4617
126
#endif
4618
4619
126
    return_trace (true);
4620
126
  }
bool OT::GSUBGPOSVersion1_2<OT::Layout::SmallTypes>::sanitize<OT::Layout::GSUB_impl::SubstLookup>(hb_sanitize_context_t*) const
Line
Count
Source
4606
63
  {
4607
63
    TRACE_SANITIZE (this);
4608
63
    typedef List16OfOffsetTo<TLookup, typename Types::HBUINT> TLookupList;
4609
63
    if (unlikely (!(scriptList.sanitize (c, this) &&
4610
63
        featureList.sanitize (c, this) &&
4611
63
        reinterpret_cast<const typename Types::template OffsetTo<TLookupList> &> (lookupList).sanitize (c, this))))
4612
0
      return_trace (false);
4613
4614
63
#ifndef HB_NO_VAR
4615
63
    if (unlikely (!(version.to_int () < 0x00010001u || featureVars.sanitize (c, this))))
4616
0
      return_trace (false);
4617
63
#endif
4618
4619
63
    return_trace (true);
4620
63
  }
bool OT::GSUBGPOSVersion1_2<OT::Layout::SmallTypes>::sanitize<OT::Layout::GPOS_impl::PosLookup>(hb_sanitize_context_t*) const
Line
Count
Source
4606
63
  {
4607
63
    TRACE_SANITIZE (this);
4608
63
    typedef List16OfOffsetTo<TLookup, typename Types::HBUINT> TLookupList;
4609
63
    if (unlikely (!(scriptList.sanitize (c, this) &&
4610
63
        featureList.sanitize (c, this) &&
4611
63
        reinterpret_cast<const typename Types::template OffsetTo<TLookupList> &> (lookupList).sanitize (c, this))))
4612
0
      return_trace (false);
4613
4614
63
#ifndef HB_NO_VAR
4615
63
    if (unlikely (!(version.to_int () < 0x00010001u || featureVars.sanitize (c, this))))
4616
0
      return_trace (false);
4617
63
#endif
4618
4619
63
    return_trace (true);
4620
63
  }
4621
4622
  template <typename TLookup>
4623
  bool subset (hb_subset_layout_context_t *c) const
4624
0
  {
4625
0
    TRACE_SUBSET (this);
4626
0
4627
0
    auto *out = c->subset_context->serializer->start_embed (this);
4628
0
    if (unlikely (!c->subset_context->serializer->extend_min (out))) return_trace (false);
4629
0
4630
0
    out->version = version;
4631
0
4632
0
    typedef LookupOffsetList<TLookup, typename Types::HBUINT> TLookupList;
4633
0
    reinterpret_cast<typename Types::template OffsetTo<TLookupList> &> (out->lookupList)
4634
0
  .serialize_subset (c->subset_context,
4635
0
         reinterpret_cast<const typename Types::template OffsetTo<TLookupList> &> (lookupList),
4636
0
         this,
4637
0
         c);
4638
0
4639
0
    reinterpret_cast<typename Types::template OffsetTo<RecordListOfFeature> &> (out->featureList)
4640
0
  .serialize_subset (c->subset_context,
4641
0
         reinterpret_cast<const typename Types::template OffsetTo<RecordListOfFeature> &> (featureList),
4642
0
         this,
4643
0
         c);
4644
0
4645
0
    out->scriptList.serialize_subset (c->subset_context,
4646
0
              scriptList,
4647
0
              this,
4648
0
              c);
4649
0
4650
0
#ifndef HB_NO_VAR
4651
0
    if (version.to_int () >= 0x00010001u)
4652
0
    {
4653
0
      auto snapshot = c->subset_context->serializer->snapshot ();
4654
0
      if (!c->subset_context->serializer->extend_min (&out->featureVars))
4655
0
        return_trace (false);
4656
0
4657
0
      // if all axes are pinned all feature vars are dropped.
4658
0
      bool ret = !c->subset_context->plan->all_axes_pinned
4659
0
                 && out->featureVars.serialize_subset (c->subset_context, featureVars, this, c);
4660
0
      if (!ret && version.major == 1)
4661
0
      {
4662
0
        c->subset_context->serializer->revert (snapshot);
4663
0
  out->version.major = 1;
4664
0
  out->version.minor = 0;
4665
0
      }
4666
0
    }
4667
0
#endif
4668
0
4669
0
    return_trace (true);
4670
0
  }
Unexecuted instantiation: bool OT::GSUBGPOSVersion1_2<OT::Layout::SmallTypes>::subset<OT::Layout::GPOS_impl::PosLookup>(OT::hb_subset_layout_context_t*) const
Unexecuted instantiation: bool OT::GSUBGPOSVersion1_2<OT::Layout::SmallTypes>::subset<OT::Layout::GSUB_impl::SubstLookup>(OT::hb_subset_layout_context_t*) const
4671
};
4672
4673
struct GSUBGPOS
4674
{
4675
  unsigned int get_size () const
4676
0
  {
4677
0
    switch (u.version.major) {
4678
0
    case 1: hb_barrier (); return u.version1.get_size ();
4679
0
#ifndef HB_NO_BEYOND_64K
4680
0
    case 2: hb_barrier (); return u.version2.get_size ();
4681
0
#endif
4682
0
    default: return u.version.static_size;
4683
0
    }
4684
0
  }
4685
4686
  template <typename TLookup>
4687
  bool sanitize (hb_sanitize_context_t *c) const
4688
126
  {
4689
126
    TRACE_SANITIZE (this);
4690
126
    if (unlikely (!u.version.sanitize (c))) return_trace (false);
4691
126
    hb_barrier ();
4692
126
    switch (u.version.major) {
4693
126
    case 1: hb_barrier (); return_trace (u.version1.sanitize<TLookup> (c));
4694
#ifndef HB_NO_BEYOND_64K
4695
    case 2: hb_barrier (); return_trace (u.version2.sanitize<TLookup> (c));
4696
#endif
4697
0
    default: return_trace (true);
4698
126
    }
4699
126
  }
bool OT::GSUBGPOS::sanitize<OT::Layout::GSUB_impl::SubstLookup>(hb_sanitize_context_t*) const
Line
Count
Source
4688
63
  {
4689
63
    TRACE_SANITIZE (this);
4690
63
    if (unlikely (!u.version.sanitize (c))) return_trace (false);
4691
63
    hb_barrier ();
4692
63
    switch (u.version.major) {
4693
63
    case 1: hb_barrier (); return_trace (u.version1.sanitize<TLookup> (c));
4694
#ifndef HB_NO_BEYOND_64K
4695
    case 2: hb_barrier (); return_trace (u.version2.sanitize<TLookup> (c));
4696
#endif
4697
0
    default: return_trace (true);
4698
63
    }
4699
63
  }
bool OT::GSUBGPOS::sanitize<OT::Layout::GPOS_impl::PosLookup>(hb_sanitize_context_t*) const
Line
Count
Source
4688
63
  {
4689
63
    TRACE_SANITIZE (this);
4690
63
    if (unlikely (!u.version.sanitize (c))) return_trace (false);
4691
63
    hb_barrier ();
4692
63
    switch (u.version.major) {
4693
63
    case 1: hb_barrier (); return_trace (u.version1.sanitize<TLookup> (c));
4694
#ifndef HB_NO_BEYOND_64K
4695
    case 2: hb_barrier (); return_trace (u.version2.sanitize<TLookup> (c));
4696
#endif
4697
0
    default: return_trace (true);
4698
63
    }
4699
63
  }
4700
4701
  template <typename TLookup>
4702
  bool subset (hb_subset_layout_context_t *c) const
4703
0
  {
4704
0
    switch (u.version.major) {
4705
0
    case 1: hb_barrier (); return u.version1.subset<TLookup> (c);
4706
0
#ifndef HB_NO_BEYOND_64K
4707
0
    case 2: hb_barrier (); return u.version2.subset<TLookup> (c);
4708
0
#endif
4709
0
    default: return false;
4710
0
    }
4711
0
  }
Unexecuted instantiation: bool OT::GSUBGPOS::subset<OT::Layout::GPOS_impl::PosLookup>(OT::hb_subset_layout_context_t*) const
Unexecuted instantiation: bool OT::GSUBGPOS::subset<OT::Layout::GSUB_impl::SubstLookup>(OT::hb_subset_layout_context_t*) const
4712
4713
  const ScriptList &get_script_list () const
4714
101k
  {
4715
101k
    switch (u.version.major) {
4716
101k
    case 1: hb_barrier (); return this+u.version1.scriptList;
4717
#ifndef HB_NO_BEYOND_64K
4718
    case 2: hb_barrier (); return this+u.version2.scriptList;
4719
#endif
4720
0
    default: return Null (ScriptList);
4721
101k
    }
4722
101k
  }
4723
  const FeatureList &get_feature_list () const
4724
62.4k
  {
4725
62.4k
    switch (u.version.major) {
4726
62.4k
    case 1: hb_barrier (); return this+u.version1.featureList;
4727
#ifndef HB_NO_BEYOND_64K
4728
    case 2: hb_barrier (); return this+u.version2.featureList;
4729
#endif
4730
0
    default: return Null (FeatureList);
4731
62.4k
    }
4732
62.4k
  }
4733
  unsigned int get_lookup_count () const
4734
20.9k
  {
4735
20.9k
    switch (u.version.major) {
4736
20.9k
    case 1: hb_barrier (); return (this+u.version1.lookupList).len;
4737
#ifndef HB_NO_BEYOND_64K
4738
    case 2: hb_barrier (); return (this+u.version2.lookupList).len;
4739
#endif
4740
0
    default: return 0;
4741
20.9k
    }
4742
20.9k
  }
4743
  const Lookup& get_lookup (unsigned int i) const
4744
6.16M
  {
4745
6.16M
    switch (u.version.major) {
4746
6.16M
    case 1: hb_barrier (); return (this+u.version1.lookupList)[i];
4747
#ifndef HB_NO_BEYOND_64K
4748
    case 2: hb_barrier (); return (this+u.version2.lookupList)[i];
4749
#endif
4750
0
    default: return Null (Lookup);
4751
6.16M
    }
4752
6.16M
  }
4753
  const FeatureVariations &get_feature_variations () const
4754
49.3M
  {
4755
49.3M
    switch (u.version.major) {
4756
49.3M
    case 1: hb_barrier (); return (u.version.to_int () >= 0x00010001u && hb_barrier () ? this+u.version1.featureVars : Null (FeatureVariations));
4757
#ifndef HB_NO_BEYOND_64K
4758
    case 2: hb_barrier (); return this+u.version2.featureVars;
4759
#endif
4760
0
    default: return Null (FeatureVariations);
4761
49.3M
    }
4762
49.3M
  }
4763
4764
19.8k
  bool has_data () const { return u.version.to_int (); }
4765
  unsigned int get_script_count () const
4766
195
  { return get_script_list ().len; }
4767
  const Tag& get_script_tag (unsigned int i) const
4768
0
  { return get_script_list ().get_tag (i); }
4769
  unsigned int get_script_tags (unsigned int start_offset,
4770
        unsigned int *script_count /* IN/OUT */,
4771
        hb_tag_t     *script_tags /* OUT */) const
4772
0
  { return get_script_list ().get_tags (start_offset, script_count, script_tags); }
4773
  const Script& get_script (unsigned int i) const
4774
61.3k
  { return get_script_list ()[i]; }
4775
  bool find_script_index (hb_tag_t tag, unsigned int *index) const
4776
40.2k
  { return get_script_list ().find_index (tag, index); }
4777
4778
  unsigned int get_feature_count () const
4779
3.29k
  { return get_feature_list ().len; }
4780
  hb_tag_t get_feature_tag (unsigned int i) const
4781
58.1k
  { return i == Index::NOT_FOUND_INDEX ? HB_TAG_NONE : get_feature_list ().get_tag (i); }
4782
  unsigned int get_feature_tags (unsigned int start_offset,
4783
         unsigned int *feature_count /* IN/OUT */,
4784
         hb_tag_t     *feature_tags /* OUT */) const
4785
0
  { return get_feature_list ().get_tags (start_offset, feature_count, feature_tags); }
4786
  const Feature& get_feature (unsigned int i) const
4787
20.8k
  { return get_feature_list ()[i]; }
4788
  bool find_feature_index (hb_tag_t tag, unsigned int *index) const
4789
0
  { return get_feature_list ().find_index (tag, index); }
4790
4791
  bool find_variations_index (const int *coords, unsigned int num_coords,
4792
            unsigned int *index,
4793
            ItemVarStoreInstancer *instancer) const
4794
49.3M
  {
4795
#ifdef HB_NO_VAR
4796
    *index = FeatureVariations::NOT_FOUND_INDEX;
4797
    return false;
4798
#endif
4799
49.3M
    return get_feature_variations ().find_index (coords, num_coords, index, instancer);
4800
49.3M
  }
4801
  const Feature& get_feature_variation (unsigned int feature_index,
4802
          unsigned int variations_index) const
4803
20.8k
  {
4804
20.8k
#ifndef HB_NO_VAR
4805
20.8k
    if (FeatureVariations::NOT_FOUND_INDEX != variations_index &&
4806
0
  u.version.to_int () >= 0x00010001u)
4807
0
    {
4808
0
      const Feature *feature = get_feature_variations ().find_substitute (variations_index,
4809
0
                    feature_index);
4810
0
      if (feature)
4811
0
  return *feature;
4812
0
    }
4813
20.8k
#endif
4814
20.8k
    return get_feature (feature_index);
4815
20.8k
  }
4816
4817
  void feature_variation_collect_lookups (const hb_set_t *feature_indexes,
4818
            const hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map,
4819
            hb_set_t       *lookup_indexes /* OUT */) const
4820
195
  {
4821
195
#ifndef HB_NO_VAR
4822
195
    get_feature_variations ().collect_lookups (feature_indexes, feature_record_cond_idx_map, lookup_indexes);
4823
195
#endif
4824
195
  }
4825
4826
#ifndef HB_NO_VAR
4827
  void collect_feature_substitutes_with_variations (hb_collect_feature_substitutes_with_var_context_t *c) const
4828
0
  { get_feature_variations ().collect_feature_substitutes_with_variations (c); }
4829
#endif
4830
4831
  template <typename TLookup>
4832
  void closure_lookups (hb_face_t      *face,
4833
      const hb_set_t *glyphs,
4834
      hb_set_t       *lookup_indexes /* IN/OUT */) const
4835
0
  {
4836
0
    hb_set_t visited_lookups, inactive_lookups;
4837
0
    hb_closure_lookups_context_t c (face, glyphs, &visited_lookups, &inactive_lookups);
4838
0
4839
0
    c.set_recurse_func (TLookup::template dispatch_recurse_func<hb_closure_lookups_context_t>);
4840
0
4841
0
    for (unsigned lookup_index : *lookup_indexes)
4842
0
      reinterpret_cast<const TLookup &> (get_lookup (lookup_index)).closure_lookups (&c, lookup_index);
4843
0
4844
0
    hb_set_union (lookup_indexes, &visited_lookups);
4845
0
    hb_set_subtract (lookup_indexes, &inactive_lookups);
4846
0
  }
Unexecuted instantiation: void OT::GSUBGPOS::closure_lookups<OT::Layout::GPOS_impl::PosLookup>(hb_face_t*, hb_set_t const*, hb_set_t*) const
Unexecuted instantiation: void OT::GSUBGPOS::closure_lookups<OT::Layout::GSUB_impl::SubstLookup>(hb_face_t*, hb_set_t const*, hb_set_t*) const
4847
4848
  void prune_langsys (const hb_map_t *duplicate_feature_map,
4849
                      const hb_set_t *layout_scripts,
4850
                      hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *script_langsys_map,
4851
                      hb_set_t       *new_feature_indexes /* OUT */) const
4852
0
  {
4853
0
    hb_prune_langsys_context_t c (this, script_langsys_map, duplicate_feature_map, new_feature_indexes);
4854
0
4855
0
    unsigned count = get_script_count ();
4856
0
    for (unsigned script_index = 0; script_index < count; script_index++)
4857
0
    {
4858
0
      const Tag& tag = get_script_tag (script_index);
4859
0
      if (!layout_scripts->has (tag)) continue;
4860
0
      const Script& s = get_script (script_index);
4861
0
      s.prune_langsys (&c, script_index);
4862
0
    }
4863
0
  }
4864
4865
  void prune_features (const hb_map_t *lookup_indices, /* IN */
4866
           const hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map, /* IN */
4867
           const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map, /* IN */
4868
           hb_set_t       *feature_indices /* IN/OUT */) const
4869
0
  {
4870
0
#ifndef HB_NO_VAR
4871
0
    // This is the set of feature indices which have alternate versions defined
4872
0
    // if the FeatureVariation's table and the alternate version(s) intersect the
4873
0
    // set of lookup indices.
4874
0
    hb_set_t alternate_feature_indices;
4875
0
    get_feature_variations ().closure_features (lookup_indices, feature_record_cond_idx_map, &alternate_feature_indices);
4876
0
    if (unlikely (alternate_feature_indices.in_error()))
4877
0
    {
4878
0
      feature_indices->err ();
4879
0
      return;
4880
0
    }
4881
0
#endif
4882
0
4883
0
    for (unsigned i : hb_iter (feature_indices))
4884
0
    {
4885
0
      hb_tag_t tag =  get_feature_tag (i);
4886
0
      if (tag == HB_TAG ('p', 'r', 'e', 'f'))
4887
0
        // Note: Never ever drop feature 'pref', even if it's empty.
4888
0
        // HarfBuzz chooses shaper for Khmer based on presence of this
4889
0
        // feature. See thread at:
4890
0
  // http://lists.freedesktop.org/archives/harfbuzz/2012-November/002660.html
4891
0
        continue;
4892
0
4893
0
4894
0
      const Feature *f = &(get_feature (i));
4895
0
      const Feature** p = nullptr;
4896
0
      if (feature_substitutes_map->has (i, &p))
4897
0
        f = *p;
4898
0
4899
0
      if (!f->featureParams.is_null () &&
4900
0
          tag == HB_TAG ('s', 'i', 'z', 'e'))
4901
0
        continue;
4902
0
4903
0
      if (!f->intersects_lookup_indexes (lookup_indices)
4904
0
#ifndef HB_NO_VAR
4905
0
          && !alternate_feature_indices.has (i)
4906
0
#endif
4907
0
    )
4908
0
  feature_indices->del (i);
4909
0
    }
4910
0
  }
4911
4912
  void collect_name_ids (const hb_map_t *feature_index_map,
4913
                         hb_set_t *nameids_to_retain /* OUT */) const
4914
0
  {
4915
0
    unsigned count = get_feature_count ();
4916
0
    for (unsigned i = 0 ; i < count; i++)
4917
0
    {
4918
0
      if (!feature_index_map->has (i)) continue;
4919
0
      hb_tag_t tag = get_feature_tag (i);
4920
0
      get_feature (i).collect_name_ids (tag, nameids_to_retain);
4921
0
    }
4922
0
  }
4923
4924
  template <typename T>
4925
  struct accelerator_t
4926
  {
4927
    accelerator_t (hb_face_t *face)
4928
126
    {
4929
126
      hb_sanitize_context_t sc;
4930
126
      sc.lazy_some_gpos = true;
4931
126
      this->table = sc.reference_table<T> (face);
4932
4933
126
      if (unlikely (this->table->is_blocklisted (this->table.get_blob (), face)))
4934
0
      {
4935
0
  hb_blob_destroy (this->table.get_blob ());
4936
0
  this->table = hb_blob_get_empty ();
4937
0
      }
4938
4939
126
      this->lookup_count = table->get_lookup_count ();
4940
4941
126
      this->accels = (hb_atomic_t<hb_ot_layout_lookup_accelerator_t *> *) hb_calloc (this->lookup_count, sizeof (*accels));
4942
126
      if (unlikely (!this->accels))
4943
0
      {
4944
0
  this->lookup_count = 0;
4945
0
  this->table.destroy ();
4946
0
  this->table = hb_blob_get_empty ();
4947
0
      }
4948
126
    }
OT::GSUBGPOS::accelerator_t<OT::Layout::GSUB>::accelerator_t(hb_face_t*)
Line
Count
Source
4928
63
    {
4929
63
      hb_sanitize_context_t sc;
4930
63
      sc.lazy_some_gpos = true;
4931
63
      this->table = sc.reference_table<T> (face);
4932
4933
63
      if (unlikely (this->table->is_blocklisted (this->table.get_blob (), face)))
4934
0
      {
4935
0
  hb_blob_destroy (this->table.get_blob ());
4936
0
  this->table = hb_blob_get_empty ();
4937
0
      }
4938
4939
63
      this->lookup_count = table->get_lookup_count ();
4940
4941
63
      this->accels = (hb_atomic_t<hb_ot_layout_lookup_accelerator_t *> *) hb_calloc (this->lookup_count, sizeof (*accels));
4942
63
      if (unlikely (!this->accels))
4943
0
      {
4944
0
  this->lookup_count = 0;
4945
0
  this->table.destroy ();
4946
0
  this->table = hb_blob_get_empty ();
4947
0
      }
4948
63
    }
OT::GSUBGPOS::accelerator_t<OT::Layout::GPOS>::accelerator_t(hb_face_t*)
Line
Count
Source
4928
63
    {
4929
63
      hb_sanitize_context_t sc;
4930
63
      sc.lazy_some_gpos = true;
4931
63
      this->table = sc.reference_table<T> (face);
4932
4933
63
      if (unlikely (this->table->is_blocklisted (this->table.get_blob (), face)))
4934
0
      {
4935
0
  hb_blob_destroy (this->table.get_blob ());
4936
0
  this->table = hb_blob_get_empty ();
4937
0
      }
4938
4939
63
      this->lookup_count = table->get_lookup_count ();
4940
4941
63
      this->accels = (hb_atomic_t<hb_ot_layout_lookup_accelerator_t *> *) hb_calloc (this->lookup_count, sizeof (*accels));
4942
63
      if (unlikely (!this->accels))
4943
0
      {
4944
0
  this->lookup_count = 0;
4945
0
  this->table.destroy ();
4946
0
  this->table = hb_blob_get_empty ();
4947
0
      }
4948
63
    }
4949
    ~accelerator_t ()
4950
0
    {
4951
0
      for (unsigned int i = 0; i < this->lookup_count; i++)
4952
0
      {
4953
0
  auto *accel = this->accels[i].get_relaxed ();
4954
0
  if (accel)
4955
0
    accel->fini ();
4956
0
  hb_free (accel);
4957
0
      }
4958
0
      hb_free (this->accels);
4959
0
      this->table.destroy ();
4960
0
    }
Unexecuted instantiation: OT::GSUBGPOS::accelerator_t<OT::Layout::GSUB>::~accelerator_t()
Unexecuted instantiation: OT::GSUBGPOS::accelerator_t<OT::Layout::GPOS>::~accelerator_t()
4961
4962
49.2M
    hb_blob_t *get_blob () const { return table.get_blob (); }
OT::GSUBGPOS::accelerator_t<OT::Layout::GSUB>::get_blob() const
Line
Count
Source
4962
24.6M
    hb_blob_t *get_blob () const { return table.get_blob (); }
OT::GSUBGPOS::accelerator_t<OT::Layout::GPOS>::get_blob() const
Line
Count
Source
4962
24.6M
    hb_blob_t *get_blob () const { return table.get_blob (); }
4963
4964
    hb_ot_layout_lookup_accelerator_t *get_accel (unsigned lookup_index) const
4965
102M
    {
4966
102M
      if (unlikely (lookup_index >= lookup_count)) return nullptr;
4967
4968
102M
    retry:
4969
102M
      auto *accel = accels[lookup_index].get_acquire ();
4970
102M
      if (unlikely (!accel))
4971
985
      {
4972
985
  accel = hb_ot_layout_lookup_accelerator_t::create (table->get_lookup (lookup_index));
4973
985
  if (unlikely (!accel))
4974
0
    return nullptr;
4975
4976
985
  if (unlikely (!accels[lookup_index].cmpexch (nullptr, accel)))
4977
0
  {
4978
0
    accel->fini ();
4979
0
    hb_free (accel);
4980
0
    goto retry;
4981
0
  }
4982
985
      }
4983
4984
102M
      return accel;
4985
102M
    }
OT::GSUBGPOS::accelerator_t<OT::Layout::GPOS>::get_accel(unsigned int) const
Line
Count
Source
4965
93.8M
    {
4966
93.8M
      if (unlikely (lookup_index >= lookup_count)) return nullptr;
4967
4968
93.8M
    retry:
4969
93.8M
      auto *accel = accels[lookup_index].get_acquire ();
4970
93.8M
      if (unlikely (!accel))
4971
889
      {
4972
889
  accel = hb_ot_layout_lookup_accelerator_t::create (table->get_lookup (lookup_index));
4973
889
  if (unlikely (!accel))
4974
0
    return nullptr;
4975
4976
889
  if (unlikely (!accels[lookup_index].cmpexch (nullptr, accel)))
4977
0
  {
4978
0
    accel->fini ();
4979
0
    hb_free (accel);
4980
0
    goto retry;
4981
0
  }
4982
889
      }
4983
4984
93.8M
      return accel;
4985
93.8M
    }
OT::GSUBGPOS::accelerator_t<OT::Layout::GSUB>::get_accel(unsigned int) const
Line
Count
Source
4965
8.75M
    {
4966
8.75M
      if (unlikely (lookup_index >= lookup_count)) return nullptr;
4967
4968
8.75M
    retry:
4969
8.75M
      auto *accel = accels[lookup_index].get_acquire ();
4970
8.75M
      if (unlikely (!accel))
4971
96
      {
4972
96
  accel = hb_ot_layout_lookup_accelerator_t::create (table->get_lookup (lookup_index));
4973
96
  if (unlikely (!accel))
4974
0
    return nullptr;
4975
4976
96
  if (unlikely (!accels[lookup_index].cmpexch (nullptr, accel)))
4977
0
  {
4978
0
    accel->fini ();
4979
0
    hb_free (accel);
4980
0
    goto retry;
4981
0
  }
4982
96
      }
4983
4984
8.75M
      return accel;
4985
8.75M
    }
4986
4987
    hb_blob_ptr_t<T> table;
4988
    unsigned int lookup_count;
4989
    hb_atomic_t<hb_ot_layout_lookup_accelerator_t *> *accels;
4990
  };
4991
4992
  protected:
4993
  union {
4994
  FixedVersion<>      version;  /* Version identifier */
4995
  GSUBGPOSVersion1_2<SmallTypes>  version1;
4996
#ifndef HB_NO_BEYOND_64K
4997
  GSUBGPOSVersion1_2<MediumTypes> version2;
4998
#endif
4999
  } u;
5000
  public:
5001
  DEFINE_SIZE_MIN (4);
5002
};
5003
5004
5005
} /* namespace OT */
5006
5007
5008
#endif /* HB_OT_LAYOUT_GSUBGPOS_HH */