Coverage Report

Created: 2026-08-13 06:33

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