166bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod/*
22409d5f8d7dd8b535ce5ea29e933f7db27d33793Behdad Esfahbod * Copyright © 2007,2008,2009,2010  Red Hat, Inc.
35b93e8d94fb4c2474816304ae3f52e1c704882deBehdad Esfahbod * Copyright © 2010,2012  Google, Inc.
466bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod *
5c755cb3e3ac55156d0d2ec05adea7a650b97cc41Behdad Esfahbod *  This is part of HarfBuzz, a text shaping library.
666bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod *
766bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod * Permission is hereby granted, without written agreement and without
866bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod * license or royalty fees, to use, copy, modify, and distribute this
966bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod * software and its documentation for any purpose, provided that the
1066bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod * above copyright notice and the following two paragraphs appear in
1166bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod * all copies of this software.
1266bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod *
1366bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
1466bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
1566bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
1666bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
1766bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod * DAMAGE.
1866bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod *
1966bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
2066bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
2166bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
2266bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
2366bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
2466bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod *
2566bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod * Red Hat Author(s): Behdad Esfahbod
2698370e89d1bff248737b482d129c2a4deb8bfd95Behdad Esfahbod * Google Author(s): Behdad Esfahbod
2766bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod */
2866bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod
295f5b24f99f52bbc922e238b65c06061ba07c8548Behdad Esfahbod#ifndef HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH
305f5b24f99f52bbc922e238b65c06061ba07c8548Behdad Esfahbod#define HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH
3166bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod
3240ec3bbb55b8af1668bb3d5f6232a85b15cff136Behdad Esfahbod#include "hb-private.hh"
3340ec3bbb55b8af1668bb3d5f6232a85b15cff136Behdad Esfahbod#include "hb-debug.hh"
3422da7fd94d6318c52df69d70470a85464ffc533dBehdad Esfahbod#include "hb-buffer-private.hh"
357a750ac33ec482e2c4856c19ea607f3563741c24Behdad Esfahbod#include "hb-ot-layout-gdef-table.hh"
361336ecdf8e4e9879b96b26ecfbf5c9ba6c49e2b9Behdad Esfahbod#include "hb-set-private.hh"
37f94b0aa64609654497ced9c00312c9643eb69053Behdad Esfahbod
3866bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod
397c8e844d92aa604fc4b396343721ea90eb83adb8Behdad Esfahbodnamespace OT {
407c8e844d92aa604fc4b396343721ea90eb83adb8Behdad Esfahbod
41acdba3f90b232fc12fcb200dca2584481b339118Behdad Esfahbod
4277a1a2bc18e7b04d4e352a8777ccce345b2f8659Behdad Esfahbodstruct hb_closure_context_t :
4377a1a2bc18e7b04d4e352a8777ccce345b2f8659Behdad Esfahbod       hb_dispatch_context_t<hb_closure_context_t, hb_void_t, HB_DEBUG_CLOSURE>
44f94b0aa64609654497ced9c00312c9643eb69053Behdad Esfahbod{
45a1733db1c6ff40aae71fa142a12b1fea7b53dd37Behdad Esfahbod  inline const char *get_name (void) { return "CLOSURE"; }
4644fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod  typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
4744fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod  template <typename T>
489c5a9ee967120c8a968a1160c420e03620d46c24Behdad Esfahbod  inline return_t dispatch (const T &obj) { obj.closure (this); return HB_VOID; }
49130bb3f6144afe5c88bb5b4e4c98e7cba03b1e26Behdad Esfahbod  static return_t default_return_value (void) { return HB_VOID; }
507b912c1936c3e8a7df27a30782ca127d0a83822dBehdad Esfahbod  bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
5144fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod  return_t recurse (unsigned int lookup_index)
5244fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod  {
539b34677f362fb0ef5a7cb8a284a9e06d1a4cc03bBehdad Esfahbod    if (unlikely (nesting_level_left == 0 || !recurse_func))
542005fa5340fc528c32dc2af945ad2431964a47d2Behdad Esfahbod      return default_return_value ();
5544fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod
5644fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod    nesting_level_left--;
5744fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod    recurse_func (this, lookup_index);
5844fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod    nesting_level_left++;
59130bb3f6144afe5c88bb5b4e4c98e7cba03b1e26Behdad Esfahbod    return HB_VOID;
6044fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod  }
6144fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod
62f94b0aa64609654497ced9c00312c9643eb69053Behdad Esfahbod  hb_face_t *face;
636a9be5bd3524dc3eb1e88d1063bde2e4d8b57011Behdad Esfahbod  hb_set_t *glyphs;
6444fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod  recurse_func_t recurse_func;
65f94b0aa64609654497ced9c00312c9643eb69053Behdad Esfahbod  unsigned int nesting_level_left;
66f94b0aa64609654497ced9c00312c9643eb69053Behdad Esfahbod  unsigned int debug_depth;
67f94b0aa64609654497ced9c00312c9643eb69053Behdad Esfahbod
68f94b0aa64609654497ced9c00312c9643eb69053Behdad Esfahbod  hb_closure_context_t (hb_face_t *face_,
696a9be5bd3524dc3eb1e88d1063bde2e4d8b57011Behdad Esfahbod			hb_set_t *glyphs_,
705ba450407b9d9856453e63a815499da8721ff6a7Behdad Esfahbod		        unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
71e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod			  face (face_),
72e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod			  glyphs (glyphs_),
73dbdbfe3d7b36613d893832dcb1884c756c20bfdaBehdad Esfahbod			  recurse_func (nullptr),
74f94b0aa64609654497ced9c00312c9643eb69053Behdad Esfahbod			  nesting_level_left (nesting_level_left_),
75f94b0aa64609654497ced9c00312c9643eb69053Behdad Esfahbod			  debug_depth (0) {}
769b34677f362fb0ef5a7cb8a284a9e06d1a4cc03bBehdad Esfahbod
779b34677f362fb0ef5a7cb8a284a9e06d1a4cc03bBehdad Esfahbod  void set_recurse_func (recurse_func_t func) { recurse_func = func; }
78f94b0aa64609654497ced9c00312c9643eb69053Behdad Esfahbod};
79f94b0aa64609654497ced9c00312c9643eb69053Behdad Esfahbod
80f94b0aa64609654497ced9c00312c9643eb69053Behdad Esfahbod
8177a1a2bc18e7b04d4e352a8777ccce345b2f8659Behdad Esfahbodstruct hb_would_apply_context_t :
8277a1a2bc18e7b04d4e352a8777ccce345b2f8659Behdad Esfahbod       hb_dispatch_context_t<hb_would_apply_context_t, bool, HB_DEBUG_WOULD_APPLY>
83e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod{
84a1733db1c6ff40aae71fa142a12b1fea7b53dd37Behdad Esfahbod  inline const char *get_name (void) { return "WOULD_APPLY"; }
851d67ef980f35ae30d4f8975f65ee07b8cc5deeeaBehdad Esfahbod  template <typename T>
869c5a9ee967120c8a968a1160c420e03620d46c24Behdad Esfahbod  inline return_t dispatch (const T &obj) { return obj.would_apply (this); }
871d67ef980f35ae30d4f8975f65ee07b8cc5deeeaBehdad Esfahbod  static return_t default_return_value (void) { return false; }
887b912c1936c3e8a7df27a30782ca127d0a83822dBehdad Esfahbod  bool stop_sublookup_iteration (return_t r) const { return r; }
891d67ef980f35ae30d4f8975f65ee07b8cc5deeeaBehdad Esfahbod
90e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod  hb_face_t *face;
91472f229a63f0d1bb21b02179ef430b7698df8f12Behdad Esfahbod  const hb_codepoint_t *glyphs;
92e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod  unsigned int len;
93d9b204d3d24cde165167714728bf380267903d6aBehdad Esfahbod  bool zero_context;
94e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod  unsigned int debug_depth;
95e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod
96e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod  hb_would_apply_context_t (hb_face_t *face_,
97472f229a63f0d1bb21b02179ef430b7698df8f12Behdad Esfahbod			    const hb_codepoint_t *glyphs_,
98472f229a63f0d1bb21b02179ef430b7698df8f12Behdad Esfahbod			    unsigned int len_,
992bd9fe359839a653f7caae534bf768af1735f155Behdad Esfahbod			    bool zero_context_) :
100e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod			      face (face_),
101472f229a63f0d1bb21b02179ef430b7698df8f12Behdad Esfahbod			      glyphs (glyphs_),
102472f229a63f0d1bb21b02179ef430b7698df8f12Behdad Esfahbod			      len (len_),
103d9b204d3d24cde165167714728bf380267903d6aBehdad Esfahbod			      zero_context (zero_context_),
104a1733db1c6ff40aae71fa142a12b1fea7b53dd37Behdad Esfahbod			      debug_depth (0) {}
105e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod};
106e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod
107e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod
10877a1a2bc18e7b04d4e352a8777ccce345b2f8659Behdad Esfahbodstruct hb_collect_glyphs_context_t :
10977a1a2bc18e7b04d4e352a8777ccce345b2f8659Behdad Esfahbod       hb_dispatch_context_t<hb_collect_glyphs_context_t, hb_void_t, HB_DEBUG_COLLECT_GLYPHS>
110e8cfdd7fa8d0fb66e0a261f3547e5824897e5131Behdad Esfahbod{
111a1733db1c6ff40aae71fa142a12b1fea7b53dd37Behdad Esfahbod  inline const char *get_name (void) { return "COLLECT_GLYPHS"; }
11226514d51b6669f092d9ccb7523443a5ece74169aBehdad Esfahbod  typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index);
1131d67ef980f35ae30d4f8975f65ee07b8cc5deeeaBehdad Esfahbod  template <typename T>
1149c5a9ee967120c8a968a1160c420e03620d46c24Behdad Esfahbod  inline return_t dispatch (const T &obj) { obj.collect_glyphs (this); return HB_VOID; }
115130bb3f6144afe5c88bb5b4e4c98e7cba03b1e26Behdad Esfahbod  static return_t default_return_value (void) { return HB_VOID; }
1167b912c1936c3e8a7df27a30782ca127d0a83822dBehdad Esfahbod  bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
1171d67ef980f35ae30d4f8975f65ee07b8cc5deeeaBehdad Esfahbod  return_t recurse (unsigned int lookup_index)
1181d67ef980f35ae30d4f8975f65ee07b8cc5deeeaBehdad Esfahbod  {
11926514d51b6669f092d9ccb7523443a5ece74169aBehdad Esfahbod    if (unlikely (nesting_level_left == 0 || !recurse_func))
12026514d51b6669f092d9ccb7523443a5ece74169aBehdad Esfahbod      return default_return_value ();
12126514d51b6669f092d9ccb7523443a5ece74169aBehdad Esfahbod
122dbdbfe3d7b36613d893832dcb1884c756c20bfdaBehdad Esfahbod    /* Note that GPOS sets recurse_func to nullptr already, so it doesn't get
1231bcfa06d1173f219809542a7380ce77f1c907becBehdad Esfahbod     * past the previous check.  For GSUB, we only want to collect the output
12476ea563673d24ae1673a5aa3a21da6014479d433Behdad Esfahbod     * glyphs in the recursion.  If output is not requested, we can go home now.
12576ea563673d24ae1673a5aa3a21da6014479d433Behdad Esfahbod     *
12676ea563673d24ae1673a5aa3a21da6014479d433Behdad Esfahbod     * Note further, that the above is not exactly correct.  A recursed lookup
12776ea563673d24ae1673a5aa3a21da6014479d433Behdad Esfahbod     * is allowed to match input that is not matched in the context, but that's
12876ea563673d24ae1673a5aa3a21da6014479d433Behdad Esfahbod     * not how most fonts are built.  It's possible to relax that and recurse
12976ea563673d24ae1673a5aa3a21da6014479d433Behdad Esfahbod     * with all sets here if it proves to be an issue.
13076ea563673d24ae1673a5aa3a21da6014479d433Behdad Esfahbod     */
1314a350d0eb25db60d95638664c892d4c8dacf050bBehdad Esfahbod
1324a350d0eb25db60d95638664c892d4c8dacf050bBehdad Esfahbod    if (output == hb_set_get_empty ())
133130bb3f6144afe5c88bb5b4e4c98e7cba03b1e26Behdad Esfahbod      return HB_VOID;
1344a350d0eb25db60d95638664c892d4c8dacf050bBehdad Esfahbod
135fde3e4a423871463c883cb969e99c29cb6f69f6bBehdad Esfahbod    /* Return if new lookup was recursed to before. */
1368b9d9b71b04c9d5698ec146658b31381060c700dBehdad Esfahbod    if (recursed_lookups->has (lookup_index))
137fde3e4a423871463c883cb969e99c29cb6f69f6bBehdad Esfahbod      return HB_VOID;
138fde3e4a423871463c883cb969e99c29cb6f69f6bBehdad Esfahbod
1394a350d0eb25db60d95638664c892d4c8dacf050bBehdad Esfahbod    hb_set_t *old_before = before;
1404a350d0eb25db60d95638664c892d4c8dacf050bBehdad Esfahbod    hb_set_t *old_input  = input;
1414a350d0eb25db60d95638664c892d4c8dacf050bBehdad Esfahbod    hb_set_t *old_after  = after;
1424a350d0eb25db60d95638664c892d4c8dacf050bBehdad Esfahbod    before = input = after = hb_set_get_empty ();
1431bcfa06d1173f219809542a7380ce77f1c907becBehdad Esfahbod
14426514d51b6669f092d9ccb7523443a5ece74169aBehdad Esfahbod    nesting_level_left--;
1454a350d0eb25db60d95638664c892d4c8dacf050bBehdad Esfahbod    recurse_func (this, lookup_index);
14626514d51b6669f092d9ccb7523443a5ece74169aBehdad Esfahbod    nesting_level_left++;
1474a350d0eb25db60d95638664c892d4c8dacf050bBehdad Esfahbod
1484a350d0eb25db60d95638664c892d4c8dacf050bBehdad Esfahbod    before = old_before;
1494a350d0eb25db60d95638664c892d4c8dacf050bBehdad Esfahbod    input  = old_input;
1504a350d0eb25db60d95638664c892d4c8dacf050bBehdad Esfahbod    after  = old_after;
1514a350d0eb25db60d95638664c892d4c8dacf050bBehdad Esfahbod
1528b9d9b71b04c9d5698ec146658b31381060c700dBehdad Esfahbod    recursed_lookups->add (lookup_index);
153fde3e4a423871463c883cb969e99c29cb6f69f6bBehdad Esfahbod
154130bb3f6144afe5c88bb5b4e4c98e7cba03b1e26Behdad Esfahbod    return HB_VOID;
1551d67ef980f35ae30d4f8975f65ee07b8cc5deeeaBehdad Esfahbod  }
1561d67ef980f35ae30d4f8975f65ee07b8cc5deeeaBehdad Esfahbod
157e8cfdd7fa8d0fb66e0a261f3547e5824897e5131Behdad Esfahbod  hb_face_t *face;
1588303593ba1db06e402eab52df47f21f13049112dBehdad Esfahbod  hb_set_t *before;
1598303593ba1db06e402eab52df47f21f13049112dBehdad Esfahbod  hb_set_t *input;
1608303593ba1db06e402eab52df47f21f13049112dBehdad Esfahbod  hb_set_t *after;
1618303593ba1db06e402eab52df47f21f13049112dBehdad Esfahbod  hb_set_t *output;
16226514d51b6669f092d9ccb7523443a5ece74169aBehdad Esfahbod  recurse_func_t recurse_func;
1638b9d9b71b04c9d5698ec146658b31381060c700dBehdad Esfahbod  hb_set_t *recursed_lookups;
16426514d51b6669f092d9ccb7523443a5ece74169aBehdad Esfahbod  unsigned int nesting_level_left;
165e8cfdd7fa8d0fb66e0a261f3547e5824897e5131Behdad Esfahbod  unsigned int debug_depth;
166e8cfdd7fa8d0fb66e0a261f3547e5824897e5131Behdad Esfahbod
167e8cfdd7fa8d0fb66e0a261f3547e5824897e5131Behdad Esfahbod  hb_collect_glyphs_context_t (hb_face_t *face_,
168dbdbfe3d7b36613d893832dcb1884c756c20bfdaBehdad Esfahbod			       hb_set_t  *glyphs_before, /* OUT. May be nullptr */
169dbdbfe3d7b36613d893832dcb1884c756c20bfdaBehdad Esfahbod			       hb_set_t  *glyphs_input,  /* OUT. May be nullptr */
170dbdbfe3d7b36613d893832dcb1884c756c20bfdaBehdad Esfahbod			       hb_set_t  *glyphs_after,  /* OUT. May be nullptr */
171dbdbfe3d7b36613d893832dcb1884c756c20bfdaBehdad Esfahbod			       hb_set_t  *glyphs_output, /* OUT. May be nullptr */
1725ba450407b9d9856453e63a815499da8721ff6a7Behdad Esfahbod			       unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
173e8cfdd7fa8d0fb66e0a261f3547e5824897e5131Behdad Esfahbod			      face (face_),
1748303593ba1db06e402eab52df47f21f13049112dBehdad Esfahbod			      before (glyphs_before ? glyphs_before : hb_set_get_empty ()),
1758303593ba1db06e402eab52df47f21f13049112dBehdad Esfahbod			      input  (glyphs_input  ? glyphs_input  : hb_set_get_empty ()),
1768303593ba1db06e402eab52df47f21f13049112dBehdad Esfahbod			      after  (glyphs_after  ? glyphs_after  : hb_set_get_empty ()),
1778303593ba1db06e402eab52df47f21f13049112dBehdad Esfahbod			      output (glyphs_output ? glyphs_output : hb_set_get_empty ()),
178dbdbfe3d7b36613d893832dcb1884c756c20bfdaBehdad Esfahbod			      recurse_func (nullptr),
1798b9d9b71b04c9d5698ec146658b31381060c700dBehdad Esfahbod			      recursed_lookups (nullptr),
18026514d51b6669f092d9ccb7523443a5ece74169aBehdad Esfahbod			      nesting_level_left (nesting_level_left_),
181fde3e4a423871463c883cb969e99c29cb6f69f6bBehdad Esfahbod			      debug_depth (0)
182fde3e4a423871463c883cb969e99c29cb6f69f6bBehdad Esfahbod  {
1838b9d9b71b04c9d5698ec146658b31381060c700dBehdad Esfahbod    recursed_lookups = hb_set_create ();
184fde3e4a423871463c883cb969e99c29cb6f69f6bBehdad Esfahbod  }
185fde3e4a423871463c883cb969e99c29cb6f69f6bBehdad Esfahbod  ~hb_collect_glyphs_context_t (void)
186fde3e4a423871463c883cb969e99c29cb6f69f6bBehdad Esfahbod  {
1878b9d9b71b04c9d5698ec146658b31381060c700dBehdad Esfahbod    hb_set_destroy (recursed_lookups);
188fde3e4a423871463c883cb969e99c29cb6f69f6bBehdad Esfahbod  }
18926514d51b6669f092d9ccb7523443a5ece74169aBehdad Esfahbod
19026514d51b6669f092d9ccb7523443a5ece74169aBehdad Esfahbod  void set_recurse_func (recurse_func_t func) { recurse_func = func; }
191e8cfdd7fa8d0fb66e0a261f3547e5824897e5131Behdad Esfahbod};
192e8cfdd7fa8d0fb66e0a261f3547e5824897e5131Behdad Esfahbod
193e8cfdd7fa8d0fb66e0a261f3547e5824897e5131Behdad Esfahbod
194e8cfdd7fa8d0fb66e0a261f3547e5824897e5131Behdad Esfahbod
19577a1a2bc18e7b04d4e352a8777ccce345b2f8659Behdad Esfahbod/* XXX Can we remove this? */
19677a1a2bc18e7b04d4e352a8777ccce345b2f8659Behdad Esfahbod
1978e36ccfd4f076888076ca176c055c18104af03b6Behdad Esfahbodtemplate <typename set_t>
19877a1a2bc18e7b04d4e352a8777ccce345b2f8659Behdad Esfahbodstruct hb_add_coverage_context_t :
19977a1a2bc18e7b04d4e352a8777ccce345b2f8659Behdad Esfahbod       hb_dispatch_context_t<hb_add_coverage_context_t<set_t>, const Coverage &, HB_DEBUG_GET_COVERAGE>
2002005fa5340fc528c32dc2af945ad2431964a47d2Behdad Esfahbod{
201a1733db1c6ff40aae71fa142a12b1fea7b53dd37Behdad Esfahbod  inline const char *get_name (void) { return "GET_COVERAGE"; }
2022005fa5340fc528c32dc2af945ad2431964a47d2Behdad Esfahbod  typedef const Coverage &return_t;
2032005fa5340fc528c32dc2af945ad2431964a47d2Behdad Esfahbod  template <typename T>
2049c5a9ee967120c8a968a1160c420e03620d46c24Behdad Esfahbod  inline return_t dispatch (const T &obj) { return obj.get_coverage (); }
205a1733db1c6ff40aae71fa142a12b1fea7b53dd37Behdad Esfahbod  static return_t default_return_value (void) { return Null(Coverage); }
2068e36ccfd4f076888076ca176c055c18104af03b6Behdad Esfahbod  bool stop_sublookup_iteration (return_t r) const
2078e36ccfd4f076888076ca176c055c18104af03b6Behdad Esfahbod  {
2088e36ccfd4f076888076ca176c055c18104af03b6Behdad Esfahbod    r.add_coverage (set);
2098e36ccfd4f076888076ca176c055c18104af03b6Behdad Esfahbod    return false;
2108e36ccfd4f076888076ca176c055c18104af03b6Behdad Esfahbod  }
2111d67ef980f35ae30d4f8975f65ee07b8cc5deeeaBehdad Esfahbod
2128e36ccfd4f076888076ca176c055c18104af03b6Behdad Esfahbod  hb_add_coverage_context_t (set_t *set_) :
2138e36ccfd4f076888076ca176c055c18104af03b6Behdad Esfahbod			    set (set_),
214a1733db1c6ff40aae71fa142a12b1fea7b53dd37Behdad Esfahbod			    debug_depth (0) {}
215a1733db1c6ff40aae71fa142a12b1fea7b53dd37Behdad Esfahbod
2168e36ccfd4f076888076ca176c055c18104af03b6Behdad Esfahbod  set_t *set;
217a1733db1c6ff40aae71fa142a12b1fea7b53dd37Behdad Esfahbod  unsigned int debug_depth;
2182005fa5340fc528c32dc2af945ad2431964a47d2Behdad Esfahbod};
2192005fa5340fc528c32dc2af945ad2431964a47d2Behdad Esfahbod
2202005fa5340fc528c32dc2af945ad2431964a47d2Behdad Esfahbod
22177a1a2bc18e7b04d4e352a8777ccce345b2f8659Behdad Esfahbodstruct hb_apply_context_t :
22277a1a2bc18e7b04d4e352a8777ccce345b2f8659Behdad Esfahbod       hb_dispatch_context_t<hb_apply_context_t, bool, HB_DEBUG_APPLY>
2231376fb7bf9ef07970f0ba13dc64d6a8ab8252762Behdad Esfahbod{
224607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod  struct matcher_t
2254ab97311541225906f6b737a2b47de252224cc09Behdad Esfahbod  {
226607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod    inline matcher_t (void) :
227607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod	     lookup_props (0),
228cfc507c5432e6327e8484b07b9e091212653bc92Behdad Esfahbod	     ignore_zwnj (false),
229cfc507c5432e6327e8484b07b9e091212653bc92Behdad Esfahbod	     ignore_zwj (false),
230607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod	     mask (-1),
231607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod#define arg1(arg) (arg) /* Remove the macro to see why it's needed! */
232607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod	     syllable arg1(0),
233607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod#undef arg1
234dbdbfe3d7b36613d893832dcb1884c756c20bfdaBehdad Esfahbod	     match_func (nullptr),
235dbdbfe3d7b36613d893832dcb1884c756c20bfdaBehdad Esfahbod	     match_data (nullptr) {};
236607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod
2376f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod    typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const UINT16 &value, const void *data);
238607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod
239607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod    inline void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; }
2400b45479198d61d5135dad771e9c68408eb13f930Behdad Esfahbod    inline void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; }
241607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod    inline void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
242607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod    inline void set_mask (hb_mask_t mask_) { mask = mask_; }
243607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod    inline void set_syllable (uint8_t syllable_)  { syllable = syllable_; }
244607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod    inline void set_match_func (match_func_t match_func_,
245607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod				const void *match_data_)
246607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod    { match_func = match_func_; match_data = match_data_; }
247607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod
2482b2a6e8944144755ab641f2842e36d9a847719f3Behdad Esfahbod    enum may_match_t {
2492b2a6e8944144755ab641f2842e36d9a847719f3Behdad Esfahbod      MATCH_NO,
2502b2a6e8944144755ab641f2842e36d9a847719f3Behdad Esfahbod      MATCH_YES,
2512b2a6e8944144755ab641f2842e36d9a847719f3Behdad Esfahbod      MATCH_MAYBE
2522b2a6e8944144755ab641f2842e36d9a847719f3Behdad Esfahbod    };
2532b2a6e8944144755ab641f2842e36d9a847719f3Behdad Esfahbod
2542b2a6e8944144755ab641f2842e36d9a847719f3Behdad Esfahbod    inline may_match_t may_match (const hb_glyph_info_t &info,
2556f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod				  const UINT16          *glyph_data) const
2564ab97311541225906f6b737a2b47de252224cc09Behdad Esfahbod    {
2572b2a6e8944144755ab641f2842e36d9a847719f3Behdad Esfahbod      if (!(info.mask & mask) ||
2582b2a6e8944144755ab641f2842e36d9a847719f3Behdad Esfahbod	  (syllable && syllable != info.syllable ()))
2592b2a6e8944144755ab641f2842e36d9a847719f3Behdad Esfahbod	return MATCH_NO;
2602b2a6e8944144755ab641f2842e36d9a847719f3Behdad Esfahbod
2612b2a6e8944144755ab641f2842e36d9a847719f3Behdad Esfahbod      if (match_func)
2622b2a6e8944144755ab641f2842e36d9a847719f3Behdad Esfahbod        return match_func (info.codepoint, *glyph_data, match_data) ? MATCH_YES : MATCH_NO;
2632b2a6e8944144755ab641f2842e36d9a847719f3Behdad Esfahbod
2642b2a6e8944144755ab641f2842e36d9a847719f3Behdad Esfahbod      return MATCH_MAYBE;
2654ab97311541225906f6b737a2b47de252224cc09Behdad Esfahbod    }
266607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod
267607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod    enum may_skip_t {
268607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod      SKIP_NO,
269607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod      SKIP_YES,
270607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod      SKIP_MAYBE
271607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod    };
272607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod
273607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod    inline may_skip_t
274607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod    may_skip (const hb_apply_context_t *c,
275607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod	      const hb_glyph_info_t    &info) const
276c074ebc466dcc9bcc0d8a5dd7e942dea974ff718Behdad Esfahbod    {
277b98c5db32d15fcfb27ce2f6737203ce1ad124319Behdad Esfahbod      if (!c->check_glyph_property (&info, lookup_props))
278607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod	return SKIP_YES;
279607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod
28006cfe3f7369684fc05fa16da7f6778350f8bcba5Khaled Hosny      if (unlikely (_hb_glyph_info_is_default_ignorable_and_not_hidden (&info) &&
2810b45479198d61d5135dad771e9c68408eb13f930Behdad Esfahbod		    (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) &&
2824ba796b26ee62de0d2830a550f3aa3b4aecf6f59Behdad Esfahbod		    (ignore_zwj || !_hb_glyph_info_is_zwj (&info))))
283607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod	return SKIP_MAYBE;
284607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod
285607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod      return SKIP_NO;
286c074ebc466dcc9bcc0d8a5dd7e942dea974ff718Behdad Esfahbod    }
287607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod
288607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod    protected:
289607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod    unsigned int lookup_props;
290607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod    bool ignore_zwnj;
2910b45479198d61d5135dad771e9c68408eb13f930Behdad Esfahbod    bool ignore_zwj;
292607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod    hb_mask_t mask;
293607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod    uint8_t syllable;
294607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod    match_func_t match_func;
295607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod    const void *match_data;
296607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod  };
297607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod
298696266981df5ef6c62ad0115133dad1d6c1d9accBehdad Esfahbod  struct skipping_iterator_t
299607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod  {
300514564f5444b8ad2f210b1e3d7d66378f7275317Behdad Esfahbod    inline void init (hb_apply_context_t *c_, bool context_match = false)
3014ab97311541225906f6b737a2b47de252224cc09Behdad Esfahbod    {
302514564f5444b8ad2f210b1e3d7d66378f7275317Behdad Esfahbod      c = c_;
303dbdbfe3d7b36613d893832dcb1884c756c20bfdaBehdad Esfahbod      match_glyph_data = nullptr;
304dbdbfe3d7b36613d893832dcb1884c756c20bfdaBehdad Esfahbod      matcher.set_match_func (nullptr, nullptr);
305607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod      matcher.set_lookup_props (c->lookup_props);
306a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod      /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */
307cdf1fd0627c5517c948ca05d2e9427c3e441adf9Behdad Esfahbod      matcher.set_ignore_zwnj (c->table_index == 1 || (context_match && c->auto_zwnj));
308a8cf7b43fa795150ae3d42d64424bb6e0373d0b2Behdad Esfahbod      /* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */
309cdf1fd0627c5517c948ca05d2e9427c3e441adf9Behdad Esfahbod      matcher.set_ignore_zwj  (c->table_index == 1 || (context_match || c->auto_zwj));
310514564f5444b8ad2f210b1e3d7d66378f7275317Behdad Esfahbod      matcher.set_mask (context_match ? -1 : c->lookup_mask);
311514564f5444b8ad2f210b1e3d7d66378f7275317Behdad Esfahbod    }
312514564f5444b8ad2f210b1e3d7d66378f7275317Behdad Esfahbod    inline void set_lookup_props (unsigned int lookup_props)
313514564f5444b8ad2f210b1e3d7d66378f7275317Behdad Esfahbod    {
314514564f5444b8ad2f210b1e3d7d66378f7275317Behdad Esfahbod      matcher.set_lookup_props (lookup_props);
3154ab97311541225906f6b737a2b47de252224cc09Behdad Esfahbod    }
3164a6b1eedbb0044b57505eea65a329d2dc4f9f917Behdad Esfahbod    inline void set_match_func (matcher_t::match_func_t match_func_,
3174a6b1eedbb0044b57505eea65a329d2dc4f9f917Behdad Esfahbod				const void *match_data_,
3186f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod				const UINT16 glyph_data[])
3197b84c536c10ab90ed96a033d88e9ad232d46c5b8Behdad Esfahbod    {
3204a6b1eedbb0044b57505eea65a329d2dc4f9f917Behdad Esfahbod      matcher.set_match_func (match_func_, match_data_);
321607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod      match_glyph_data = glyph_data;
3227b84c536c10ab90ed96a033d88e9ad232d46c5b8Behdad Esfahbod    }
323607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod
324b051be542a8945ec14b0192bbc285f3e1a78c8f1Behdad Esfahbod    inline void reset (unsigned int start_index_,
325b051be542a8945ec14b0192bbc285f3e1a78c8f1Behdad Esfahbod		       unsigned int num_items_)
326b051be542a8945ec14b0192bbc285f3e1a78c8f1Behdad Esfahbod    {
327b051be542a8945ec14b0192bbc285f3e1a78c8f1Behdad Esfahbod      idx = start_index_;
328b051be542a8945ec14b0192bbc285f3e1a78c8f1Behdad Esfahbod      num_items = num_items_;
329b051be542a8945ec14b0192bbc285f3e1a78c8f1Behdad Esfahbod      end = c->buffer->len;
330b051be542a8945ec14b0192bbc285f3e1a78c8f1Behdad Esfahbod      matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
331b051be542a8945ec14b0192bbc285f3e1a78c8f1Behdad Esfahbod    }
332b051be542a8945ec14b0192bbc285f3e1a78c8f1Behdad Esfahbod
333607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod    inline void reject (void) { num_items++; match_glyph_data--; }
334696266981df5ef6c62ad0115133dad1d6c1d9accBehdad Esfahbod
3358b2c94c43fd335b944d5e5487265706b8e0f9041Behdad Esfahbod    inline matcher_t::may_skip_t
3368b2c94c43fd335b944d5e5487265706b8e0f9041Behdad Esfahbod    may_skip (const hb_apply_context_t *c,
3378b2c94c43fd335b944d5e5487265706b8e0f9041Behdad Esfahbod	      const hb_glyph_info_t    &info) const
3388b2c94c43fd335b944d5e5487265706b8e0f9041Behdad Esfahbod    {
3398b2c94c43fd335b944d5e5487265706b8e0f9041Behdad Esfahbod      return matcher.may_skip (c, info);
3408b2c94c43fd335b944d5e5487265706b8e0f9041Behdad Esfahbod    }
3418b2c94c43fd335b944d5e5487265706b8e0f9041Behdad Esfahbod
342c074ebc466dcc9bcc0d8a5dd7e942dea974ff718Behdad Esfahbod    inline bool next (void)
3434ab97311541225906f6b737a2b47de252224cc09Behdad Esfahbod    {
344506ffeb8e77a668fa305139582d215c32e46bb03Behdad Esfahbod      assert (num_items > 0);
34537d13acd8d414a4b53fac0152addfadecf755cd4Behdad Esfahbod      while (idx + num_items < end)
3464ab97311541225906f6b737a2b47de252224cc09Behdad Esfahbod      {
347a4a48fe6d4f884a37e720430347d10dbe3562a79Behdad Esfahbod	idx++;
348607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod	const hb_glyph_info_t &info = c->buffer->info[idx];
349607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod
350ff93ac8cb24cbc3d9dc1a2bfb0faa88950f4a507Behdad Esfahbod	matcher_t::may_skip_t skip = matcher.may_skip (c, info);
351607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod	if (unlikely (skip == matcher_t::SKIP_YES))
352607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod	  continue;
353607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod
3542b2a6e8944144755ab641f2842e36d9a847719f3Behdad Esfahbod	matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
355722e8b857eafc52e07dee5d9b253b88ed5c5c8edBehdad Esfahbod	if (match == matcher_t::MATCH_YES ||
356722e8b857eafc52e07dee5d9b253b88ed5c5c8edBehdad Esfahbod	    (match == matcher_t::MATCH_MAYBE &&
357722e8b857eafc52e07dee5d9b253b88ed5c5c8edBehdad Esfahbod	     skip == matcher_t::SKIP_NO))
358607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod	{
359607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod	  num_items--;
360607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod	  match_glyph_data++;
361607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod	  return true;
362607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod	}
363607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod
364607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod	if (skip == matcher_t::SKIP_NO)
365722e8b857eafc52e07dee5d9b253b88ed5c5c8edBehdad Esfahbod	  return false;
366607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod      }
367607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod      return false;
3684ab97311541225906f6b737a2b47de252224cc09Behdad Esfahbod    }
369c074ebc466dcc9bcc0d8a5dd7e942dea974ff718Behdad Esfahbod    inline bool prev (void)
3704ab97311541225906f6b737a2b47de252224cc09Behdad Esfahbod    {
371506ffeb8e77a668fa305139582d215c32e46bb03Behdad Esfahbod      assert (num_items > 0);
37237d13acd8d414a4b53fac0152addfadecf755cd4Behdad Esfahbod      while (idx >= num_items)
3734ab97311541225906f6b737a2b47de252224cc09Behdad Esfahbod      {
3744ab97311541225906f6b737a2b47de252224cc09Behdad Esfahbod	idx--;
375607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod	const hb_glyph_info_t &info = c->buffer->out_info[idx];
376607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod
377ff93ac8cb24cbc3d9dc1a2bfb0faa88950f4a507Behdad Esfahbod	matcher_t::may_skip_t skip = matcher.may_skip (c, info);
378607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod	if (unlikely (skip == matcher_t::SKIP_YES))
379607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod	  continue;
380607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod
3812b2a6e8944144755ab641f2842e36d9a847719f3Behdad Esfahbod	matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
382722e8b857eafc52e07dee5d9b253b88ed5c5c8edBehdad Esfahbod	if (match == matcher_t::MATCH_YES ||
383722e8b857eafc52e07dee5d9b253b88ed5c5c8edBehdad Esfahbod	    (match == matcher_t::MATCH_MAYBE &&
384722e8b857eafc52e07dee5d9b253b88ed5c5c8edBehdad Esfahbod	     skip == matcher_t::SKIP_NO))
385607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod	{
386607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod	  num_items--;
387607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod	  match_glyph_data++;
388607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod	  return true;
389607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod	}
390607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod
391607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod	if (skip == matcher_t::SKIP_NO)
392722e8b857eafc52e07dee5d9b253b88ed5c5c8edBehdad Esfahbod	  return false;
393607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod      }
394607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod      return false;
3954ab97311541225906f6b737a2b47de252224cc09Behdad Esfahbod    }
3964ab97311541225906f6b737a2b47de252224cc09Behdad Esfahbod
3974ab97311541225906f6b737a2b47de252224cc09Behdad Esfahbod    unsigned int idx;
398ec8d2494694275dfbbac2dd0d33ca2894b0463d6Behdad Esfahbod    protected:
3994ab97311541225906f6b737a2b47de252224cc09Behdad Esfahbod    hb_apply_context_t *c;
400607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod    matcher_t matcher;
4016f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod    const UINT16 *match_glyph_data;
402607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod
4034ab97311541225906f6b737a2b47de252224cc09Behdad Esfahbod    unsigned int num_items;
404696266981df5ef6c62ad0115133dad1d6c1d9accBehdad Esfahbod    unsigned int end;
4054ab97311541225906f6b737a2b47de252224cc09Behdad Esfahbod  };
4064ab97311541225906f6b737a2b47de252224cc09Behdad Esfahbod
4072cecc38c7cf49b2cf697efa7e974ceee7055f2c5Behdad Esfahbod
4082cecc38c7cf49b2cf697efa7e974ceee7055f2c5Behdad Esfahbod  inline const char *get_name (void) { return "APPLY"; }
4092cecc38c7cf49b2cf697efa7e974ceee7055f2c5Behdad Esfahbod  typedef return_t (*recurse_func_t) (hb_apply_context_t *c, unsigned int lookup_index);
4102cecc38c7cf49b2cf697efa7e974ceee7055f2c5Behdad Esfahbod  template <typename T>
4112cecc38c7cf49b2cf697efa7e974ceee7055f2c5Behdad Esfahbod  inline return_t dispatch (const T &obj) { return obj.apply (this); }
4122cecc38c7cf49b2cf697efa7e974ceee7055f2c5Behdad Esfahbod  static return_t default_return_value (void) { return false; }
4132cecc38c7cf49b2cf697efa7e974ceee7055f2c5Behdad Esfahbod  bool stop_sublookup_iteration (return_t r) const { return r; }
4142cecc38c7cf49b2cf697efa7e974ceee7055f2c5Behdad Esfahbod  return_t recurse (unsigned int lookup_index)
4152cecc38c7cf49b2cf697efa7e974ceee7055f2c5Behdad Esfahbod  {
416baf7779d2d6e4810168a8f036bbf8f9e6493dd1aBehdad Esfahbod    if (unlikely (nesting_level_left == 0 || !recurse_func || buffer->max_ops-- <= 0))
4172cecc38c7cf49b2cf697efa7e974ceee7055f2c5Behdad Esfahbod      return default_return_value ();
4182cecc38c7cf49b2cf697efa7e974ceee7055f2c5Behdad Esfahbod
4192cecc38c7cf49b2cf697efa7e974ceee7055f2c5Behdad Esfahbod    nesting_level_left--;
4202cecc38c7cf49b2cf697efa7e974ceee7055f2c5Behdad Esfahbod    bool ret = recurse_func (this, lookup_index);
4212cecc38c7cf49b2cf697efa7e974ceee7055f2c5Behdad Esfahbod    nesting_level_left++;
4222cecc38c7cf49b2cf697efa7e974ceee7055f2c5Behdad Esfahbod    return ret;
4232cecc38c7cf49b2cf697efa7e974ceee7055f2c5Behdad Esfahbod  }
4242cecc38c7cf49b2cf697efa7e974ceee7055f2c5Behdad Esfahbod
425cdf1fd0627c5517c948ca05d2e9427c3e441adf9Behdad Esfahbod  skipping_iterator_t iter_input, iter_context;
426cdf1fd0627c5517c948ca05d2e9427c3e441adf9Behdad Esfahbod
4272cecc38c7cf49b2cf697efa7e974ceee7055f2c5Behdad Esfahbod  hb_font_t *font;
4282cecc38c7cf49b2cf697efa7e974ceee7055f2c5Behdad Esfahbod  hb_face_t *face;
4292cecc38c7cf49b2cf697efa7e974ceee7055f2c5Behdad Esfahbod  hb_buffer_t *buffer;
4302cecc38c7cf49b2cf697efa7e974ceee7055f2c5Behdad Esfahbod  recurse_func_t recurse_func;
4312cecc38c7cf49b2cf697efa7e974ceee7055f2c5Behdad Esfahbod  const GDEF &gdef;
432cf3de4d8f79fc6e8413957cdef034e975343ce30Behdad Esfahbod  const VariationStore &var_store;
433cdf1fd0627c5517c948ca05d2e9427c3e441adf9Behdad Esfahbod
434cdf1fd0627c5517c948ca05d2e9427c3e441adf9Behdad Esfahbod  hb_direction_t direction;
435cdf1fd0627c5517c948ca05d2e9427c3e441adf9Behdad Esfahbod  hb_mask_t lookup_mask;
436cdf1fd0627c5517c948ca05d2e9427c3e441adf9Behdad Esfahbod  unsigned int table_index; /* GSUB/GPOS */
4372c8b3b2e5312c9858584f568b1528c57e5bb8a10Behdad Esfahbod  unsigned int lookup_index;
438cdf1fd0627c5517c948ca05d2e9427c3e441adf9Behdad Esfahbod  unsigned int lookup_props;
439cdf1fd0627c5517c948ca05d2e9427c3e441adf9Behdad Esfahbod  unsigned int nesting_level_left;
4402cecc38c7cf49b2cf697efa7e974ceee7055f2c5Behdad Esfahbod  unsigned int debug_depth;
4412cecc38c7cf49b2cf697efa7e974ceee7055f2c5Behdad Esfahbod
442cdf1fd0627c5517c948ca05d2e9427c3e441adf9Behdad Esfahbod  bool auto_zwnj;
443cdf1fd0627c5517c948ca05d2e9427c3e441adf9Behdad Esfahbod  bool auto_zwj;
444cdf1fd0627c5517c948ca05d2e9427c3e441adf9Behdad Esfahbod  bool has_glyph_classes;
445cdf1fd0627c5517c948ca05d2e9427c3e441adf9Behdad Esfahbod
4462cecc38c7cf49b2cf697efa7e974ceee7055f2c5Behdad Esfahbod
4472cecc38c7cf49b2cf697efa7e974ceee7055f2c5Behdad Esfahbod  hb_apply_context_t (unsigned int table_index_,
4482cecc38c7cf49b2cf697efa7e974ceee7055f2c5Behdad Esfahbod		      hb_font_t *font_,
4492cecc38c7cf49b2cf697efa7e974ceee7055f2c5Behdad Esfahbod		      hb_buffer_t *buffer_) :
450cdf1fd0627c5517c948ca05d2e9427c3e441adf9Behdad Esfahbod			iter_input (), iter_context (),
4512cecc38c7cf49b2cf697efa7e974ceee7055f2c5Behdad Esfahbod			font (font_), face (font->face), buffer (buffer_),
452dbdbfe3d7b36613d893832dcb1884c756c20bfdaBehdad Esfahbod			recurse_func (nullptr),
4532cecc38c7cf49b2cf697efa7e974ceee7055f2c5Behdad Esfahbod			gdef (*hb_ot_layout_from_face (face)->gdef),
454151d93de8a595924a8dcb00fcba648b4b3df0bf5Behdad Esfahbod			var_store (gdef.get_var_store ()),
455cdf1fd0627c5517c948ca05d2e9427c3e441adf9Behdad Esfahbod			direction (buffer_->props.direction),
456cdf1fd0627c5517c948ca05d2e9427c3e441adf9Behdad Esfahbod			lookup_mask (1),
457cdf1fd0627c5517c948ca05d2e9427c3e441adf9Behdad Esfahbod			table_index (table_index_),
4582c8b3b2e5312c9858584f568b1528c57e5bb8a10Behdad Esfahbod			lookup_index ((unsigned int) -1),
459cdf1fd0627c5517c948ca05d2e9427c3e441adf9Behdad Esfahbod			lookup_props (0),
460cdf1fd0627c5517c948ca05d2e9427c3e441adf9Behdad Esfahbod			nesting_level_left (HB_MAX_NESTING_LEVEL),
461cdf1fd0627c5517c948ca05d2e9427c3e441adf9Behdad Esfahbod			debug_depth (0),
462cdf1fd0627c5517c948ca05d2e9427c3e441adf9Behdad Esfahbod			auto_zwnj (true),
463cdf1fd0627c5517c948ca05d2e9427c3e441adf9Behdad Esfahbod			auto_zwj (true),
464cdf1fd0627c5517c948ca05d2e9427c3e441adf9Behdad Esfahbod			has_glyph_classes (gdef.has_glyph_classes ()) {}
4652cecc38c7cf49b2cf697efa7e974ceee7055f2c5Behdad Esfahbod
4662cecc38c7cf49b2cf697efa7e974ceee7055f2c5Behdad Esfahbod  inline void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; }
4672cecc38c7cf49b2cf697efa7e974ceee7055f2c5Behdad Esfahbod  inline void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; }
468cdf1fd0627c5517c948ca05d2e9427c3e441adf9Behdad Esfahbod  inline void set_auto_zwnj (bool auto_zwnj_) { auto_zwnj = auto_zwnj_; }
4692cecc38c7cf49b2cf697efa7e974ceee7055f2c5Behdad Esfahbod  inline void set_recurse_func (recurse_func_t func) { recurse_func = func; }
4702c8b3b2e5312c9858584f568b1528c57e5bb8a10Behdad Esfahbod  inline void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; }
471365576d246949f9d587e90cf0539dc0381e4d0a3Behdad Esfahbod  inline void set_lookup_props (unsigned int lookup_props_)
472365576d246949f9d587e90cf0539dc0381e4d0a3Behdad Esfahbod  {
473365576d246949f9d587e90cf0539dc0381e4d0a3Behdad Esfahbod    lookup_props = lookup_props_;
474365576d246949f9d587e90cf0539dc0381e4d0a3Behdad Esfahbod    iter_input.init (this, false);
475365576d246949f9d587e90cf0539dc0381e4d0a3Behdad Esfahbod    iter_context.init (this, true);
476365576d246949f9d587e90cf0539dc0381e4d0a3Behdad Esfahbod  }
4772cecc38c7cf49b2cf697efa7e974ceee7055f2c5Behdad Esfahbod
47803f67bc012f42131b36083a23efc78e1b04b828cBehdad Esfahbod  inline bool
47903f67bc012f42131b36083a23efc78e1b04b828cBehdad Esfahbod  match_properties_mark (hb_codepoint_t  glyph,
48003f67bc012f42131b36083a23efc78e1b04b828cBehdad Esfahbod			 unsigned int    glyph_props,
481b931e0b0ceeab0e4819d9c4b838c1a1eb87b52e4Behdad Esfahbod			 unsigned int    match_props) const
48203f67bc012f42131b36083a23efc78e1b04b828cBehdad Esfahbod  {
48303f67bc012f42131b36083a23efc78e1b04b828cBehdad Esfahbod    /* If using mark filtering sets, the high short of
484b931e0b0ceeab0e4819d9c4b838c1a1eb87b52e4Behdad Esfahbod     * match_props has the set index.
48503f67bc012f42131b36083a23efc78e1b04b828cBehdad Esfahbod     */
486b931e0b0ceeab0e4819d9c4b838c1a1eb87b52e4Behdad Esfahbod    if (match_props & LookupFlag::UseMarkFilteringSet)
487b931e0b0ceeab0e4819d9c4b838c1a1eb87b52e4Behdad Esfahbod      return gdef.mark_set_covers (match_props >> 16, glyph);
48803f67bc012f42131b36083a23efc78e1b04b828cBehdad Esfahbod
489b931e0b0ceeab0e4819d9c4b838c1a1eb87b52e4Behdad Esfahbod    /* The second byte of match_props has the meaning
49003f67bc012f42131b36083a23efc78e1b04b828cBehdad Esfahbod     * "ignore marks of attachment type different than
49103f67bc012f42131b36083a23efc78e1b04b828cBehdad Esfahbod     * the attachment type specified."
49203f67bc012f42131b36083a23efc78e1b04b828cBehdad Esfahbod     */
493b931e0b0ceeab0e4819d9c4b838c1a1eb87b52e4Behdad Esfahbod    if (match_props & LookupFlag::MarkAttachmentType)
494b931e0b0ceeab0e4819d9c4b838c1a1eb87b52e4Behdad Esfahbod      return (match_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType);
49503f67bc012f42131b36083a23efc78e1b04b828cBehdad Esfahbod
49603f67bc012f42131b36083a23efc78e1b04b828cBehdad Esfahbod    return true;
49703f67bc012f42131b36083a23efc78e1b04b828cBehdad Esfahbod  }
49803f67bc012f42131b36083a23efc78e1b04b828cBehdad Esfahbod
49903f67bc012f42131b36083a23efc78e1b04b828cBehdad Esfahbod  inline bool
500b98c5db32d15fcfb27ce2f6737203ce1ad124319Behdad Esfahbod  check_glyph_property (const hb_glyph_info_t *info,
501b931e0b0ceeab0e4819d9c4b838c1a1eb87b52e4Behdad Esfahbod			unsigned int  match_props) const
50203f67bc012f42131b36083a23efc78e1b04b828cBehdad Esfahbod  {
503b98c5db32d15fcfb27ce2f6737203ce1ad124319Behdad Esfahbod    hb_codepoint_t glyph = info->codepoint;
504b98c5db32d15fcfb27ce2f6737203ce1ad124319Behdad Esfahbod    unsigned int glyph_props = _hb_glyph_info_get_glyph_props (info);
505b98c5db32d15fcfb27ce2f6737203ce1ad124319Behdad Esfahbod
50603f67bc012f42131b36083a23efc78e1b04b828cBehdad Esfahbod    /* Not covered, if, for example, glyph class is ligature and
507b931e0b0ceeab0e4819d9c4b838c1a1eb87b52e4Behdad Esfahbod     * match_props includes LookupFlags::IgnoreLigatures
50803f67bc012f42131b36083a23efc78e1b04b828cBehdad Esfahbod     */
509b931e0b0ceeab0e4819d9c4b838c1a1eb87b52e4Behdad Esfahbod    if (glyph_props & match_props & LookupFlag::IgnoreFlags)
51003f67bc012f42131b36083a23efc78e1b04b828cBehdad Esfahbod      return false;
51103f67bc012f42131b36083a23efc78e1b04b828cBehdad Esfahbod
5125a08ecf9200a6ac9b4ebb7ec5c13dcb42d8820ceBehdad Esfahbod    if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK))
513b931e0b0ceeab0e4819d9c4b838c1a1eb87b52e4Behdad Esfahbod      return match_properties_mark (glyph, glyph_props, match_props);
51403f67bc012f42131b36083a23efc78e1b04b828cBehdad Esfahbod
51503f67bc012f42131b36083a23efc78e1b04b828cBehdad Esfahbod    return true;
51603f67bc012f42131b36083a23efc78e1b04b828cBehdad Esfahbod  }
51703f67bc012f42131b36083a23efc78e1b04b828cBehdad Esfahbod
518a0161746589934e93c3b115814bbd81f56ab962fBehdad Esfahbod  inline void _set_glyph_props (hb_codepoint_t glyph_index,
51971b4c999a511bf018acaf48a45e070470c0daf12Behdad Esfahbod			  unsigned int class_guess = 0,
520832a6f99b34f334b1e82b8e3a7ad137e823d203cBehdad Esfahbod			  bool ligature = false,
521832a6f99b34f334b1e82b8e3a7ad137e823d203cBehdad Esfahbod			  bool component = false) const
52260da763dfac96a7931d6e6bdef8b9973bd5209abBehdad Esfahbod  {
52309675a8115b9d77261c33940401aa919cede8662Behdad Esfahbod    unsigned int add_in = _hb_glyph_info_get_glyph_props (&buffer->cur()) &
52409675a8115b9d77261c33940401aa919cede8662Behdad Esfahbod			  HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE;
52509675a8115b9d77261c33940401aa919cede8662Behdad Esfahbod    add_in |= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED;
52609675a8115b9d77261c33940401aa919cede8662Behdad Esfahbod    if (ligature)
527832a6f99b34f334b1e82b8e3a7ad137e823d203cBehdad Esfahbod    {
52809675a8115b9d77261c33940401aa919cede8662Behdad Esfahbod      add_in |= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED;
529832a6f99b34f334b1e82b8e3a7ad137e823d203cBehdad Esfahbod      /* In the only place that the MULTIPLIED bit is used, Uniscribe
530832a6f99b34f334b1e82b8e3a7ad137e823d203cBehdad Esfahbod       * seems to only care about the "last" transformation between
531832a6f99b34f334b1e82b8e3a7ad137e823d203cBehdad Esfahbod       * Ligature and Multiple substitions.  Ie. if you ligate, expand,
532832a6f99b34f334b1e82b8e3a7ad137e823d203cBehdad Esfahbod       * and ligate again, it forgives the multiplication and acts as
533832a6f99b34f334b1e82b8e3a7ad137e823d203cBehdad Esfahbod       * if only ligation happened.  As such, clear MULTIPLIED bit.
534832a6f99b34f334b1e82b8e3a7ad137e823d203cBehdad Esfahbod       */
535832a6f99b34f334b1e82b8e3a7ad137e823d203cBehdad Esfahbod      add_in &= ~HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
536832a6f99b34f334b1e82b8e3a7ad137e823d203cBehdad Esfahbod    }
537832a6f99b34f334b1e82b8e3a7ad137e823d203cBehdad Esfahbod    if (component)
538832a6f99b34f334b1e82b8e3a7ad137e823d203cBehdad Esfahbod      add_in |= HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
5392fca1426ca06cabbe8f027f2dc9dee9c27560c76Behdad Esfahbod    if (likely (has_glyph_classes))
54005ad6b50ac0a1b9a8da10d2ee2238068b7811e7dBehdad Esfahbod      _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | gdef.get_glyph_props (glyph_index));
54105bd1b63426e07d1df7a1b40bf845dc94ab995a8Behdad Esfahbod    else if (class_guess)
54209675a8115b9d77261c33940401aa919cede8662Behdad Esfahbod      _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | class_guess);
54360da763dfac96a7931d6e6bdef8b9973bd5209abBehdad Esfahbod  }
5444ab97311541225906f6b737a2b47de252224cc09Behdad Esfahbod
545a0161746589934e93c3b115814bbd81f56ab962fBehdad Esfahbod  inline void replace_glyph (hb_codepoint_t glyph_index) const
5463ec77d6ae0510dc2c0ec64382c4948bc6e109844Behdad Esfahbod  {
547a0161746589934e93c3b115814bbd81f56ab962fBehdad Esfahbod    _set_glyph_props (glyph_index);
548a0161746589934e93c3b115814bbd81f56ab962fBehdad Esfahbod    buffer->replace_glyph (glyph_index);
5493ec77d6ae0510dc2c0ec64382c4948bc6e109844Behdad Esfahbod  }
550a0161746589934e93c3b115814bbd81f56ab962fBehdad Esfahbod  inline void replace_glyph_inplace (hb_codepoint_t glyph_index) const
55198370e89d1bff248737b482d129c2a4deb8bfd95Behdad Esfahbod  {
552a0161746589934e93c3b115814bbd81f56ab962fBehdad Esfahbod    _set_glyph_props (glyph_index);
553a0161746589934e93c3b115814bbd81f56ab962fBehdad Esfahbod    buffer->cur().codepoint = glyph_index;
554a0161746589934e93c3b115814bbd81f56ab962fBehdad Esfahbod  }
555a0161746589934e93c3b115814bbd81f56ab962fBehdad Esfahbod  inline void replace_glyph_with_ligature (hb_codepoint_t glyph_index,
556a0161746589934e93c3b115814bbd81f56ab962fBehdad Esfahbod					   unsigned int class_guess) const
557a0161746589934e93c3b115814bbd81f56ab962fBehdad Esfahbod  {
55809675a8115b9d77261c33940401aa919cede8662Behdad Esfahbod    _set_glyph_props (glyph_index, class_guess, true);
55998370e89d1bff248737b482d129c2a4deb8bfd95Behdad Esfahbod    buffer->replace_glyph (glyph_index);
56098370e89d1bff248737b482d129c2a4deb8bfd95Behdad Esfahbod  }
561832a6f99b34f334b1e82b8e3a7ad137e823d203cBehdad Esfahbod  inline void output_glyph_for_component (hb_codepoint_t glyph_index,
562832a6f99b34f334b1e82b8e3a7ad137e823d203cBehdad Esfahbod					  unsigned int class_guess) const
5637fbbf86efe675e4c038dfc5985c24bbc544620cdBehdad Esfahbod  {
564832a6f99b34f334b1e82b8e3a7ad137e823d203cBehdad Esfahbod    _set_glyph_props (glyph_index, class_guess, false, true);
565a0161746589934e93c3b115814bbd81f56ab962fBehdad Esfahbod    buffer->output_glyph (glyph_index);
5667fbbf86efe675e4c038dfc5985c24bbc544620cdBehdad Esfahbod  }
5671376fb7bf9ef07970f0ba13dc64d6a8ab8252762Behdad Esfahbod};
5681376fb7bf9ef07970f0ba13dc64d6a8ab8252762Behdad Esfahbod
56966bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod
57094a23aaeca39c662614037ef887412249bdc8d49Behdad Esfahbod
5716f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbodtypedef bool (*intersects_func_t) (hb_set_t *glyphs, const UINT16 &value, const void *data);
5726f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbodtypedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const UINT16 &value, const void *data);
5736f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbodtypedef bool (*match_func_t) (hb_codepoint_t glyph_id, const UINT16 &value, const void *data);
57466bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod
57531081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbodstruct ContextClosureFuncs
57631081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod{
57731081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod  intersects_func_t intersects;
57831081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod};
579d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbodstruct ContextCollectGlyphsFuncs
580d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod{
581d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod  collect_glyphs_func_t collect;
582d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod};
58331081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbodstruct ContextApplyFuncs
58460d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod{
58548f16ed96ac7041b511d9e0864623d2aa09c6da3Behdad Esfahbod  match_func_t match;
58666bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod};
58766bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod
588d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod
5896f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbodstatic inline bool intersects_glyph (hb_set_t *glyphs, const UINT16 &value, const void *data HB_UNUSED)
59031081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod{
59131081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod  return glyphs->has (value);
59231081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod}
5936f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbodstatic inline bool intersects_class (hb_set_t *glyphs, const UINT16 &value, const void *data)
59431081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod{
59531081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod  const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
59631081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod  return class_def.intersects_class (glyphs, value);
59731081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod}
5986f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbodstatic inline bool intersects_coverage (hb_set_t *glyphs, const UINT16 &value, const void *data)
59931081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod{
60031081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod  const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
60131081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod  return (data+coverage).intersects (glyphs);
60231081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod}
60331081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod
60431081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbodstatic inline bool intersects_array (hb_closure_context_t *c,
60531081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod				     unsigned int count,
6066f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod				     const UINT16 values[],
60731081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod				     intersects_func_t intersects_func,
60831081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod				     const void *intersects_data)
60931081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod{
61031081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod  for (unsigned int i = 0; i < count; i++)
61131081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod    if (likely (!intersects_func (c->glyphs, values[i], intersects_data)))
61231081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod      return false;
61331081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod  return true;
61431081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod}
61531081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod
616f14c2b7acfba75b8a6880f41ceec758f9a56abceBehdad Esfahbod
6176f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbodstatic inline void collect_glyph (hb_set_t *glyphs, const UINT16 &value, const void *data HB_UNUSED)
618d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod{
619d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod  glyphs->add (value);
620d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod}
6216f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbodstatic inline void collect_class (hb_set_t *glyphs, const UINT16 &value, const void *data)
622d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod{
623d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod  const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
62471e6adf1e2d65eb905a0ba247672fe36169955efBehdad Esfahbod  class_def.add_class (glyphs, value);
625d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod}
6266f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbodstatic inline void collect_coverage (hb_set_t *glyphs, const UINT16 &value, const void *data)
627d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod{
628d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod  const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
629d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod  (data+coverage).add_coverage (glyphs);
630d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod}
6310beb66e3a61ae8bb1fa66e54b1ff1abb2f8711e9Behdad Esfahbodstatic inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED,
632f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod				  hb_set_t *glyphs,
633d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod				  unsigned int count,
6346f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod				  const UINT16 values[],
635d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod				  collect_glyphs_func_t collect_func,
636d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod				  const void *collect_data)
637d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod{
638d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod  for (unsigned int i = 0; i < count; i++)
639f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod    collect_func (glyphs, values[i], collect_data);
640d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod}
641d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod
642d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod
6436f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbodstatic inline bool match_glyph (hb_codepoint_t glyph_id, const UINT16 &value, const void *data HB_UNUSED)
64460d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod{
64548f16ed96ac7041b511d9e0864623d2aa09c6da3Behdad Esfahbod  return glyph_id == value;
64648f16ed96ac7041b511d9e0864623d2aa09c6da3Behdad Esfahbod}
6476f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbodstatic inline bool match_class (hb_codepoint_t glyph_id, const UINT16 &value, const void *data)
64860d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod{
6492b5a59c277f4c5bf7aac9a9005054763e322e02dBehdad Esfahbod  const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
65048f16ed96ac7041b511d9e0864623d2aa09c6da3Behdad Esfahbod  return class_def.get_class (glyph_id) == value;
65148f16ed96ac7041b511d9e0864623d2aa09c6da3Behdad Esfahbod}
6526f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbodstatic inline bool match_coverage (hb_codepoint_t glyph_id, const UINT16 &value, const void *data)
65360d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod{
6546b54c5d0446b514fbb6521e7e9e614d153435f0eBehdad Esfahbod  const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
65531081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod  return (data+coverage).get_coverage (glyph_id) != NOT_COVERED;
65648f16ed96ac7041b511d9e0864623d2aa09c6da3Behdad Esfahbod}
65748f16ed96ac7041b511d9e0864623d2aa09c6da3Behdad Esfahbod
658e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbodstatic inline bool would_match_input (hb_would_apply_context_t *c,
659e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod				      unsigned int count, /* Including the first glyph (not matched) */
6606f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod				      const UINT16 input[], /* Array of input values--start with second glyph */
661e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod				      match_func_t match_func,
662e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod				      const void *match_data)
663e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod{
664e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod  if (count != c->len)
665e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod    return false;
666e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod
667e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod  for (unsigned int i = 1; i < count; i++)
668472f229a63f0d1bb21b02179ef430b7698df8f12Behdad Esfahbod    if (likely (!match_func (c->glyphs[i], input[i - 1], match_data)))
669e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod      return false;
670e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod
671e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod  return true;
672e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod}
673d7cfb3b2d1dd2e9fdae2b3e540bbe313660895e8Behdad Esfahbodstatic inline bool match_input (hb_apply_context_t *c,
674d0ba0557007798db2c60ddd0b7a5a0624cd1698dBehdad Esfahbod				unsigned int count, /* Including the first glyph (not matched) */
6756f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod				const UINT16 input[], /* Array of input values--start with second glyph */
676d0ba0557007798db2c60ddd0b7a5a0624cd1698dBehdad Esfahbod				match_func_t match_func,
67740cbefe858192531ed64dd51d402f7ca7b8153a3Behdad Esfahbod				const void *match_data,
6786cc136f7531a45e71ea08a7dc8a2187172cb813dBehdad Esfahbod				unsigned int *end_offset,
6795ba450407b9d9856453e63a815499da8721ff6a7Behdad Esfahbod				unsigned int match_positions[HB_MAX_CONTEXT_LENGTH],
680dbdbfe3d7b36613d893832dcb1884c756c20bfdaBehdad Esfahbod				bool *p_is_mark_ligature = nullptr,
681dbdbfe3d7b36613d893832dcb1884c756c20bfdaBehdad Esfahbod				unsigned int *p_total_component_count = nullptr)
682d0ba0557007798db2c60ddd0b7a5a0624cd1698dBehdad Esfahbod{
683dbdbfe3d7b36613d893832dcb1884c756c20bfdaBehdad Esfahbod  TRACE_APPLY (nullptr);
68493814ca7dc2a7251f861c1c47ba155ba6e6bdf19Behdad Esfahbod
6855ba450407b9d9856453e63a815499da8721ff6a7Behdad Esfahbod  if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return_trace (false);
6866b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod
6873c3df9cba13fec2c35e0e7ae587d9699ac0c37f5Behdad Esfahbod  hb_buffer_t *buffer = c->buffer;
6883c3df9cba13fec2c35e0e7ae587d9699ac0c37f5Behdad Esfahbod
689365576d246949f9d587e90cf0539dc0381e4d0a3Behdad Esfahbod  hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
690b051be542a8945ec14b0192bbc285f3e1a78c8f1Behdad Esfahbod  skippy_iter.reset (buffer->idx, count - 1);
691607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod  skippy_iter.set_match_func (match_func, match_data, input);
69293814ca7dc2a7251f861c1c47ba155ba6e6bdf19Behdad Esfahbod
693191fa885d9e0a2dce92dd8727cddd18495e62409Behdad Esfahbod  /*
694191fa885d9e0a2dce92dd8727cddd18495e62409Behdad Esfahbod   * This is perhaps the trickiest part of OpenType...  Remarks:
695191fa885d9e0a2dce92dd8727cddd18495e62409Behdad Esfahbod   *
696191fa885d9e0a2dce92dd8727cddd18495e62409Behdad Esfahbod   * - If all components of the ligature were marks, we call this a mark ligature.
697191fa885d9e0a2dce92dd8727cddd18495e62409Behdad Esfahbod   *
698191fa885d9e0a2dce92dd8727cddd18495e62409Behdad Esfahbod   * - If there is no GDEF, and the ligature is NOT a mark ligature, we categorize
699191fa885d9e0a2dce92dd8727cddd18495e62409Behdad Esfahbod   *   it as a ligature glyph.
700191fa885d9e0a2dce92dd8727cddd18495e62409Behdad Esfahbod   *
701191fa885d9e0a2dce92dd8727cddd18495e62409Behdad Esfahbod   * - Ligatures cannot be formed across glyphs attached to different components
702191fa885d9e0a2dce92dd8727cddd18495e62409Behdad Esfahbod   *   of previous ligatures.  Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and
703191fa885d9e0a2dce92dd8727cddd18495e62409Behdad Esfahbod   *   LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother.
7048b2c94c43fd335b944d5e5487265706b8e0f9041Behdad Esfahbod   *   However, it would be wrong to ligate that SHADDA,FATHA sequence.
7058b2c94c43fd335b944d5e5487265706b8e0f9041Behdad Esfahbod   *   There are a couple of exceptions to this:
7068b2c94c43fd335b944d5e5487265706b8e0f9041Behdad Esfahbod   *
7078b2c94c43fd335b944d5e5487265706b8e0f9041Behdad Esfahbod   *   o If a ligature tries ligating with marks that belong to it itself, go ahead,
7088b2c94c43fd335b944d5e5487265706b8e0f9041Behdad Esfahbod   *     assuming that the font designer knows what they are doing (otherwise it can
7098b2c94c43fd335b944d5e5487265706b8e0f9041Behdad Esfahbod   *     break Indic stuff when a matra wants to ligate with a conjunct,
7108b2c94c43fd335b944d5e5487265706b8e0f9041Behdad Esfahbod   *
7118b2c94c43fd335b944d5e5487265706b8e0f9041Behdad Esfahbod   *   o If two marks want to ligate and they belong to different components of the
7128b2c94c43fd335b944d5e5487265706b8e0f9041Behdad Esfahbod   *     same ligature glyph, and said ligature glyph is to be ignored according to
7138b2c94c43fd335b944d5e5487265706b8e0f9041Behdad Esfahbod   *     mark-filtering rules, then allow.
7147c6937e7c7b62602fef10ac4b2e164d0c67c932bebraminio   *     https://github.com/harfbuzz/harfbuzz/issues/545
715191fa885d9e0a2dce92dd8727cddd18495e62409Behdad Esfahbod   */
716191fa885d9e0a2dce92dd8727cddd18495e62409Behdad Esfahbod
717101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod  bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->cur());
71893814ca7dc2a7251f861c1c47ba155ba6e6bdf19Behdad Esfahbod
71993814ca7dc2a7251f861c1c47ba155ba6e6bdf19Behdad Esfahbod  unsigned int total_component_count = 0;
7203ddf892b5328b74afb6e7d9da727d8771ca5d288Behdad Esfahbod  total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur());
72193814ca7dc2a7251f861c1c47ba155ba6e6bdf19Behdad Esfahbod
7223ddf892b5328b74afb6e7d9da727d8771ca5d288Behdad Esfahbod  unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
7233ddf892b5328b74afb6e7d9da727d8771ca5d288Behdad Esfahbod  unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
724d0ba0557007798db2c60ddd0b7a5a0624cd1698dBehdad Esfahbod
725621c49cb8657a79ee6897c4d313d0e825b2b228fBehdad Esfahbod  enum {
726621c49cb8657a79ee6897c4d313d0e825b2b228fBehdad Esfahbod    LIGBASE_NOT_CHECKED,
727621c49cb8657a79ee6897c4d313d0e825b2b228fBehdad Esfahbod    LIGBASE_MAY_NOT_SKIP,
728621c49cb8657a79ee6897c4d313d0e825b2b228fBehdad Esfahbod    LIGBASE_MAY_SKIP
729621c49cb8657a79ee6897c4d313d0e825b2b228fBehdad Esfahbod  } ligbase = LIGBASE_NOT_CHECKED;
730621c49cb8657a79ee6897c4d313d0e825b2b228fBehdad Esfahbod
7313c3df9cba13fec2c35e0e7ae587d9699ac0c37f5Behdad Esfahbod  match_positions[0] = buffer->idx;
732370f03e9c69d98d735eafb7e72b13b17f42cbaa9Behdad Esfahbod  for (unsigned int i = 1; i < count; i++)
73360d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod  {
734b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    if (!skippy_iter.next ()) return_trace (false);
7356cc136f7531a45e71ea08a7dc8a2187172cb813dBehdad Esfahbod
7366cc136f7531a45e71ea08a7dc8a2187172cb813dBehdad Esfahbod    match_positions[i] = skippy_iter.idx;
73793814ca7dc2a7251f861c1c47ba155ba6e6bdf19Behdad Esfahbod
7383ddf892b5328b74afb6e7d9da727d8771ca5d288Behdad Esfahbod    unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]);
7393ddf892b5328b74afb6e7d9da727d8771ca5d288Behdad Esfahbod    unsigned int this_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]);
74093814ca7dc2a7251f861c1c47ba155ba6e6bdf19Behdad Esfahbod
7418b2c94c43fd335b944d5e5487265706b8e0f9041Behdad Esfahbod    if (first_lig_id && first_lig_comp)
7428b2c94c43fd335b944d5e5487265706b8e0f9041Behdad Esfahbod    {
74393814ca7dc2a7251f861c1c47ba155ba6e6bdf19Behdad Esfahbod      /* If first component was attached to a previous ligature component,
74493814ca7dc2a7251f861c1c47ba155ba6e6bdf19Behdad Esfahbod       * all subsequent components should be attached to the same ligature
7458b2c94c43fd335b944d5e5487265706b8e0f9041Behdad Esfahbod       * component, otherwise we shouldn't ligate them... */
74693814ca7dc2a7251f861c1c47ba155ba6e6bdf19Behdad Esfahbod      if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp)
7478b2c94c43fd335b944d5e5487265706b8e0f9041Behdad Esfahbod      {
7488b2c94c43fd335b944d5e5487265706b8e0f9041Behdad Esfahbod        /* ...unless, we are attached to a base ligature and that base
7498b2c94c43fd335b944d5e5487265706b8e0f9041Behdad Esfahbod	 * ligature is ignorable. */
750621c49cb8657a79ee6897c4d313d0e825b2b228fBehdad Esfahbod        if (ligbase == LIGBASE_NOT_CHECKED)
7518b2c94c43fd335b944d5e5487265706b8e0f9041Behdad Esfahbod	{
752621c49cb8657a79ee6897c4d313d0e825b2b228fBehdad Esfahbod	  bool found = false;
753621c49cb8657a79ee6897c4d313d0e825b2b228fBehdad Esfahbod	  const hb_glyph_info_t *out = buffer->out_info;
754621c49cb8657a79ee6897c4d313d0e825b2b228fBehdad Esfahbod	  unsigned int j = buffer->out_len;
755621c49cb8657a79ee6897c4d313d0e825b2b228fBehdad Esfahbod	  while (j && _hb_glyph_info_get_lig_id (&out[j - 1]) == first_lig_id)
7568b2c94c43fd335b944d5e5487265706b8e0f9041Behdad Esfahbod	  {
757621c49cb8657a79ee6897c4d313d0e825b2b228fBehdad Esfahbod	    if (_hb_glyph_info_get_lig_comp (&out[j - 1]) == 0)
758621c49cb8657a79ee6897c4d313d0e825b2b228fBehdad Esfahbod	    {
759621c49cb8657a79ee6897c4d313d0e825b2b228fBehdad Esfahbod	      j--;
760621c49cb8657a79ee6897c4d313d0e825b2b228fBehdad Esfahbod	      found = true;
761621c49cb8657a79ee6897c4d313d0e825b2b228fBehdad Esfahbod	      break;
762621c49cb8657a79ee6897c4d313d0e825b2b228fBehdad Esfahbod	    }
7638b2c94c43fd335b944d5e5487265706b8e0f9041Behdad Esfahbod	    j--;
7648b2c94c43fd335b944d5e5487265706b8e0f9041Behdad Esfahbod	  }
7658b2c94c43fd335b944d5e5487265706b8e0f9041Behdad Esfahbod
766621c49cb8657a79ee6897c4d313d0e825b2b228fBehdad Esfahbod	  if (found && skippy_iter.may_skip (c, out[j]) == hb_apply_context_t::matcher_t::SKIP_YES)
767621c49cb8657a79ee6897c4d313d0e825b2b228fBehdad Esfahbod	    ligbase = LIGBASE_MAY_SKIP;
768621c49cb8657a79ee6897c4d313d0e825b2b228fBehdad Esfahbod	  else
769621c49cb8657a79ee6897c4d313d0e825b2b228fBehdad Esfahbod	    ligbase = LIGBASE_MAY_NOT_SKIP;
770621c49cb8657a79ee6897c4d313d0e825b2b228fBehdad Esfahbod	}
7718b2c94c43fd335b944d5e5487265706b8e0f9041Behdad Esfahbod
772621c49cb8657a79ee6897c4d313d0e825b2b228fBehdad Esfahbod        if (ligbase == LIGBASE_MAY_NOT_SKIP)
7738b2c94c43fd335b944d5e5487265706b8e0f9041Behdad Esfahbod	  return_trace (false);
7748b2c94c43fd335b944d5e5487265706b8e0f9041Behdad Esfahbod      }
7758b2c94c43fd335b944d5e5487265706b8e0f9041Behdad Esfahbod    }
7768b2c94c43fd335b944d5e5487265706b8e0f9041Behdad Esfahbod    else
777621c49cb8657a79ee6897c4d313d0e825b2b228fBehdad Esfahbod    {
77893814ca7dc2a7251f861c1c47ba155ba6e6bdf19Behdad Esfahbod      /* If first component was NOT attached to a previous ligature component,
77993814ca7dc2a7251f861c1c47ba155ba6e6bdf19Behdad Esfahbod       * all subsequent components should also NOT be attached to any ligature
78093814ca7dc2a7251f861c1c47ba155ba6e6bdf19Behdad Esfahbod       * component, unless they are attached to the first component itself! */
78193814ca7dc2a7251f861c1c47ba155ba6e6bdf19Behdad Esfahbod      if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id))
782b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod	return_trace (false);
78393814ca7dc2a7251f861c1c47ba155ba6e6bdf19Behdad Esfahbod    }
78493814ca7dc2a7251f861c1c47ba155ba6e6bdf19Behdad Esfahbod
785101303dbf7cf15d044bf2518f14b3aec65970feaBehdad Esfahbod    is_mark_ligature = is_mark_ligature && _hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx]);
7863ddf892b5328b74afb6e7d9da727d8771ca5d288Behdad Esfahbod    total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->info[skippy_iter.idx]);
787d0ba0557007798db2c60ddd0b7a5a0624cd1698dBehdad Esfahbod  }
788d0ba0557007798db2c60ddd0b7a5a0624cd1698dBehdad Esfahbod
7893c3df9cba13fec2c35e0e7ae587d9699ac0c37f5Behdad Esfahbod  *end_offset = skippy_iter.idx - buffer->idx + 1;
790d0ba0557007798db2c60ddd0b7a5a0624cd1698dBehdad Esfahbod
791191fa885d9e0a2dce92dd8727cddd18495e62409Behdad Esfahbod  if (p_is_mark_ligature)
792191fa885d9e0a2dce92dd8727cddd18495e62409Behdad Esfahbod    *p_is_mark_ligature = is_mark_ligature;
793191fa885d9e0a2dce92dd8727cddd18495e62409Behdad Esfahbod
794191fa885d9e0a2dce92dd8727cddd18495e62409Behdad Esfahbod  if (p_total_component_count)
795191fa885d9e0a2dce92dd8727cddd18495e62409Behdad Esfahbod    *p_total_component_count = total_component_count;
796191fa885d9e0a2dce92dd8727cddd18495e62409Behdad Esfahbod
797b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod  return_trace (true);
798d0ba0557007798db2c60ddd0b7a5a0624cd1698dBehdad Esfahbod}
799b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbodstatic inline bool ligate_input (hb_apply_context_t *c,
800e714fe6d6a2633494cb1fa7170a32ca2638cbb51Behdad Esfahbod				 unsigned int count, /* Including the first glyph */
8015ba450407b9d9856453e63a815499da8721ff6a7Behdad Esfahbod				 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
802e714fe6d6a2633494cb1fa7170a32ca2638cbb51Behdad Esfahbod				 unsigned int match_length,
803a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod				 hb_codepoint_t lig_glyph,
804a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod				 bool is_mark_ligature,
805a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod				 unsigned int total_component_count)
806a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod{
807dbdbfe3d7b36613d893832dcb1884c756c20bfdaBehdad Esfahbod  TRACE_APPLY (nullptr);
808e714fe6d6a2633494cb1fa7170a32ca2638cbb51Behdad Esfahbod
8093c3df9cba13fec2c35e0e7ae587d9699ac0c37f5Behdad Esfahbod  hb_buffer_t *buffer = c->buffer;
8103c3df9cba13fec2c35e0e7ae587d9699ac0c37f5Behdad Esfahbod
8113c3df9cba13fec2c35e0e7ae587d9699ac0c37f5Behdad Esfahbod  buffer->merge_clusters (buffer->idx, buffer->idx + match_length);
812607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod
813a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod  /*
814a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod   * - If it *is* a mark ligature, we don't allocate a new ligature id, and leave
815a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod   *   the ligature to keep its old ligature id.  This will allow it to attach to
816a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod   *   a base ligature in GPOS.  Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH,
817a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod   *   and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA wit a
818a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod   *   ligature id and component value of 2.  Then if SHADDA,FATHA form a ligature
819a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod   *   later, we don't want them to lose their ligature id/component, otherwise
820a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod   *   GPOS will fail to correctly position the mark ligature on top of the
821a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod   *   LAM,LAM,HEH ligature.  See:
822a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod   *     https://bugzilla.gnome.org/show_bug.cgi?id=676343
823a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod   *
824a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod   * - If a ligature is formed of components that some of which are also ligatures
825a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod   *   themselves, and those ligature components had marks attached to *their*
826a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod   *   components, we have to attach the marks to the new ligature component
827a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod   *   positions!  Now *that*'s tricky!  And these marks may be following the
828a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod   *   last component of the whole sequence, so we should loop forward looking
829a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod   *   for them and update them.
830a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod   *
831a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod   *   Eg. the sequence is LAM,LAM,SHADDA,FATHA,HEH, and the font first forms a
832a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod   *   'calt' ligature of LAM,HEH, leaving the SHADDA and FATHA with a ligature
833a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod   *   id and component == 1.  Now, during 'liga', the LAM and the LAM-HEH ligature
834a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod   *   form a LAM-LAM-HEH ligature.  We need to reassign the SHADDA and FATHA to
835a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod   *   the new ligature with a component value of 2.
836a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod   *
837a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod   *   This in fact happened to a font...  See:
838a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod   *   https://bugzilla.gnome.org/show_bug.cgi?id=437633
839a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod   */
840a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod
8415a08ecf9200a6ac9b4ebb7ec5c13dcb42d8820ceBehdad Esfahbod  unsigned int klass = is_mark_ligature ? 0 : HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE;
8423ddf892b5328b74afb6e7d9da727d8771ca5d288Behdad Esfahbod  unsigned int lig_id = is_mark_ligature ? 0 : _hb_allocate_lig_id (buffer);
8433ddf892b5328b74afb6e7d9da727d8771ca5d288Behdad Esfahbod  unsigned int last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
8443ddf892b5328b74afb6e7d9da727d8771ca5d288Behdad Esfahbod  unsigned int last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
845a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod  unsigned int components_so_far = last_num_components;
846a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod
847a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod  if (!is_mark_ligature)
8487e08f1258da229dfaf7e1c4b5c41e5bb83906cb0Behdad Esfahbod  {
8493ddf892b5328b74afb6e7d9da727d8771ca5d288Behdad Esfahbod    _hb_glyph_info_set_lig_props_for_ligature (&buffer->cur(), lig_id, total_component_count);
8503c3df9cba13fec2c35e0e7ae587d9699ac0c37f5Behdad Esfahbod    if (_hb_glyph_info_get_general_category (&buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
8513d436d325edccc0f3dd820e06e3d529cc8f3eca4Behdad Esfahbod    {
8528259669fbd1b070fc02287325894caf1bc4d590eBehdad Esfahbod      _hb_glyph_info_set_general_category (&buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER);
8533d436d325edccc0f3dd820e06e3d529cc8f3eca4Behdad Esfahbod    }
8547e08f1258da229dfaf7e1c4b5c41e5bb83906cb0Behdad Esfahbod  }
855a0161746589934e93c3b115814bbd81f56ab962fBehdad Esfahbod  c->replace_glyph_with_ligature (lig_glyph, klass);
856a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod
857a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod  for (unsigned int i = 1; i < count; i++)
858a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod  {
859abadc1717d997b69f987fdf1be9e12156d2d13d6Behdad Esfahbod    while (buffer->idx < match_positions[i] && !buffer->in_error)
860a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod    {
861a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod      if (!is_mark_ligature) {
8622f02fc79a5018e3348fccf366c470803554e1e58Behdad Esfahbod        unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
8632f02fc79a5018e3348fccf366c470803554e1e58Behdad Esfahbod	if (this_comp == 0)
864100fbeaf196515774c985ee839d0fa0695f9a6faBehdad Esfahbod	  this_comp = last_num_components;
865a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod	unsigned int new_lig_comp = components_so_far - last_num_components +
8662f02fc79a5018e3348fccf366c470803554e1e58Behdad Esfahbod				    MIN (this_comp, last_num_components);
8672f02fc79a5018e3348fccf366c470803554e1e58Behdad Esfahbod	  _hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp);
868a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod      }
8693c3df9cba13fec2c35e0e7ae587d9699ac0c37f5Behdad Esfahbod      buffer->next_glyph ();
870a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod    }
871a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod
8723ddf892b5328b74afb6e7d9da727d8771ca5d288Behdad Esfahbod    last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
8733ddf892b5328b74afb6e7d9da727d8771ca5d288Behdad Esfahbod    last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
874a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod    components_so_far += last_num_components;
875a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod
876a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod    /* Skip the base glyph */
8773c3df9cba13fec2c35e0e7ae587d9699ac0c37f5Behdad Esfahbod    buffer->idx++;
878a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod  }
879a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod
880a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod  if (!is_mark_ligature && last_lig_id) {
881a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod    /* Re-adjust components for any marks following. */
8823c3df9cba13fec2c35e0e7ae587d9699ac0c37f5Behdad Esfahbod    for (unsigned int i = buffer->idx; i < buffer->len; i++) {
8833ddf892b5328b74afb6e7d9da727d8771ca5d288Behdad Esfahbod      if (last_lig_id == _hb_glyph_info_get_lig_id (&buffer->info[i])) {
8842f02fc79a5018e3348fccf366c470803554e1e58Behdad Esfahbod        unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->info[i]);
8852f02fc79a5018e3348fccf366c470803554e1e58Behdad Esfahbod	if (!this_comp)
8862f02fc79a5018e3348fccf366c470803554e1e58Behdad Esfahbod	  break;
887a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod	unsigned int new_lig_comp = components_so_far - last_num_components +
8882f02fc79a5018e3348fccf366c470803554e1e58Behdad Esfahbod				    MIN (this_comp, last_num_components);
8893ddf892b5328b74afb6e7d9da727d8771ca5d288Behdad Esfahbod	_hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp);
890a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod      } else
891a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod	break;
892a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod    }
893a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod  }
894b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod  return_trace (true);
895a177d027d1d0ad9539e30ed75d8652e0e8da20ffBehdad Esfahbod}
896d0ba0557007798db2c60ddd0b7a5a0624cd1698dBehdad Esfahbod
897d7cfb3b2d1dd2e9fdae2b3e540bbe313660895e8Behdad Esfahbodstatic inline bool match_backtrack (hb_apply_context_t *c,
898e072c24e79f0e7c1e078a87c782ab5dd8f21dcdaBehdad Esfahbod				    unsigned int count,
8996f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod				    const UINT16 backtrack[],
900e072c24e79f0e7c1e078a87c782ab5dd8f21dcdaBehdad Esfahbod				    match_func_t match_func,
90140bd7e9a1cf422b17f15d0f66547bde9098e6ef3Behdad Esfahbod				    const void *match_data,
90240bd7e9a1cf422b17f15d0f66547bde9098e6ef3Behdad Esfahbod				    unsigned int *match_start)
903e072c24e79f0e7c1e078a87c782ab5dd8f21dcdaBehdad Esfahbod{
904dbdbfe3d7b36613d893832dcb1884c756c20bfdaBehdad Esfahbod  TRACE_APPLY (nullptr);
90593814ca7dc2a7251f861c1c47ba155ba6e6bdf19Behdad Esfahbod
906365576d246949f9d587e90cf0539dc0381e4d0a3Behdad Esfahbod  hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
907b051be542a8945ec14b0192bbc285f3e1a78c8f1Behdad Esfahbod  skippy_iter.reset (c->buffer->backtrack_len (), count);
908607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod  skippy_iter.set_match_func (match_func, match_data, backtrack);
909e072c24e79f0e7c1e078a87c782ab5dd8f21dcdaBehdad Esfahbod
9104d3aeb8cb2bc1ca7cdd03ba28ba8c334f12d4c03Behdad Esfahbod  for (unsigned int i = 0; i < count; i++)
9114ab97311541225906f6b737a2b47de252224cc09Behdad Esfahbod    if (!skippy_iter.prev ())
912b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod      return_trace (false);
913e072c24e79f0e7c1e078a87c782ab5dd8f21dcdaBehdad Esfahbod
91440bd7e9a1cf422b17f15d0f66547bde9098e6ef3Behdad Esfahbod  *match_start = skippy_iter.idx;
91540bd7e9a1cf422b17f15d0f66547bde9098e6ef3Behdad Esfahbod
916b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod  return_trace (true);
917e072c24e79f0e7c1e078a87c782ab5dd8f21dcdaBehdad Esfahbod}
918e072c24e79f0e7c1e078a87c782ab5dd8f21dcdaBehdad Esfahbod
919d7cfb3b2d1dd2e9fdae2b3e540bbe313660895e8Behdad Esfahbodstatic inline bool match_lookahead (hb_apply_context_t *c,
920d0ba0557007798db2c60ddd0b7a5a0624cd1698dBehdad Esfahbod				    unsigned int count,
9216f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod				    const UINT16 lookahead[],
922d0ba0557007798db2c60ddd0b7a5a0624cd1698dBehdad Esfahbod				    match_func_t match_func,
92340cbefe858192531ed64dd51d402f7ca7b8153a3Behdad Esfahbod				    const void *match_data,
92440bd7e9a1cf422b17f15d0f66547bde9098e6ef3Behdad Esfahbod				    unsigned int offset,
92540bd7e9a1cf422b17f15d0f66547bde9098e6ef3Behdad Esfahbod				    unsigned int *end_index)
926f14c2b7acfba75b8a6880f41ceec758f9a56abceBehdad Esfahbod{
927dbdbfe3d7b36613d893832dcb1884c756c20bfdaBehdad Esfahbod  TRACE_APPLY (nullptr);
92893814ca7dc2a7251f861c1c47ba155ba6e6bdf19Behdad Esfahbod
929365576d246949f9d587e90cf0539dc0381e4d0a3Behdad Esfahbod  hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
930b051be542a8945ec14b0192bbc285f3e1a78c8f1Behdad Esfahbod  skippy_iter.reset (c->buffer->idx + offset - 1, count);
931607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod  skippy_iter.set_match_func (match_func, match_data, lookahead);
93266bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod
933370f03e9c69d98d735eafb7e72b13b17f42cbaa9Behdad Esfahbod  for (unsigned int i = 0; i < count; i++)
9344ab97311541225906f6b737a2b47de252224cc09Behdad Esfahbod    if (!skippy_iter.next ())
935b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod      return_trace (false);
93666bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod
93740bd7e9a1cf422b17f15d0f66547bde9098e6ef3Behdad Esfahbod  *end_index = skippy_iter.idx + 1;
93840bd7e9a1cf422b17f15d0f66547bde9098e6ef3Behdad Esfahbod
939b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod  return_trace (true);
940f14c2b7acfba75b8a6880f41ceec758f9a56abceBehdad Esfahbod}
941f14c2b7acfba75b8a6880f41ceec758f9a56abceBehdad Esfahbod
942acdba3f90b232fc12fcb200dca2584481b339118Behdad Esfahbod
943f14c2b7acfba75b8a6880f41ceec758f9a56abceBehdad Esfahbod
94460d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbodstruct LookupRecord
94560d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod{
946de2118ed7a998a1df9b28fd1be96b4af89ed82c3Behdad Esfahbod  inline bool sanitize (hb_sanitize_context_t *c) const
947de2118ed7a998a1df9b28fd1be96b4af89ed82c3Behdad Esfahbod  {
948be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_SANITIZE (this);
949b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    return_trace (c->check_struct (this));
950cd3827ee567612c5500206b62840702fc956e0f5Behdad Esfahbod  }
951cd3827ee567612c5500206b62840702fc956e0f5Behdad Esfahbod
9526f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod  UINT16	sequenceIndex;		/* Index into current glyph
953f14c2b7acfba75b8a6880f41ceec758f9a56abceBehdad Esfahbod					 * sequence--first glyph = 0 */
9546f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod  UINT16	lookupListIndex;	/* Lookup to apply to that
955f14c2b7acfba75b8a6880f41ceec758f9a56abceBehdad Esfahbod					 * position--zero--based */
956569da92bc6956f42d9b2d65c784e184fb6380efeBehdad Esfahbod  public:
957569da92bc6956f42d9b2d65c784e184fb6380efeBehdad Esfahbod  DEFINE_SIZE_STATIC (4);
958f14c2b7acfba75b8a6880f41ceec758f9a56abceBehdad Esfahbod};
959f14c2b7acfba75b8a6880f41ceec758f9a56abceBehdad Esfahbod
960acdba3f90b232fc12fcb200dca2584481b339118Behdad Esfahbod
961d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbodtemplate <typename context_t>
962d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbodstatic inline void recurse_lookups (context_t *c,
963d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod				    unsigned int lookupCount,
964d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod				    const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
96531081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod{
96631081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod  for (unsigned int i = 0; i < lookupCount; i++)
96786522e493d071f395b5abf64289232bf8867ac29Behdad Esfahbod    c->recurse (lookupRecord[i].lookupListIndex);
96831081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod}
969acdba3f90b232fc12fcb200dca2584481b339118Behdad Esfahbod
970d7cfb3b2d1dd2e9fdae2b3e540bbe313660895e8Behdad Esfahbodstatic inline bool apply_lookup (hb_apply_context_t *c,
971e072c24e79f0e7c1e078a87c782ab5dd8f21dcdaBehdad Esfahbod				 unsigned int count, /* Including the first glyph */
9725ba450407b9d9856453e63a815499da8721ff6a7Behdad Esfahbod				 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
973e072c24e79f0e7c1e078a87c782ab5dd8f21dcdaBehdad Esfahbod				 unsigned int lookupCount,
9746b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod				 const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
9756b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod				 unsigned int match_length)
976f14c2b7acfba75b8a6880f41ceec758f9a56abceBehdad Esfahbod{
977dbdbfe3d7b36613d893832dcb1884c756c20bfdaBehdad Esfahbod  TRACE_APPLY (nullptr);
978902cc8aca0b3ff25eeee50b3a84d729e31731ef3Behdad Esfahbod
9796b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod  hb_buffer_t *buffer = c->buffer;
98044f7d6ecde9bf7427a05cbe73ed5d668b8a72b2ajfkthame  int end;
98152e9a71d578c5171bbb0f4bfc1b70841c3270328Behdad Esfahbod
9826b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod  /* All positions are distance from beginning of *output* buffer.
9836b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod   * Adjust. */
9846b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod  {
9856b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod    unsigned int bl = buffer->backtrack_len ();
9866b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod    end = bl + match_length;
987607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod
9886b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod    int delta = bl - buffer->idx;
9896b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod    /* Convert positions to new indexing. */
9906b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod    for (unsigned int j = 0; j < count; j++)
9916b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod      match_positions[j] += delta;
9926b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod  }
993607feb7cff0e50f8738d2e49ca463fc9d7d494deBehdad Esfahbod
994b87e36f6f119fac80b8fd55f3abae563c2c5b798Behdad Esfahbod  for (unsigned int i = 0; i < lookupCount && !buffer->in_error; i++)
99560d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod  {
9966b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod    unsigned int idx = lookupRecord[i].sequenceIndex;
9976b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod    if (idx >= count)
9986b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod      continue;
9998751de50831338ce550601c34c17d152ad89c1fdBehdad Esfahbod
10009cc1ed4fa68075b3b142a2737438109772dd0002Behdad Esfahbod    /* Don't recurse to ourself at same position.
10019cc1ed4fa68075b3b142a2737438109772dd0002Behdad Esfahbod     * Note that this test is too naive, it doesn't catch longer loops. */
10029cc1ed4fa68075b3b142a2737438109772dd0002Behdad Esfahbod    if (idx == 0 && lookupRecord[i].lookupListIndex == c->lookup_index)
10039cc1ed4fa68075b3b142a2737438109772dd0002Behdad Esfahbod      continue;
10049cc1ed4fa68075b3b142a2737438109772dd0002Behdad Esfahbod
1005e5930722d485207ca158612a2b08816337fed7e8Behdad Esfahbod    if (unlikely (!buffer->move_to (match_positions[idx])))
1006e5930722d485207ca158612a2b08816337fed7e8Behdad Esfahbod      break;
10078820bb235b1f63e4d93c8a2f5c08b44d89e06b78Behdad Esfahbod
1008baf7779d2d6e4810168a8f036bbf8f9e6493dd1aBehdad Esfahbod    if (unlikely (buffer->max_ops <= 0))
1009baf7779d2d6e4810168a8f036bbf8f9e6493dd1aBehdad Esfahbod      break;
1010baf7779d2d6e4810168a8f036bbf8f9e6493dd1aBehdad Esfahbod
10116b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod    unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
10126b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod    if (!c->recurse (lookupRecord[i].lookupListIndex))
10136b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod      continue;
10148820bb235b1f63e4d93c8a2f5c08b44d89e06b78Behdad Esfahbod
10156b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod    unsigned int new_len = buffer->backtrack_len () + buffer->lookahead_len ();
10166b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod    int delta = new_len - orig_len;
1017e73a0c2a903112ce9a35b95e14e10ab8ea2dc337Behdad Esfahbod
10186b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod    if (!delta)
10196b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod        continue;
10208751de50831338ce550601c34c17d152ad89c1fdBehdad Esfahbod
10219ac9af725c781f4597e8db46cf330d595c072739Behdad Esfahbod    /* Recursed lookup changed buffer len.  Adjust.
10229ac9af725c781f4597e8db46cf330d595c072739Behdad Esfahbod     *
10239ac9af725c781f4597e8db46cf330d595c072739Behdad Esfahbod     * TODO:
10249ac9af725c781f4597e8db46cf330d595c072739Behdad Esfahbod     *
10259ac9af725c781f4597e8db46cf330d595c072739Behdad Esfahbod     * Right now, if buffer length increased by n, we assume n new glyphs
10269ac9af725c781f4597e8db46cf330d595c072739Behdad Esfahbod     * were added right after the current position, and if buffer length
10279ac9af725c781f4597e8db46cf330d595c072739Behdad Esfahbod     * was decreased by n, we assume n match positions after the current
10289ac9af725c781f4597e8db46cf330d595c072739Behdad Esfahbod     * one where removed.  The former (buffer length increased) case is
10299ac9af725c781f4597e8db46cf330d595c072739Behdad Esfahbod     * fine, but the decrease case can be improved in at least two ways,
10309ac9af725c781f4597e8db46cf330d595c072739Behdad Esfahbod     * both of which are significant:
10319ac9af725c781f4597e8db46cf330d595c072739Behdad Esfahbod     *
10329ac9af725c781f4597e8db46cf330d595c072739Behdad Esfahbod     *   - If recursed-to lookup is MultipleSubst and buffer length
10339ac9af725c781f4597e8db46cf330d595c072739Behdad Esfahbod     *     decreased, then it's current match position that was deleted,
10349ac9af725c781f4597e8db46cf330d595c072739Behdad Esfahbod     *     NOT the one after it.
10359ac9af725c781f4597e8db46cf330d595c072739Behdad Esfahbod     *
10369ac9af725c781f4597e8db46cf330d595c072739Behdad Esfahbod     *   - If buffer length was decreased by n, it does not necessarily
10379ac9af725c781f4597e8db46cf330d595c072739Behdad Esfahbod     *     mean that n match positions where removed, as there might
10389ac9af725c781f4597e8db46cf330d595c072739Behdad Esfahbod     *     have been marks and default-ignorables in the sequence.  We
10399ac9af725c781f4597e8db46cf330d595c072739Behdad Esfahbod     *     should instead drop match positions between current-position
10409ac9af725c781f4597e8db46cf330d595c072739Behdad Esfahbod     *     and current-position + n instead.
10419ac9af725c781f4597e8db46cf330d595c072739Behdad Esfahbod     *
10429ac9af725c781f4597e8db46cf330d595c072739Behdad Esfahbod     * It should be possible to construct tests for both of these cases.
10439ac9af725c781f4597e8db46cf330d595c072739Behdad Esfahbod     */
104466bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod
104544f7d6ecde9bf7427a05cbe73ed5d668b8a72b2ajfkthame    end += delta;
104647e7a1800fba9b8bf042a1f4976a15ab012ebfc7Behdad Esfahbod    if (end <= int (match_positions[idx]))
1047359dead960c825edeb4587915a511d323f1c1f2aBehdad Esfahbod    {
10484b4a1b9f235598b04ce9ae1f9670fc978ab7620dBehdad Esfahbod      /* End might end up being smaller than match_positions[idx] if the recursed
104947e7a1800fba9b8bf042a1f4976a15ab012ebfc7Behdad Esfahbod       * lookup ended up removing many items, more than we have had matched.
10504b4a1b9f235598b04ce9ae1f9670fc978ab7620dBehdad Esfahbod       * Just never rewind end back and get out of here.
10514b4a1b9f235598b04ce9ae1f9670fc978ab7620dBehdad Esfahbod       * https://bugs.chromium.org/p/chromium/issues/detail?id=659496 */
10524b4a1b9f235598b04ce9ae1f9670fc978ab7620dBehdad Esfahbod      end = match_positions[idx];
105347e7a1800fba9b8bf042a1f4976a15ab012ebfc7Behdad Esfahbod      /* There can't be any further changes. */
1054359dead960c825edeb4587915a511d323f1c1f2aBehdad Esfahbod      break;
1055359dead960c825edeb4587915a511d323f1c1f2aBehdad Esfahbod    }
105666bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod
10576b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod    unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */
10586b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod
10596b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod    if (delta > 0)
10606b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod    {
10615ba450407b9d9856453e63a815499da8721ff6a7Behdad Esfahbod      if (unlikely (delta + count > HB_MAX_CONTEXT_LENGTH))
10626b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod	break;
106366bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod    }
106466bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod    else
106566bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod    {
106647e7a1800fba9b8bf042a1f4976a15ab012ebfc7Behdad Esfahbod      /* NOTE: delta is negative. */
10676b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod      delta = MAX (delta, (int) next - (int) count);
10686b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod      next -= delta;
106966bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod    }
10706b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod
10716b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod    /* Shift! */
10726b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod    memmove (match_positions + next + delta, match_positions + next,
10736b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod	     (count - next) * sizeof (match_positions[0]));
10746b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod    next += delta;
10756b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod    count += delta;
10766b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod
10776b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod    /* Fill in new entries. */
10786b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod    for (unsigned int j = idx + 1; j < next; j++)
10796b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod      match_positions[j] = match_positions[j - 1] + 1;
10806b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod
10816b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod    /* And fixup the rest. */
10826b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod    for (; next < count; next++)
10836b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod      match_positions[next] += delta;
108466bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod  }
108566bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod
10866b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod  buffer->move_to (end);
10876b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod
1088b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod  return_trace (true);
108966bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod}
109048f16ed96ac7041b511d9e0864623d2aa09c6da3Behdad Esfahbod
1091acdba3f90b232fc12fcb200dca2584481b339118Behdad Esfahbod
1092f14c2b7acfba75b8a6880f41ceec758f9a56abceBehdad Esfahbod
1093f14c2b7acfba75b8a6880f41ceec758f9a56abceBehdad Esfahbod/* Contextual lookups */
1094f14c2b7acfba75b8a6880f41ceec758f9a56abceBehdad Esfahbod
109531081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbodstruct ContextClosureLookupContext
109631081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod{
109731081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod  ContextClosureFuncs funcs;
109831081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod  const void *intersects_data;
109931081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod};
110031081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod
1101d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbodstruct ContextCollectGlyphsLookupContext
1102d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod{
1103d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod  ContextCollectGlyphsFuncs funcs;
1104d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod  const void *collect_data;
1105d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod};
1106d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod
110731081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbodstruct ContextApplyLookupContext
110860d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod{
110931081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod  ContextApplyFuncs funcs;
111040cbefe858192531ed64dd51d402f7ca7b8153a3Behdad Esfahbod  const void *match_data;
1111f14c2b7acfba75b8a6880f41ceec758f9a56abceBehdad Esfahbod};
1112f14c2b7acfba75b8a6880f41ceec758f9a56abceBehdad Esfahbod
11135caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbodstatic inline void context_closure_lookup (hb_closure_context_t *c,
111431081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod					   unsigned int inputCount, /* Including the first glyph (not matched) */
11156f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod					   const UINT16 input[], /* Array of input values--start with second glyph */
111631081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod					   unsigned int lookupCount,
111731081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod					   const LookupRecord lookupRecord[],
111831081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod					   ContextClosureLookupContext &lookup_context)
111931081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod{
11205caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod  if (intersects_array (c,
11215caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod			inputCount ? inputCount - 1 : 0, input,
11225caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod			lookup_context.funcs.intersects, lookup_context.intersects_data))
1123d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod    recurse_lookups (c,
1124d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod		     lookupCount, lookupRecord);
112531081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod}
112631081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod
1127d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbodstatic inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
1128d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod						  unsigned int inputCount, /* Including the first glyph (not matched) */
11296f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod						  const UINT16 input[], /* Array of input values--start with second glyph */
1130d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod						  unsigned int lookupCount,
1131d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod						  const LookupRecord lookupRecord[],
1132d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod						  ContextCollectGlyphsLookupContext &lookup_context)
1133d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod{
11348303593ba1db06e402eab52df47f21f13049112dBehdad Esfahbod  collect_array (c, c->input,
1135d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod		 inputCount ? inputCount - 1 : 0, input,
1136d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod		 lookup_context.funcs.collect, lookup_context.collect_data);
1137d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod  recurse_lookups (c,
1138d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod		   lookupCount, lookupRecord);
1139d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod}
114031081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod
1141e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbodstatic inline bool context_would_apply_lookup (hb_would_apply_context_t *c,
1142e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod					       unsigned int inputCount, /* Including the first glyph (not matched) */
11436f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod					       const UINT16 input[], /* Array of input values--start with second glyph */
11440beb66e3a61ae8bb1fa66e54b1ff1abb2f8711e9Behdad Esfahbod					       unsigned int lookupCount HB_UNUSED,
11450beb66e3a61ae8bb1fa66e54b1ff1abb2f8711e9Behdad Esfahbod					       const LookupRecord lookupRecord[] HB_UNUSED,
1146e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod					       ContextApplyLookupContext &lookup_context)
1147e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod{
1148e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod  return would_match_input (c,
1149e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod			    inputCount, input,
1150e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod			    lookup_context.funcs.match, lookup_context.match_data);
1151e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod}
115231081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbodstatic inline bool context_apply_lookup (hb_apply_context_t *c,
115331081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod					 unsigned int inputCount, /* Including the first glyph (not matched) */
11546f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod					 const UINT16 input[], /* Array of input values--start with second glyph */
115531081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod					 unsigned int lookupCount,
115631081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod					 const LookupRecord lookupRecord[],
115731081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod					 ContextApplyLookupContext &lookup_context)
1158f14c2b7acfba75b8a6880f41ceec758f9a56abceBehdad Esfahbod{
11596b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod  unsigned int match_length = 0;
11605ba450407b9d9856453e63a815499da8721ff6a7Behdad Esfahbod  unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
1161d7cfb3b2d1dd2e9fdae2b3e540bbe313660895e8Behdad Esfahbod  return match_input (c,
11624169710911450e0f9bc045fe279bfc8ba9e8457cBehdad Esfahbod		      inputCount, input,
11636b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod		      lookup_context.funcs.match, lookup_context.match_data,
11646b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod		      &match_length, match_positions)
116540bd7e9a1cf422b17f15d0f66547bde9098e6ef3Behdad Esfahbod      && (c->buffer->unsafe_to_break (c->buffer->idx, c->buffer->idx + match_length),
116640bd7e9a1cf422b17f15d0f66547bde9098e6ef3Behdad Esfahbod	  apply_lookup (c,
11676b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod		       inputCount, match_positions,
11686b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod		       lookupCount, lookupRecord,
116940bd7e9a1cf422b17f15d0f66547bde9098e6ef3Behdad Esfahbod		       match_length));
1170f14c2b7acfba75b8a6880f41ceec758f9a56abceBehdad Esfahbod}
1171f14c2b7acfba75b8a6880f41ceec758f9a56abceBehdad Esfahbod
117260d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbodstruct Rule
117360d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod{
11745caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod  inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
117531081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod  {
1176be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_CLOSURE (this);
1177093c520de506aec74f3fb1e195c0ca85813424ddBehdad Esfahbod    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
11785caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod    context_closure_lookup (c,
1179093c520de506aec74f3fb1e195c0ca85813424ddBehdad Esfahbod			    inputCount, inputZ,
11805caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod			    lookupCount, lookupRecord,
11815caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod			    lookup_context);
118231081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod  }
118331081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod
1184d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod  inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const
1185d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod  {
1186d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod    TRACE_COLLECT_GLYPHS (this);
1187093c520de506aec74f3fb1e195c0ca85813424ddBehdad Esfahbod    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
1188d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod    context_collect_glyphs_lookup (c,
1189093c520de506aec74f3fb1e195c0ca85813424ddBehdad Esfahbod				   inputCount, inputZ,
1190d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod				   lookupCount, lookupRecord,
1191d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod				   lookup_context);
1192d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod  }
1193d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod
1194e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod  inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
1195e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod  {
1196be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_WOULD_APPLY (this);
1197093c520de506aec74f3fb1e195c0ca85813424ddBehdad Esfahbod    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
1198b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    return_trace (context_would_apply_lookup (c, inputCount, inputZ, lookupCount, lookupRecord, lookup_context));
1199e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod  }
1200e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod
120131081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod  inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
120260d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod  {
1203be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_APPLY (this);
1204093c520de506aec74f3fb1e195c0ca85813424ddBehdad Esfahbod    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
1205b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    return_trace (context_apply_lookup (c, inputCount, inputZ, lookupCount, lookupRecord, lookup_context));
120666bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod  }
120766bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod
120870de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod  public:
1209de2118ed7a998a1df9b28fd1be96b4af89ed82c3Behdad Esfahbod  inline bool sanitize (hb_sanitize_context_t *c) const
1210de2118ed7a998a1df9b28fd1be96b4af89ed82c3Behdad Esfahbod  {
1211be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_SANITIZE (this);
12125aad81943329df199501e9473e2cc39f9d4421a1Behdad Esfahbod    return_trace (inputCount.sanitize (c) &&
12135aad81943329df199501e9473e2cc39f9d4421a1Behdad Esfahbod		  lookupCount.sanitize (c) &&
12145aad81943329df199501e9473e2cc39f9d4421a1Behdad Esfahbod		  c->check_range (inputZ,
12155aad81943329df199501e9473e2cc39f9d4421a1Behdad Esfahbod				  inputZ[0].static_size * inputCount +
12165aad81943329df199501e9473e2cc39f9d4421a1Behdad Esfahbod				  lookupRecordX[0].static_size * lookupCount));
121770de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod  }
121870de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod
1219ec8d2494694275dfbbac2dd0d33ca2894b0463d6Behdad Esfahbod  protected:
12206f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod  UINT16	inputCount;		/* Total number of glyphs in input
122131081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod					 * glyph sequence--includes the first
122266bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod					 * glyph */
12236f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod  UINT16	lookupCount;		/* Number of LookupRecords */
12246f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod  UINT16	inputZ[VAR];		/* Array of match inputs--start with
122566bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod					 * second glyph */
1226d3480ba37fbb5d4be75b094060f5b2f1ce98fb53Behdad Esfahbod  LookupRecord	lookupRecordX[VAR];	/* Array of LookupRecords--in
122766bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod					 * design order */
1228569da92bc6956f42d9b2d65c784e184fb6380efeBehdad Esfahbod  public:
1229093c520de506aec74f3fb1e195c0ca85813424ddBehdad Esfahbod  DEFINE_SIZE_ARRAY2 (4, inputZ, lookupRecordX);
123066bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod};
123166bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod
123260d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbodstruct RuleSet
123360d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod{
12345caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod  inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
123531081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod  {
1236be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_CLOSURE (this);
123731081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod    unsigned int num_rules = rule.len;
123831081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod    for (unsigned int i = 0; i < num_rules; i++)
12395caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod      (this+rule[i]).closure (c, lookup_context);
124031081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod  }
124131081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod
1242d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod  inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const
1243d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod  {
1244d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod    TRACE_COLLECT_GLYPHS (this);
1245d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod    unsigned int num_rules = rule.len;
1246d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod    for (unsigned int i = 0; i < num_rules; i++)
1247d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod      (this+rule[i]).collect_glyphs (c, lookup_context);
1248d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod  }
1249d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod
1250e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod  inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
1251e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod  {
1252be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_WOULD_APPLY (this);
1253e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod    unsigned int num_rules = rule.len;
1254e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod    for (unsigned int i = 0; i < num_rules; i++)
1255e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod    {
1256e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod      if ((this+rule[i]).would_apply (c, lookup_context))
1257b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod        return_trace (true);
1258e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod    }
1259b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    return_trace (false);
1260e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod  }
1261e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod
126231081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod  inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
126360d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod  {
1264be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_APPLY (this);
126566bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod    unsigned int num_rules = rule.len;
126660d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod    for (unsigned int i = 0; i < num_rules; i++)
126760d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod    {
1268d7cfb3b2d1dd2e9fdae2b3e540bbe313660895e8Behdad Esfahbod      if ((this+rule[i]).apply (c, lookup_context))
1269b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod        return_trace (true);
127066bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod    }
1271b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    return_trace (false);
127266bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod  }
127366bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod
1274de2118ed7a998a1df9b28fd1be96b4af89ed82c3Behdad Esfahbod  inline bool sanitize (hb_sanitize_context_t *c) const
1275de2118ed7a998a1df9b28fd1be96b4af89ed82c3Behdad Esfahbod  {
1276be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_SANITIZE (this);
1277b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    return_trace (rule.sanitize (c, this));
127870de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod  }
127970de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod
1280ec8d2494694275dfbbac2dd0d33ca2894b0463d6Behdad Esfahbod  protected:
128166bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod  OffsetArrayOf<Rule>
128248f16ed96ac7041b511d9e0864623d2aa09c6da3Behdad Esfahbod		rule;			/* Array of Rule tables
128366bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod					 * ordered by preference */
1284ed07422c33bbb52ff4d79e65986171e3f07697d8Behdad Esfahbod  public:
12850eb9fc6e37935707dba2bf4b3705de2161a08cb7Behdad Esfahbod  DEFINE_SIZE_ARRAY (2, rule);
128666bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod};
128766bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod
128866bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod
128960d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbodstruct ContextFormat1
129060d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod{
129144fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod  inline void closure (hb_closure_context_t *c) const
1292f94b0aa64609654497ced9c00312c9643eb69053Behdad Esfahbod  {
1293be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_CLOSURE (this);
129431081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod
129531081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod    const Coverage &cov = (this+coverage);
129631081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod
129731081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod    struct ContextClosureLookupContext lookup_context = {
129844fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod      {intersects_glyph},
1299dbdbfe3d7b36613d893832dcb1884c756c20bfdaBehdad Esfahbod      nullptr
130031081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod    };
130131081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod
130231081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod    unsigned int count = ruleSet.len;
130331081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod    for (unsigned int i = 0; i < count; i++)
130431081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod      if (cov.intersects_coverage (c->glyphs, i)) {
130531081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod	const RuleSet &rule_set = this+ruleSet[i];
13065caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod	rule_set.closure (c, lookup_context);
130731081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod      }
1308f94b0aa64609654497ced9c00312c9643eb69053Behdad Esfahbod  }
1309f94b0aa64609654497ced9c00312c9643eb69053Behdad Esfahbod
131026514d51b6669f092d9ccb7523443a5ece74169aBehdad Esfahbod  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
131126514d51b6669f092d9ccb7523443a5ece74169aBehdad Esfahbod  {
1312d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod    TRACE_COLLECT_GLYPHS (this);
13138303593ba1db06e402eab52df47f21f13049112dBehdad Esfahbod    (this+coverage).add_coverage (c->input);
1314d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod
1315d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod    struct ContextCollectGlyphsLookupContext lookup_context = {
1316d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod      {collect_glyph},
1317dbdbfe3d7b36613d893832dcb1884c756c20bfdaBehdad Esfahbod      nullptr
1318d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod    };
1319d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod
1320d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod    unsigned int count = ruleSet.len;
1321d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod    for (unsigned int i = 0; i < count; i++)
1322f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod      (this+ruleSet[i]).collect_glyphs (c, lookup_context);
132326514d51b6669f092d9ccb7523443a5ece74169aBehdad Esfahbod  }
132426514d51b6669f092d9ccb7523443a5ece74169aBehdad Esfahbod
1325e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod  inline bool would_apply (hb_would_apply_context_t *c) const
1326e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod  {
1327be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_WOULD_APPLY (this);
1328e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod
1329b67881b171a7cf865af58df146da52fc1e27b160Behdad Esfahbod    const RuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
1330e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod    struct ContextApplyLookupContext lookup_context = {
1331ec35a72a44301934b8f123ab2833f59d8c875a09Behdad Esfahbod      {match_glyph},
1332dbdbfe3d7b36613d893832dcb1884c756c20bfdaBehdad Esfahbod      nullptr
1333e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod    };
1334b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    return_trace (rule_set.would_apply (c, lookup_context));
1335e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod  }
1336e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod
133744fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod  inline const Coverage &get_coverage (void) const
133844fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod  {
133944fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod    return this+coverage;
134044fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod  }
134144fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod
1342ec35a72a44301934b8f123ab2833f59d8c875a09Behdad Esfahbod  inline bool apply (hb_apply_context_t *c) const
134360d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod  {
1344be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_APPLY (this);
1345b67881b171a7cf865af58df146da52fc1e27b160Behdad Esfahbod    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
134664d3fc8d0dada673245cc8c0b1c12cd849b30997Behdad Esfahbod    if (likely (index == NOT_COVERED))
1347b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod      return_trace (false);
1348aa3d7adca5c821c91a2a1b5380fd6b3d19656ab1Behdad Esfahbod
134966bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod    const RuleSet &rule_set = this+ruleSet[index];
135031081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod    struct ContextApplyLookupContext lookup_context = {
1351ec35a72a44301934b8f123ab2833f59d8c875a09Behdad Esfahbod      {match_glyph},
1352dbdbfe3d7b36613d893832dcb1884c756c20bfdaBehdad Esfahbod      nullptr
135366bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod    };
1354b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    return_trace (rule_set.apply (c, lookup_context));
135566bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod  }
135666bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod
1357de2118ed7a998a1df9b28fd1be96b4af89ed82c3Behdad Esfahbod  inline bool sanitize (hb_sanitize_context_t *c) const
1358de2118ed7a998a1df9b28fd1be96b4af89ed82c3Behdad Esfahbod  {
1359be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_SANITIZE (this);
1360b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
136170de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod  }
136270de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod
1363ec8d2494694275dfbbac2dd0d33ca2894b0463d6Behdad Esfahbod  protected:
13646f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod  UINT16	format;			/* Format identifier--format = 1 */
136566bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod  OffsetTo<Coverage>
136666bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod		coverage;		/* Offset to Coverage table--from
136766bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod					 * beginning of table */
136866bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod  OffsetArrayOf<RuleSet>
136966bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod		ruleSet;		/* Array of RuleSet tables
137066bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod					 * ordered by Coverage Index */
1371b3651231bf80bb7009214547a75ed90e21815c68Behdad Esfahbod  public:
13720eb9fc6e37935707dba2bf4b3705de2161a08cb7Behdad Esfahbod  DEFINE_SIZE_ARRAY (6, ruleSet);
137366bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod};
137466bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod
137566bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod
137660d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbodstruct ContextFormat2
137760d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod{
137844fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod  inline void closure (hb_closure_context_t *c) const
1379f94b0aa64609654497ced9c00312c9643eb69053Behdad Esfahbod  {
1380be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_CLOSURE (this);
138131081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod    if (!(this+coverage).intersects (c->glyphs))
13825caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod      return;
138331081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod
138431081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod    const ClassDef &class_def = this+classDef;
138531081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod
138631081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod    struct ContextClosureLookupContext lookup_context = {
138744fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod      {intersects_class},
138811fba79ee9383eb995ddf7eb924dd64c67e2df63Behdad Esfahbod      &class_def
138931081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod    };
139031081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod
139131081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod    unsigned int count = ruleSet.len;
139231081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod    for (unsigned int i = 0; i < count; i++)
139331081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod      if (class_def.intersects_class (c->glyphs, i)) {
139431081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod	const RuleSet &rule_set = this+ruleSet[i];
13955caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod	rule_set.closure (c, lookup_context);
139631081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod      }
1397f94b0aa64609654497ced9c00312c9643eb69053Behdad Esfahbod  }
1398f94b0aa64609654497ced9c00312c9643eb69053Behdad Esfahbod
139926514d51b6669f092d9ccb7523443a5ece74169aBehdad Esfahbod  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
140026514d51b6669f092d9ccb7523443a5ece74169aBehdad Esfahbod  {
1401d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod    TRACE_COLLECT_GLYPHS (this);
14028303593ba1db06e402eab52df47f21f13049112dBehdad Esfahbod    (this+coverage).add_coverage (c->input);
1403d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod
140411fba79ee9383eb995ddf7eb924dd64c67e2df63Behdad Esfahbod    const ClassDef &class_def = this+classDef;
1405d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod    struct ContextCollectGlyphsLookupContext lookup_context = {
1406d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod      {collect_class},
140711fba79ee9383eb995ddf7eb924dd64c67e2df63Behdad Esfahbod      &class_def
1408d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod    };
1409d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod
1410d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod    unsigned int count = ruleSet.len;
1411d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod    for (unsigned int i = 0; i < count; i++)
1412f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod      (this+ruleSet[i]).collect_glyphs (c, lookup_context);
141326514d51b6669f092d9ccb7523443a5ece74169aBehdad Esfahbod  }
141426514d51b6669f092d9ccb7523443a5ece74169aBehdad Esfahbod
1415e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod  inline bool would_apply (hb_would_apply_context_t *c) const
1416e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod  {
1417be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_WOULD_APPLY (this);
1418e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod
1419e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod    const ClassDef &class_def = this+classDef;
14202dc1141d7d0a9f5818862b09d6b9cfe0a27f1fc1Behdad Esfahbod    unsigned int index = class_def.get_class (c->glyphs[0]);
1421e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod    const RuleSet &rule_set = this+ruleSet[index];
1422e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod    struct ContextApplyLookupContext lookup_context = {
1423ec35a72a44301934b8f123ab2833f59d8c875a09Behdad Esfahbod      {match_class},
1424e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod      &class_def
1425e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod    };
1426b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    return_trace (rule_set.would_apply (c, lookup_context));
1427e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod  }
1428e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod
142944fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod  inline const Coverage &get_coverage (void) const
143044fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod  {
143144fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod    return this+coverage;
143244fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod  }
143344fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod
1434ec35a72a44301934b8f123ab2833f59d8c875a09Behdad Esfahbod  inline bool apply (hb_apply_context_t *c) const
143560d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod  {
1436be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_APPLY (this);
1437b67881b171a7cf865af58df146da52fc1e27b160Behdad Esfahbod    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
1438b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    if (likely (index == NOT_COVERED)) return_trace (false);
1439aa3d7adca5c821c91a2a1b5380fd6b3d19656ab1Behdad Esfahbod
1440aa3d7adca5c821c91a2a1b5380fd6b3d19656ab1Behdad Esfahbod    const ClassDef &class_def = this+classDef;
14412dc1141d7d0a9f5818862b09d6b9cfe0a27f1fc1Behdad Esfahbod    index = class_def.get_class (c->buffer->cur().codepoint);
144266bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod    const RuleSet &rule_set = this+ruleSet[index];
144331081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod    struct ContextApplyLookupContext lookup_context = {
1444ec35a72a44301934b8f123ab2833f59d8c875a09Behdad Esfahbod      {match_class},
144540cbefe858192531ed64dd51d402f7ca7b8153a3Behdad Esfahbod      &class_def
144666bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod    };
1447b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    return_trace (rule_set.apply (c, lookup_context));
144866bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod  }
144966bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod
1450de2118ed7a998a1df9b28fd1be96b4af89ed82c3Behdad Esfahbod  inline bool sanitize (hb_sanitize_context_t *c) const
1451de2118ed7a998a1df9b28fd1be96b4af89ed82c3Behdad Esfahbod  {
1452be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_SANITIZE (this);
1453b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    return_trace (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this));
145470de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod  }
145570de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod
1456ec8d2494694275dfbbac2dd0d33ca2894b0463d6Behdad Esfahbod  protected:
14576f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod  UINT16	format;			/* Format identifier--format = 2 */
145866bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod  OffsetTo<Coverage>
145966bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod		coverage;		/* Offset to Coverage table--from
146066bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod					 * beginning of table */
146166bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod  OffsetTo<ClassDef>
146266bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod		classDef;		/* Offset to glyph ClassDef table--from
146366bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod					 * beginning of table */
146466bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod  OffsetArrayOf<RuleSet>
146566bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod		ruleSet;		/* Array of RuleSet tables
146666bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod					 * ordered by class */
1467b3651231bf80bb7009214547a75ed90e21815c68Behdad Esfahbod  public:
14680eb9fc6e37935707dba2bf4b3705de2161a08cb7Behdad Esfahbod  DEFINE_SIZE_ARRAY (8, ruleSet);
146966bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod};
147066bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod
147166bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod
147260d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbodstruct ContextFormat3
147360d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod{
147444fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod  inline void closure (hb_closure_context_t *c) const
1475f94b0aa64609654497ced9c00312c9643eb69053Behdad Esfahbod  {
1476be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_CLOSURE (this);
1477093c520de506aec74f3fb1e195c0ca85813424ddBehdad Esfahbod    if (!(this+coverageZ[0]).intersects (c->glyphs))
14785caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod      return;
147931081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod
1480093c520de506aec74f3fb1e195c0ca85813424ddBehdad Esfahbod    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
148131081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod    struct ContextClosureLookupContext lookup_context = {
148244fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod      {intersects_coverage},
148331081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod      this
148431081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod    };
14855caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod    context_closure_lookup (c,
14866f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod			    glyphCount, (const UINT16 *) (coverageZ + 1),
14875caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod			    lookupCount, lookupRecord,
14885caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod			    lookup_context);
1489f94b0aa64609654497ced9c00312c9643eb69053Behdad Esfahbod  }
1490f94b0aa64609654497ced9c00312c9643eb69053Behdad Esfahbod
149126514d51b6669f092d9ccb7523443a5ece74169aBehdad Esfahbod  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
149226514d51b6669f092d9ccb7523443a5ece74169aBehdad Esfahbod  {
1493d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod    TRACE_COLLECT_GLYPHS (this);
1494093c520de506aec74f3fb1e195c0ca85813424ddBehdad Esfahbod    (this+coverageZ[0]).add_coverage (c->input);
1495d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod
1496093c520de506aec74f3fb1e195c0ca85813424ddBehdad Esfahbod    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
1497d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod    struct ContextCollectGlyphsLookupContext lookup_context = {
1498d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod      {collect_coverage},
1499e75943de803f571b7ad2cf2f777119753a209656Behdad Esfahbod      this
1500d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod    };
1501d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod
1502d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod    context_collect_glyphs_lookup (c,
15036f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod				   glyphCount, (const UINT16 *) (coverageZ + 1),
1504d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod				   lookupCount, lookupRecord,
1505d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod				   lookup_context);
150626514d51b6669f092d9ccb7523443a5ece74169aBehdad Esfahbod  }
150726514d51b6669f092d9ccb7523443a5ece74169aBehdad Esfahbod
1508e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod  inline bool would_apply (hb_would_apply_context_t *c) const
1509e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod  {
1510be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_WOULD_APPLY (this);
1511e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod
1512093c520de506aec74f3fb1e195c0ca85813424ddBehdad Esfahbod    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
1513e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod    struct ContextApplyLookupContext lookup_context = {
1514ec35a72a44301934b8f123ab2833f59d8c875a09Behdad Esfahbod      {match_coverage},
1515e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod      this
1516e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod    };
15176f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod    return_trace (context_would_apply_lookup (c, glyphCount, (const UINT16 *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
1518e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod  }
1519e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod
152044fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod  inline const Coverage &get_coverage (void) const
152144fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod  {
1522093c520de506aec74f3fb1e195c0ca85813424ddBehdad Esfahbod    return this+coverageZ[0];
152344fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod  }
152444fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod
1525ec35a72a44301934b8f123ab2833f59d8c875a09Behdad Esfahbod  inline bool apply (hb_apply_context_t *c) const
152660d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod  {
1527be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_APPLY (this);
1528093c520de506aec74f3fb1e195c0ca85813424ddBehdad Esfahbod    unsigned int index = (this+coverageZ[0]).get_coverage (c->buffer->cur().codepoint);
1529b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    if (likely (index == NOT_COVERED)) return_trace (false);
153066bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod
1531093c520de506aec74f3fb1e195c0ca85813424ddBehdad Esfahbod    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
153231081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod    struct ContextApplyLookupContext lookup_context = {
1533ec35a72a44301934b8f123ab2833f59d8c875a09Behdad Esfahbod      {match_coverage},
153440cbefe858192531ed64dd51d402f7ca7b8153a3Behdad Esfahbod      this
153566bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod    };
15366f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod    return_trace (context_apply_lookup (c, glyphCount, (const UINT16 *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
153766bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod  }
153866bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod
1539de2118ed7a998a1df9b28fd1be96b4af89ed82c3Behdad Esfahbod  inline bool sanitize (hb_sanitize_context_t *c) const
1540de2118ed7a998a1df9b28fd1be96b4af89ed82c3Behdad Esfahbod  {
1541be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_SANITIZE (this);
1542b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    if (!c->check_struct (this)) return_trace (false);
154370de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod    unsigned int count = glyphCount;
1544b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    if (!count) return_trace (false); /* We want to access coverageZ[0] freely. */
1545b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    if (!c->check_array (coverageZ, coverageZ[0].static_size, count)) return_trace (false);
154670de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod    for (unsigned int i = 0; i < count; i++)
1547b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod      if (!coverageZ[i].sanitize (c, this)) return_trace (false);
1548de2118ed7a998a1df9b28fd1be96b4af89ed82c3Behdad Esfahbod    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * count);
1549b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    return_trace (c->check_array (lookupRecord, lookupRecord[0].static_size, lookupCount));
155070de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod  }
155170de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod
1552ec8d2494694275dfbbac2dd0d33ca2894b0463d6Behdad Esfahbod  protected:
15536f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod  UINT16	format;			/* Format identifier--format = 3 */
15546f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod  UINT16	glyphCount;		/* Number of glyphs in the input glyph
155566bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod					 * sequence */
15566f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod  UINT16	lookupCount;		/* Number of LookupRecords */
1557aa3d7adca5c821c91a2a1b5380fd6b3d19656ab1Behdad Esfahbod  OffsetTo<Coverage>
1558093c520de506aec74f3fb1e195c0ca85813424ddBehdad Esfahbod		coverageZ[VAR];		/* Array of offsets to Coverage
1559aa3d7adca5c821c91a2a1b5380fd6b3d19656ab1Behdad Esfahbod					 * table in glyph sequence order */
1560d3480ba37fbb5d4be75b094060f5b2f1ce98fb53Behdad Esfahbod  LookupRecord	lookupRecordX[VAR];	/* Array of LookupRecords--in
156166bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod					 * design order */
1562569da92bc6956f42d9b2d65c784e184fb6380efeBehdad Esfahbod  public:
1563093c520de506aec74f3fb1e195c0ca85813424ddBehdad Esfahbod  DEFINE_SIZE_ARRAY2 (6, coverageZ, lookupRecordX);
156466bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod};
156566bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod
156660d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbodstruct Context
156760d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod{
156844fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod  template <typename context_t>
15699c5a9ee967120c8a968a1160c420e03620d46c24Behdad Esfahbod  inline typename context_t::return_t dispatch (context_t *c) const
1570e8cfdd7fa8d0fb66e0a261f3547e5824897e5131Behdad Esfahbod  {
157100f6a8e334ec4c586e4e633a95b411ccb50306d3Behdad Esfahbod    TRACE_DISPATCH (this, u.format);
1572f396fbb000dc1c8acddbf6a16e193b328c5e551eBehdad Esfahbod    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1573e8cfdd7fa8d0fb66e0a261f3547e5824897e5131Behdad Esfahbod    switch (u.format) {
1574b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    case 1: return_trace (c->dispatch (u.format1));
1575b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    case 2: return_trace (c->dispatch (u.format2));
1576b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    case 3: return_trace (c->dispatch (u.format3));
1577b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    default:return_trace (c->default_return_value ());
1578e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod    }
1579e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod  }
1580e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod
1581ec8d2494694275dfbbac2dd0d33ca2894b0463d6Behdad Esfahbod  protected:
158266bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod  union {
15836f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod  UINT16		format;		/* Format identifier */
1584dacebcadae36b35531d635d81df2afb937677b7aBehdad Esfahbod  ContextFormat1	format1;
1585dacebcadae36b35531d635d81df2afb937677b7aBehdad Esfahbod  ContextFormat2	format2;
1586dacebcadae36b35531d635d81df2afb937677b7aBehdad Esfahbod  ContextFormat3	format3;
158766bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod  } u;
158866bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod};
158966bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod
1590ca5290f4994e1b2db4dac03f7a22b7071441ba06Behdad Esfahbod
1591ca5290f4994e1b2db4dac03f7a22b7071441ba06Behdad Esfahbod/* Chaining Contextual lookups */
1592ca5290f4994e1b2db4dac03f7a22b7071441ba06Behdad Esfahbod
159331081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbodstruct ChainContextClosureLookupContext
159460d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod{
159531081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod  ContextClosureFuncs funcs;
159631081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod  const void *intersects_data[3];
159731081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod};
159831081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod
1599f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbodstruct ChainContextCollectGlyphsLookupContext
1600f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod{
1601f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod  ContextCollectGlyphsFuncs funcs;
1602f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod  const void *collect_data[3];
1603f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod};
1604f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod
160531081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbodstruct ChainContextApplyLookupContext
160631081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod{
160731081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod  ContextApplyFuncs funcs;
160840cbefe858192531ed64dd51d402f7ca7b8153a3Behdad Esfahbod  const void *match_data[3];
160948f16ed96ac7041b511d9e0864623d2aa09c6da3Behdad Esfahbod};
161048f16ed96ac7041b511d9e0864623d2aa09c6da3Behdad Esfahbod
16115caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbodstatic inline void chain_context_closure_lookup (hb_closure_context_t *c,
161231081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod						 unsigned int backtrackCount,
16136f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod						 const UINT16 backtrack[],
161431081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod						 unsigned int inputCount, /* Including the first glyph (not matched) */
16156f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod						 const UINT16 input[], /* Array of input values--start with second glyph */
161631081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod						 unsigned int lookaheadCount,
16176f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod						 const UINT16 lookahead[],
161831081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod						 unsigned int lookupCount,
161931081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod						 const LookupRecord lookupRecord[],
162031081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod						 ChainContextClosureLookupContext &lookup_context)
162131081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod{
16225caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod  if (intersects_array (c,
16235caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod			backtrackCount, backtrack,
16245caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod			lookup_context.funcs.intersects, lookup_context.intersects_data[0])
16255caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod   && intersects_array (c,
16265caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod			inputCount ? inputCount - 1 : 0, input,
16275caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod			lookup_context.funcs.intersects, lookup_context.intersects_data[1])
162874439d0aa10184451adc6c6469f5119be352ecbbBehdad Esfahbod   && intersects_array (c,
16295caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod		       lookaheadCount, lookahead,
16305caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod		       lookup_context.funcs.intersects, lookup_context.intersects_data[2]))
1631d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod    recurse_lookups (c,
1632d0a5233785eb327c4080432f597fe470a1046af3Behdad Esfahbod		     lookupCount, lookupRecord);
163331081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod}
163431081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod
1635f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbodstatic inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
1636f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod						        unsigned int backtrackCount,
16376f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod						        const UINT16 backtrack[],
1638f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod						        unsigned int inputCount, /* Including the first glyph (not matched) */
16396f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod						        const UINT16 input[], /* Array of input values--start with second glyph */
1640f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod						        unsigned int lookaheadCount,
16416f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod						        const UINT16 lookahead[],
1642f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod						        unsigned int lookupCount,
1643f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod						        const LookupRecord lookupRecord[],
1644f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod						        ChainContextCollectGlyphsLookupContext &lookup_context)
1645f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod{
16468303593ba1db06e402eab52df47f21f13049112dBehdad Esfahbod  collect_array (c, c->before,
1647f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod		 backtrackCount, backtrack,
1648f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod		 lookup_context.funcs.collect, lookup_context.collect_data[0]);
16498303593ba1db06e402eab52df47f21f13049112dBehdad Esfahbod  collect_array (c, c->input,
1650f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod		 inputCount ? inputCount - 1 : 0, input,
1651f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod		 lookup_context.funcs.collect, lookup_context.collect_data[1]);
16528303593ba1db06e402eab52df47f21f13049112dBehdad Esfahbod  collect_array (c, c->after,
1653f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod		 lookaheadCount, lookahead,
1654f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod		 lookup_context.funcs.collect, lookup_context.collect_data[2]);
1655f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod  recurse_lookups (c,
1656f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod		   lookupCount, lookupRecord);
1657f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod}
1658f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod
1659e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbodstatic inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c,
1660e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod						     unsigned int backtrackCount,
16616f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod						     const UINT16 backtrack[] HB_UNUSED,
1662e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod						     unsigned int inputCount, /* Including the first glyph (not matched) */
16636f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod						     const UINT16 input[], /* Array of input values--start with second glyph */
1664e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod						     unsigned int lookaheadCount,
16656f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod						     const UINT16 lookahead[] HB_UNUSED,
16660beb66e3a61ae8bb1fa66e54b1ff1abb2f8711e9Behdad Esfahbod						     unsigned int lookupCount HB_UNUSED,
16670beb66e3a61ae8bb1fa66e54b1ff1abb2f8711e9Behdad Esfahbod						     const LookupRecord lookupRecord[] HB_UNUSED,
1668e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod						     ChainContextApplyLookupContext &lookup_context)
1669e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod{
1670d9b204d3d24cde165167714728bf380267903d6aBehdad Esfahbod  return (c->zero_context ? !backtrackCount && !lookaheadCount : true)
16711f2bb172fe9a173ecfd61054f1fdd850943ef059Behdad Esfahbod      && would_match_input (c,
1672e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod			    inputCount, input,
1673e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod			    lookup_context.funcs.match, lookup_context.match_data[1]);
1674e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod}
1675e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod
167631081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbodstatic inline bool chain_context_apply_lookup (hb_apply_context_t *c,
167731081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod					       unsigned int backtrackCount,
16786f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod					       const UINT16 backtrack[],
167931081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod					       unsigned int inputCount, /* Including the first glyph (not matched) */
16806f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod					       const UINT16 input[], /* Array of input values--start with second glyph */
168131081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod					       unsigned int lookaheadCount,
16826f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod					       const UINT16 lookahead[],
168331081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod					       unsigned int lookupCount,
168431081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod					       const LookupRecord lookupRecord[],
168531081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod					       ChainContextApplyLookupContext &lookup_context)
168602e1e5c63fa4f896053fa3c21e495239e1e9caa2Behdad Esfahbod{
168740bd7e9a1cf422b17f15d0f66547bde9098e6ef3Behdad Esfahbod  unsigned int start_index = 0, match_length = 0, end_index = 0;
16885ba450407b9d9856453e63a815499da8721ff6a7Behdad Esfahbod  unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
1689f19e0b0099ec73b8fedccacff4902403f5eabc42Behdad Esfahbod  return match_input (c,
16904169710911450e0f9bc045fe279bfc8ba9e8457cBehdad Esfahbod		      inputCount, input,
16914169710911450e0f9bc045fe279bfc8ba9e8457cBehdad Esfahbod		      lookup_context.funcs.match, lookup_context.match_data[1],
16926b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod		      &match_length, match_positions)
1693f19e0b0099ec73b8fedccacff4902403f5eabc42Behdad Esfahbod      && match_backtrack (c,
1694f19e0b0099ec73b8fedccacff4902403f5eabc42Behdad Esfahbod			  backtrackCount, backtrack,
169540bd7e9a1cf422b17f15d0f66547bde9098e6ef3Behdad Esfahbod			  lookup_context.funcs.match, lookup_context.match_data[0],
169640bd7e9a1cf422b17f15d0f66547bde9098e6ef3Behdad Esfahbod			  &start_index)
1697d7cfb3b2d1dd2e9fdae2b3e540bbe313660895e8Behdad Esfahbod      && match_lookahead (c,
16984169710911450e0f9bc045fe279bfc8ba9e8457cBehdad Esfahbod			  lookaheadCount, lookahead,
16994169710911450e0f9bc045fe279bfc8ba9e8457cBehdad Esfahbod			  lookup_context.funcs.match, lookup_context.match_data[2],
170040bd7e9a1cf422b17f15d0f66547bde9098e6ef3Behdad Esfahbod			  match_length, &end_index)
170140bd7e9a1cf422b17f15d0f66547bde9098e6ef3Behdad Esfahbod      && (c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index),
170240bd7e9a1cf422b17f15d0f66547bde9098e6ef3Behdad Esfahbod          apply_lookup (c,
17036b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod		       inputCount, match_positions,
17046b65a76b40522a4f57a6fedcbdfc5a4d736f1d3cBehdad Esfahbod		       lookupCount, lookupRecord,
170540bd7e9a1cf422b17f15d0f66547bde9098e6ef3Behdad Esfahbod		       match_length));
170602e1e5c63fa4f896053fa3c21e495239e1e9caa2Behdad Esfahbod}
170748f16ed96ac7041b511d9e0864623d2aa09c6da3Behdad Esfahbod
170860d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbodstruct ChainRule
170960d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod{
17105caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod  inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
171131081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod  {
1712be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_CLOSURE (this);
17136f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod    const HeadlessArrayOf<UINT16> &input = StructAfter<HeadlessArrayOf<UINT16> > (backtrack);
17146f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod    const ArrayOf<UINT16> &lookahead = StructAfter<ArrayOf<UINT16> > (input);
171531081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
17165caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod    chain_context_closure_lookup (c,
17175caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod				  backtrack.len, backtrack.array,
17185caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod				  input.len, input.array,
17195caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod				  lookahead.len, lookahead.array,
17205caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod				  lookup.len, lookup.array,
17215caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod				  lookup_context);
172231081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod  }
172331081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod
1724f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod  inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
1725f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod  {
1726f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod    TRACE_COLLECT_GLYPHS (this);
17276f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod    const HeadlessArrayOf<UINT16> &input = StructAfter<HeadlessArrayOf<UINT16> > (backtrack);
17286f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod    const ArrayOf<UINT16> &lookahead = StructAfter<ArrayOf<UINT16> > (input);
1729f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1730f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod    chain_context_collect_glyphs_lookup (c,
1731f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod					 backtrack.len, backtrack.array,
1732f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod					 input.len, input.array,
1733f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod					 lookahead.len, lookahead.array,
1734f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod					 lookup.len, lookup.array,
1735f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod					 lookup_context);
1736f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod  }
1737f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod
1738e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod  inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
1739e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod  {
1740be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_WOULD_APPLY (this);
17416f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod    const HeadlessArrayOf<UINT16> &input = StructAfter<HeadlessArrayOf<UINT16> > (backtrack);
17426f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod    const ArrayOf<UINT16> &lookahead = StructAfter<ArrayOf<UINT16> > (input);
1743e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1744b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    return_trace (chain_context_would_apply_lookup (c,
1745b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod						    backtrack.len, backtrack.array,
1746b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod						    input.len, input.array,
1747b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod						    lookahead.len, lookahead.array, lookup.len,
1748b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod						    lookup.array, lookup_context));
1749e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod  }
1750e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod
175131081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod  inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
175260d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod  {
1753be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_APPLY (this);
17546f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod    const HeadlessArrayOf<UINT16> &input = StructAfter<HeadlessArrayOf<UINT16> > (backtrack);
17556f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod    const ArrayOf<UINT16> &lookahead = StructAfter<ArrayOf<UINT16> > (input);
1756e961c86c579fd98ee604342a9c70c4e7f8d4f220Behdad Esfahbod    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1757b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    return_trace (chain_context_apply_lookup (c,
1758b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod					      backtrack.len, backtrack.array,
1759b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod					      input.len, input.array,
1760b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod					      lookahead.len, lookahead.array, lookup.len,
1761b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod					      lookup.array, lookup_context));
1762aa3d7adca5c821c91a2a1b5380fd6b3d19656ab1Behdad Esfahbod  }
1763aa3d7adca5c821c91a2a1b5380fd6b3d19656ab1Behdad Esfahbod
1764de2118ed7a998a1df9b28fd1be96b4af89ed82c3Behdad Esfahbod  inline bool sanitize (hb_sanitize_context_t *c) const
1765de2118ed7a998a1df9b28fd1be96b4af89ed82c3Behdad Esfahbod  {
1766be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_SANITIZE (this);
1767b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    if (!backtrack.sanitize (c)) return_trace (false);
17686f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod    const HeadlessArrayOf<UINT16> &input = StructAfter<HeadlessArrayOf<UINT16> > (backtrack);
1769b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    if (!input.sanitize (c)) return_trace (false);
17706f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod    const ArrayOf<UINT16> &lookahead = StructAfter<ArrayOf<UINT16> > (input);
1771b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    if (!lookahead.sanitize (c)) return_trace (false);
1772de2118ed7a998a1df9b28fd1be96b4af89ed82c3Behdad Esfahbod    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1773b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    return_trace (lookup.sanitize (c));
177470de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod  }
1775ca5290f4994e1b2db4dac03f7a22b7071441ba06Behdad Esfahbod
1776ec8d2494694275dfbbac2dd0d33ca2894b0463d6Behdad Esfahbod  protected:
17776f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod  ArrayOf<UINT16>
1778dcb6b60254951a2831c03f3196962d229f7e556cBehdad Esfahbod		backtrack;		/* Array of backtracking values
1779ca5290f4994e1b2db4dac03f7a22b7071441ba06Behdad Esfahbod					 * (to be matched before the input
1780ca5290f4994e1b2db4dac03f7a22b7071441ba06Behdad Esfahbod					 * sequence) */
17816f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod  HeadlessArrayOf<UINT16>
1782e8cbaaf6d538036ff9b880b018db402e0895ed01Behdad Esfahbod		inputX;			/* Array of input values (start with
1783ca5290f4994e1b2db4dac03f7a22b7071441ba06Behdad Esfahbod					 * second glyph) */
17846f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod  ArrayOf<UINT16>
1785dcb6b60254951a2831c03f3196962d229f7e556cBehdad Esfahbod		lookaheadX;		/* Array of lookahead values's (to be
178648f16ed96ac7041b511d9e0864623d2aa09c6da3Behdad Esfahbod					 * matched after the input sequence) */
1787dcb6b60254951a2831c03f3196962d229f7e556cBehdad Esfahbod  ArrayOf<LookupRecord>
178802e1e5c63fa4f896053fa3c21e495239e1e9caa2Behdad Esfahbod		lookupX;		/* Array of LookupRecords--in
1789ca5290f4994e1b2db4dac03f7a22b7071441ba06Behdad Esfahbod					 * design order) */
1790b3651231bf80bb7009214547a75ed90e21815c68Behdad Esfahbod  public:
1791bea34c7cbb583cf7660776e95cab3171590b8427Behdad Esfahbod  DEFINE_SIZE_MIN (8);
1792ca5290f4994e1b2db4dac03f7a22b7071441ba06Behdad Esfahbod};
1793ca5290f4994e1b2db4dac03f7a22b7071441ba06Behdad Esfahbod
179460d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbodstruct ChainRuleSet
179560d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod{
17965caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod  inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
179731081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod  {
1798be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_CLOSURE (this);
179931081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod    unsigned int num_rules = rule.len;
180031081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod    for (unsigned int i = 0; i < num_rules; i++)
18015caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod      (this+rule[i]).closure (c, lookup_context);
180231081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod  }
180331081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod
1804f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod  inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
1805f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod  {
1806f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod    TRACE_COLLECT_GLYPHS (this);
1807f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod    unsigned int num_rules = rule.len;
1808f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod    for (unsigned int i = 0; i < num_rules; i++)
1809f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod      (this+rule[i]).collect_glyphs (c, lookup_context);
1810f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod  }
1811f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod
1812e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod  inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
1813e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod  {
1814be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_WOULD_APPLY (this);
1815e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod    unsigned int num_rules = rule.len;
1816e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod    for (unsigned int i = 0; i < num_rules; i++)
1817e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod      if ((this+rule[i]).would_apply (c, lookup_context))
1818b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod        return_trace (true);
1819e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod
1820b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    return_trace (false);
1821e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod  }
1822e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod
182331081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod  inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
182460d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod  {
1825be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_APPLY (this);
182648f16ed96ac7041b511d9e0864623d2aa09c6da3Behdad Esfahbod    unsigned int num_rules = rule.len;
182760d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod    for (unsigned int i = 0; i < num_rules; i++)
1828d7cfb3b2d1dd2e9fdae2b3e540bbe313660895e8Behdad Esfahbod      if ((this+rule[i]).apply (c, lookup_context))
1829b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod        return_trace (true);
183048f16ed96ac7041b511d9e0864623d2aa09c6da3Behdad Esfahbod
1831b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    return_trace (false);
183248f16ed96ac7041b511d9e0864623d2aa09c6da3Behdad Esfahbod  }
1833ca5290f4994e1b2db4dac03f7a22b7071441ba06Behdad Esfahbod
1834de2118ed7a998a1df9b28fd1be96b4af89ed82c3Behdad Esfahbod  inline bool sanitize (hb_sanitize_context_t *c) const
1835de2118ed7a998a1df9b28fd1be96b4af89ed82c3Behdad Esfahbod  {
1836be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_SANITIZE (this);
1837b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    return_trace (rule.sanitize (c, this));
183870de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod  }
183970de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod
1840ec8d2494694275dfbbac2dd0d33ca2894b0463d6Behdad Esfahbod  protected:
184148f16ed96ac7041b511d9e0864623d2aa09c6da3Behdad Esfahbod  OffsetArrayOf<ChainRule>
184248f16ed96ac7041b511d9e0864623d2aa09c6da3Behdad Esfahbod		rule;			/* Array of ChainRule tables
184348f16ed96ac7041b511d9e0864623d2aa09c6da3Behdad Esfahbod					 * ordered by preference */
1844b3651231bf80bb7009214547a75ed90e21815c68Behdad Esfahbod  public:
18450eb9fc6e37935707dba2bf4b3705de2161a08cb7Behdad Esfahbod  DEFINE_SIZE_ARRAY (2, rule);
1846ca5290f4994e1b2db4dac03f7a22b7071441ba06Behdad Esfahbod};
1847ca5290f4994e1b2db4dac03f7a22b7071441ba06Behdad Esfahbod
184860d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbodstruct ChainContextFormat1
184960d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod{
185044fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod  inline void closure (hb_closure_context_t *c) const
1851f94b0aa64609654497ced9c00312c9643eb69053Behdad Esfahbod  {
1852be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_CLOSURE (this);
185331081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod    const Coverage &cov = (this+coverage);
185431081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod
185531081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod    struct ChainContextClosureLookupContext lookup_context = {
185644fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod      {intersects_glyph},
1857dbdbfe3d7b36613d893832dcb1884c756c20bfdaBehdad Esfahbod      {nullptr, nullptr, nullptr}
185831081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod    };
185931081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod
186031081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod    unsigned int count = ruleSet.len;
186131081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod    for (unsigned int i = 0; i < count; i++)
186231081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod      if (cov.intersects_coverage (c->glyphs, i)) {
186331081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod	const ChainRuleSet &rule_set = this+ruleSet[i];
18645caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod	rule_set.closure (c, lookup_context);
186531081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod      }
1866f94b0aa64609654497ced9c00312c9643eb69053Behdad Esfahbod  }
1867f94b0aa64609654497ced9c00312c9643eb69053Behdad Esfahbod
186826514d51b6669f092d9ccb7523443a5ece74169aBehdad Esfahbod  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
186926514d51b6669f092d9ccb7523443a5ece74169aBehdad Esfahbod  {
1870f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod    TRACE_COLLECT_GLYPHS (this);
18718303593ba1db06e402eab52df47f21f13049112dBehdad Esfahbod    (this+coverage).add_coverage (c->input);
1872f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod
1873f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod    struct ChainContextCollectGlyphsLookupContext lookup_context = {
1874f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod      {collect_glyph},
1875dbdbfe3d7b36613d893832dcb1884c756c20bfdaBehdad Esfahbod      {nullptr, nullptr, nullptr}
1876f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod    };
1877f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod
1878f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod    unsigned int count = ruleSet.len;
1879f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod    for (unsigned int i = 0; i < count; i++)
1880f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod      (this+ruleSet[i]).collect_glyphs (c, lookup_context);
188126514d51b6669f092d9ccb7523443a5ece74169aBehdad Esfahbod  }
188226514d51b6669f092d9ccb7523443a5ece74169aBehdad Esfahbod
1883e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod  inline bool would_apply (hb_would_apply_context_t *c) const
1884e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod  {
1885be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_WOULD_APPLY (this);
1886e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod
1887b67881b171a7cf865af58df146da52fc1e27b160Behdad Esfahbod    const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
1888e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod    struct ChainContextApplyLookupContext lookup_context = {
1889ec35a72a44301934b8f123ab2833f59d8c875a09Behdad Esfahbod      {match_glyph},
1890dbdbfe3d7b36613d893832dcb1884c756c20bfdaBehdad Esfahbod      {nullptr, nullptr, nullptr}
1891e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod    };
1892b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    return_trace (rule_set.would_apply (c, lookup_context));
1893e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod  }
1894e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod
189544fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod  inline const Coverage &get_coverage (void) const
189644fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod  {
189744fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod    return this+coverage;
189844fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod  }
189944fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod
1900ec35a72a44301934b8f123ab2833f59d8c875a09Behdad Esfahbod  inline bool apply (hb_apply_context_t *c) const
190160d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod  {
1902be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_APPLY (this);
1903b67881b171a7cf865af58df146da52fc1e27b160Behdad Esfahbod    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
1904b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    if (likely (index == NOT_COVERED)) return_trace (false);
1905ca5290f4994e1b2db4dac03f7a22b7071441ba06Behdad Esfahbod
1906aa3d7adca5c821c91a2a1b5380fd6b3d19656ab1Behdad Esfahbod    const ChainRuleSet &rule_set = this+ruleSet[index];
190731081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod    struct ChainContextApplyLookupContext lookup_context = {
1908ec35a72a44301934b8f123ab2833f59d8c875a09Behdad Esfahbod      {match_glyph},
1909dbdbfe3d7b36613d893832dcb1884c756c20bfdaBehdad Esfahbod      {nullptr, nullptr, nullptr}
1910aa3d7adca5c821c91a2a1b5380fd6b3d19656ab1Behdad Esfahbod    };
1911b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    return_trace (rule_set.apply (c, lookup_context));
1912aa3d7adca5c821c91a2a1b5380fd6b3d19656ab1Behdad Esfahbod  }
191370de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod
1914de2118ed7a998a1df9b28fd1be96b4af89ed82c3Behdad Esfahbod  inline bool sanitize (hb_sanitize_context_t *c) const
1915de2118ed7a998a1df9b28fd1be96b4af89ed82c3Behdad Esfahbod  {
1916be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_SANITIZE (this);
1917b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
191870de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod  }
191970de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod
1920ec8d2494694275dfbbac2dd0d33ca2894b0463d6Behdad Esfahbod  protected:
19216f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod  UINT16	format;			/* Format identifier--format = 1 */
192248f16ed96ac7041b511d9e0864623d2aa09c6da3Behdad Esfahbod  OffsetTo<Coverage>
192348f16ed96ac7041b511d9e0864623d2aa09c6da3Behdad Esfahbod		coverage;		/* Offset to Coverage table--from
1924ca5290f4994e1b2db4dac03f7a22b7071441ba06Behdad Esfahbod					 * beginning of table */
1925aa3d7adca5c821c91a2a1b5380fd6b3d19656ab1Behdad Esfahbod  OffsetArrayOf<ChainRuleSet>
1926aa3d7adca5c821c91a2a1b5380fd6b3d19656ab1Behdad Esfahbod		ruleSet;		/* Array of ChainRuleSet tables
1927aa3d7adca5c821c91a2a1b5380fd6b3d19656ab1Behdad Esfahbod					 * ordered by Coverage Index */
1928b3651231bf80bb7009214547a75ed90e21815c68Behdad Esfahbod  public:
19290eb9fc6e37935707dba2bf4b3705de2161a08cb7Behdad Esfahbod  DEFINE_SIZE_ARRAY (6, ruleSet);
1930ca5290f4994e1b2db4dac03f7a22b7071441ba06Behdad Esfahbod};
1931ca5290f4994e1b2db4dac03f7a22b7071441ba06Behdad Esfahbod
193260d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbodstruct ChainContextFormat2
193360d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod{
193444fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod  inline void closure (hb_closure_context_t *c) const
1935f94b0aa64609654497ced9c00312c9643eb69053Behdad Esfahbod  {
1936be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_CLOSURE (this);
193731081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod    if (!(this+coverage).intersects (c->glyphs))
19385caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod      return;
193931081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod
194031081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod    const ClassDef &backtrack_class_def = this+backtrackClassDef;
194131081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod    const ClassDef &input_class_def = this+inputClassDef;
194231081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod    const ClassDef &lookahead_class_def = this+lookaheadClassDef;
194331081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod
194431081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod    struct ChainContextClosureLookupContext lookup_context = {
194544fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod      {intersects_class},
194631081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod      {&backtrack_class_def,
194731081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod       &input_class_def,
194831081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod       &lookahead_class_def}
194931081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod    };
195031081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod
195131081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod    unsigned int count = ruleSet.len;
195231081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod    for (unsigned int i = 0; i < count; i++)
195331081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod      if (input_class_def.intersects_class (c->glyphs, i)) {
195431081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod	const ChainRuleSet &rule_set = this+ruleSet[i];
19555caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod	rule_set.closure (c, lookup_context);
195631081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod      }
1957f94b0aa64609654497ced9c00312c9643eb69053Behdad Esfahbod  }
1958f94b0aa64609654497ced9c00312c9643eb69053Behdad Esfahbod
195926514d51b6669f092d9ccb7523443a5ece74169aBehdad Esfahbod  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
196026514d51b6669f092d9ccb7523443a5ece74169aBehdad Esfahbod  {
1961f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod    TRACE_COLLECT_GLYPHS (this);
19628303593ba1db06e402eab52df47f21f13049112dBehdad Esfahbod    (this+coverage).add_coverage (c->input);
1963f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod
196411fba79ee9383eb995ddf7eb924dd64c67e2df63Behdad Esfahbod    const ClassDef &backtrack_class_def = this+backtrackClassDef;
196511fba79ee9383eb995ddf7eb924dd64c67e2df63Behdad Esfahbod    const ClassDef &input_class_def = this+inputClassDef;
196611fba79ee9383eb995ddf7eb924dd64c67e2df63Behdad Esfahbod    const ClassDef &lookahead_class_def = this+lookaheadClassDef;
196711fba79ee9383eb995ddf7eb924dd64c67e2df63Behdad Esfahbod
1968f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod    struct ChainContextCollectGlyphsLookupContext lookup_context = {
1969f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod      {collect_class},
197011fba79ee9383eb995ddf7eb924dd64c67e2df63Behdad Esfahbod      {&backtrack_class_def,
197111fba79ee9383eb995ddf7eb924dd64c67e2df63Behdad Esfahbod       &input_class_def,
197211fba79ee9383eb995ddf7eb924dd64c67e2df63Behdad Esfahbod       &lookahead_class_def}
1973f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod    };
1974f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod
1975f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod    unsigned int count = ruleSet.len;
1976f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod    for (unsigned int i = 0; i < count; i++)
1977f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod      (this+ruleSet[i]).collect_glyphs (c, lookup_context);
197826514d51b6669f092d9ccb7523443a5ece74169aBehdad Esfahbod  }
197926514d51b6669f092d9ccb7523443a5ece74169aBehdad Esfahbod
1980e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod  inline bool would_apply (hb_would_apply_context_t *c) const
1981e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod  {
1982be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_WOULD_APPLY (this);
1983e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod
198411fba79ee9383eb995ddf7eb924dd64c67e2df63Behdad Esfahbod    const ClassDef &backtrack_class_def = this+backtrackClassDef;
1985e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod    const ClassDef &input_class_def = this+inputClassDef;
198611fba79ee9383eb995ddf7eb924dd64c67e2df63Behdad Esfahbod    const ClassDef &lookahead_class_def = this+lookaheadClassDef;
1987e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod
19882dc1141d7d0a9f5818862b09d6b9cfe0a27f1fc1Behdad Esfahbod    unsigned int index = input_class_def.get_class (c->glyphs[0]);
1989e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod    const ChainRuleSet &rule_set = this+ruleSet[index];
1990e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod    struct ChainContextApplyLookupContext lookup_context = {
1991ec35a72a44301934b8f123ab2833f59d8c875a09Behdad Esfahbod      {match_class},
199211fba79ee9383eb995ddf7eb924dd64c67e2df63Behdad Esfahbod      {&backtrack_class_def,
199311fba79ee9383eb995ddf7eb924dd64c67e2df63Behdad Esfahbod       &input_class_def,
199411fba79ee9383eb995ddf7eb924dd64c67e2df63Behdad Esfahbod       &lookahead_class_def}
1995e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod    };
1996b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    return_trace (rule_set.would_apply (c, lookup_context));
1997e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod  }
1998e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod
199944fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod  inline const Coverage &get_coverage (void) const
200044fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod  {
200144fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod    return this+coverage;
200244fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod  }
200344fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod
2004ec35a72a44301934b8f123ab2833f59d8c875a09Behdad Esfahbod  inline bool apply (hb_apply_context_t *c) const
200560d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod  {
2006be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_APPLY (this);
2007b67881b171a7cf865af58df146da52fc1e27b160Behdad Esfahbod    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
2008b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    if (likely (index == NOT_COVERED)) return_trace (false);
2009aa3d7adca5c821c91a2a1b5380fd6b3d19656ab1Behdad Esfahbod
2010aa3d7adca5c821c91a2a1b5380fd6b3d19656ab1Behdad Esfahbod    const ClassDef &backtrack_class_def = this+backtrackClassDef;
2011aa3d7adca5c821c91a2a1b5380fd6b3d19656ab1Behdad Esfahbod    const ClassDef &input_class_def = this+inputClassDef;
2012aa3d7adca5c821c91a2a1b5380fd6b3d19656ab1Behdad Esfahbod    const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2013aa3d7adca5c821c91a2a1b5380fd6b3d19656ab1Behdad Esfahbod
20142dc1141d7d0a9f5818862b09d6b9cfe0a27f1fc1Behdad Esfahbod    index = input_class_def.get_class (c->buffer->cur().codepoint);
2015aa3d7adca5c821c91a2a1b5380fd6b3d19656ab1Behdad Esfahbod    const ChainRuleSet &rule_set = this+ruleSet[index];
201631081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod    struct ChainContextApplyLookupContext lookup_context = {
2017ec35a72a44301934b8f123ab2833f59d8c875a09Behdad Esfahbod      {match_class},
201840cbefe858192531ed64dd51d402f7ca7b8153a3Behdad Esfahbod      {&backtrack_class_def,
201940cbefe858192531ed64dd51d402f7ca7b8153a3Behdad Esfahbod       &input_class_def,
202040cbefe858192531ed64dd51d402f7ca7b8153a3Behdad Esfahbod       &lookahead_class_def}
2021aa3d7adca5c821c91a2a1b5380fd6b3d19656ab1Behdad Esfahbod    };
2022b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    return_trace (rule_set.apply (c, lookup_context));
2023ca5290f4994e1b2db4dac03f7a22b7071441ba06Behdad Esfahbod  }
2024ca5290f4994e1b2db4dac03f7a22b7071441ba06Behdad Esfahbod
2025de2118ed7a998a1df9b28fd1be96b4af89ed82c3Behdad Esfahbod  inline bool sanitize (hb_sanitize_context_t *c) const
2026de2118ed7a998a1df9b28fd1be96b4af89ed82c3Behdad Esfahbod  {
2027be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_SANITIZE (this);
2028b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    return_trace (coverage.sanitize (c, this) &&
2029b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod		  backtrackClassDef.sanitize (c, this) &&
2030b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod		  inputClassDef.sanitize (c, this) &&
2031b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod		  lookaheadClassDef.sanitize (c, this) &&
2032b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod		  ruleSet.sanitize (c, this));
203370de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod  }
203470de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod
2035ec8d2494694275dfbbac2dd0d33ca2894b0463d6Behdad Esfahbod  protected:
20366f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod  UINT16	format;			/* Format identifier--format = 2 */
2037aa3d7adca5c821c91a2a1b5380fd6b3d19656ab1Behdad Esfahbod  OffsetTo<Coverage>
2038aa3d7adca5c821c91a2a1b5380fd6b3d19656ab1Behdad Esfahbod		coverage;		/* Offset to Coverage table--from
2039ca5290f4994e1b2db4dac03f7a22b7071441ba06Behdad Esfahbod					 * beginning of table */
2040aa3d7adca5c821c91a2a1b5380fd6b3d19656ab1Behdad Esfahbod  OffsetTo<ClassDef>
2041aa3d7adca5c821c91a2a1b5380fd6b3d19656ab1Behdad Esfahbod		backtrackClassDef;	/* Offset to glyph ClassDef table
2042ca5290f4994e1b2db4dac03f7a22b7071441ba06Behdad Esfahbod					 * containing backtrack sequence
2043ca5290f4994e1b2db4dac03f7a22b7071441ba06Behdad Esfahbod					 * data--from beginning of table */
2044aa3d7adca5c821c91a2a1b5380fd6b3d19656ab1Behdad Esfahbod  OffsetTo<ClassDef>
2045aa3d7adca5c821c91a2a1b5380fd6b3d19656ab1Behdad Esfahbod		inputClassDef;		/* Offset to glyph ClassDef
2046ca5290f4994e1b2db4dac03f7a22b7071441ba06Behdad Esfahbod					 * table containing input sequence
2047ca5290f4994e1b2db4dac03f7a22b7071441ba06Behdad Esfahbod					 * data--from beginning of table */
2048aa3d7adca5c821c91a2a1b5380fd6b3d19656ab1Behdad Esfahbod  OffsetTo<ClassDef>
2049aa3d7adca5c821c91a2a1b5380fd6b3d19656ab1Behdad Esfahbod		lookaheadClassDef;	/* Offset to glyph ClassDef table
2050ca5290f4994e1b2db4dac03f7a22b7071441ba06Behdad Esfahbod					 * containing lookahead sequence
2051ca5290f4994e1b2db4dac03f7a22b7071441ba06Behdad Esfahbod					 * data--from beginning of table */
2052aa3d7adca5c821c91a2a1b5380fd6b3d19656ab1Behdad Esfahbod  OffsetArrayOf<ChainRuleSet>
2053aa3d7adca5c821c91a2a1b5380fd6b3d19656ab1Behdad Esfahbod		ruleSet;		/* Array of ChainRuleSet tables
2054aa3d7adca5c821c91a2a1b5380fd6b3d19656ab1Behdad Esfahbod					 * ordered by class */
2055b3651231bf80bb7009214547a75ed90e21815c68Behdad Esfahbod  public:
20560eb9fc6e37935707dba2bf4b3705de2161a08cb7Behdad Esfahbod  DEFINE_SIZE_ARRAY (12, ruleSet);
2057ca5290f4994e1b2db4dac03f7a22b7071441ba06Behdad Esfahbod};
2058ca5290f4994e1b2db4dac03f7a22b7071441ba06Behdad Esfahbod
205960d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbodstruct ChainContextFormat3
206060d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod{
206144fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod  inline void closure (hb_closure_context_t *c) const
2062f94b0aa64609654497ced9c00312c9643eb69053Behdad Esfahbod  {
2063be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_CLOSURE (this);
20645caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
20655caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod
20665caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod    if (!(this+input[0]).intersects (c->glyphs))
20675caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod      return;
20685caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod
20695caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
20705caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
20715caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod    struct ChainContextClosureLookupContext lookup_context = {
207244fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod      {intersects_coverage},
20735caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod      {this, this, this}
20745caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod    };
20755caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod    chain_context_closure_lookup (c,
20766f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod				  backtrack.len, (const UINT16 *) backtrack.array,
20776f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod				  input.len, (const UINT16 *) input.array + 1,
20786f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod				  lookahead.len, (const UINT16 *) lookahead.array,
20795caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod				  lookup.len, lookup.array,
20805caece67ab9eee322bdcdf6f4b607eadde297e56Behdad Esfahbod				  lookup_context);
2081f94b0aa64609654497ced9c00312c9643eb69053Behdad Esfahbod  }
2082f94b0aa64609654497ced9c00312c9643eb69053Behdad Esfahbod
208326514d51b6669f092d9ccb7523443a5ece74169aBehdad Esfahbod  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
208426514d51b6669f092d9ccb7523443a5ece74169aBehdad Esfahbod  {
2085f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod    TRACE_COLLECT_GLYPHS (this);
2086f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2087f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod
20888303593ba1db06e402eab52df47f21f13049112dBehdad Esfahbod    (this+input[0]).add_coverage (c->input);
2089f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod
2090f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2091f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2092f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod    struct ChainContextCollectGlyphsLookupContext lookup_context = {
2093f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod      {collect_coverage},
2094f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod      {this, this, this}
2095f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod    };
2096f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod    chain_context_collect_glyphs_lookup (c,
20976f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod					 backtrack.len, (const UINT16 *) backtrack.array,
20986f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod					 input.len, (const UINT16 *) input.array + 1,
20996f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod					 lookahead.len, (const UINT16 *) lookahead.array,
2100f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod					 lookup.len, lookup.array,
2101f1b12781d279a73b5754afee31e930b5cd87aac6Behdad Esfahbod					 lookup_context);
210226514d51b6669f092d9ccb7523443a5ece74169aBehdad Esfahbod  }
210326514d51b6669f092d9ccb7523443a5ece74169aBehdad Esfahbod
2104e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod  inline bool would_apply (hb_would_apply_context_t *c) const
2105e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod  {
2106be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_WOULD_APPLY (this);
2107e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod
2108e6f7479fe34fb4a7cada61d84c2ed70d1fd565c8Behdad Esfahbod    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2109e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2110e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2111e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod    struct ChainContextApplyLookupContext lookup_context = {
2112ec35a72a44301934b8f123ab2833f59d8c875a09Behdad Esfahbod      {match_coverage},
2113e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod      {this, this, this}
2114e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod    };
2115b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    return_trace (chain_context_would_apply_lookup (c,
21166f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod						    backtrack.len, (const UINT16 *) backtrack.array,
21176f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod						    input.len, (const UINT16 *) input.array + 1,
21186f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod						    lookahead.len, (const UINT16 *) lookahead.array,
2119b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod						    lookup.len, lookup.array, lookup_context));
2120e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod  }
2121e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod
212244fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod  inline const Coverage &get_coverage (void) const
212344fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod  {
212444fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
212544fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod    return this+input[0];
212644fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod  }
212744fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod
2128ec35a72a44301934b8f123ab2833f59d8c875a09Behdad Esfahbod  inline bool apply (hb_apply_context_t *c) const
212960d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod  {
2130be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_APPLY (this);
2131e961c86c579fd98ee604342a9c70c4e7f8d4f220Behdad Esfahbod    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
213202e1e5c63fa4f896053fa3c21e495239e1e9caa2Behdad Esfahbod
2133b67881b171a7cf865af58df146da52fc1e27b160Behdad Esfahbod    unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint);
2134b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    if (likely (index == NOT_COVERED)) return_trace (false);
213502e1e5c63fa4f896053fa3c21e495239e1e9caa2Behdad Esfahbod
2136e961c86c579fd98ee604342a9c70c4e7f8d4f220Behdad Esfahbod    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2137e961c86c579fd98ee604342a9c70c4e7f8d4f220Behdad Esfahbod    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
213831081f7390e5130df72f89acc609ccab5dc77a48Behdad Esfahbod    struct ChainContextApplyLookupContext lookup_context = {
2139ec35a72a44301934b8f123ab2833f59d8c875a09Behdad Esfahbod      {match_coverage},
214040cbefe858192531ed64dd51d402f7ca7b8153a3Behdad Esfahbod      {this, this, this}
2141aa3d7adca5c821c91a2a1b5380fd6b3d19656ab1Behdad Esfahbod    };
2142b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    return_trace (chain_context_apply_lookup (c,
21436f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod					      backtrack.len, (const UINT16 *) backtrack.array,
21446f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod					      input.len, (const UINT16 *) input.array + 1,
21456f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod					      lookahead.len, (const UINT16 *) lookahead.array,
2146b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod					      lookup.len, lookup.array, lookup_context));
2147aa3d7adca5c821c91a2a1b5380fd6b3d19656ab1Behdad Esfahbod  }
2148aa3d7adca5c821c91a2a1b5380fd6b3d19656ab1Behdad Esfahbod
2149de2118ed7a998a1df9b28fd1be96b4af89ed82c3Behdad Esfahbod  inline bool sanitize (hb_sanitize_context_t *c) const
2150de2118ed7a998a1df9b28fd1be96b4af89ed82c3Behdad Esfahbod  {
2151be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_SANITIZE (this);
2152b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    if (!backtrack.sanitize (c, this)) return_trace (false);
2153de2118ed7a998a1df9b28fd1be96b4af89ed82c3Behdad Esfahbod    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2154b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    if (!input.sanitize (c, this)) return_trace (false);
2155b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    if (!input.len) return_trace (false); /* To be consistent with Context. */
2156de2118ed7a998a1df9b28fd1be96b4af89ed82c3Behdad Esfahbod    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2157b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    if (!lookahead.sanitize (c, this)) return_trace (false);
2158de2118ed7a998a1df9b28fd1be96b4af89ed82c3Behdad Esfahbod    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2159b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    return_trace (lookup.sanitize (c));
216070de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod  }
216170de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod
2162ec8d2494694275dfbbac2dd0d33ca2894b0463d6Behdad Esfahbod  protected:
21636f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod  UINT16	format;			/* Format identifier--format = 3 */
2164dcb6b60254951a2831c03f3196962d229f7e556cBehdad Esfahbod  OffsetArrayOf<Coverage>
216513ed4405c558e445b052360f1ed8ee27ecf48e6eBehdad Esfahbod		backtrack;		/* Array of coverage tables
2166ca5290f4994e1b2db4dac03f7a22b7071441ba06Behdad Esfahbod					 * in backtracking sequence, in  glyph
2167ca5290f4994e1b2db4dac03f7a22b7071441ba06Behdad Esfahbod					 * sequence order */
2168dcb6b60254951a2831c03f3196962d229f7e556cBehdad Esfahbod  OffsetArrayOf<Coverage>
216913ed4405c558e445b052360f1ed8ee27ecf48e6eBehdad Esfahbod		inputX		;	/* Array of coverage
2170ca5290f4994e1b2db4dac03f7a22b7071441ba06Behdad Esfahbod					 * tables in input sequence, in glyph
2171ca5290f4994e1b2db4dac03f7a22b7071441ba06Behdad Esfahbod					 * sequence order */
2172dcb6b60254951a2831c03f3196962d229f7e556cBehdad Esfahbod  OffsetArrayOf<Coverage>
217313ed4405c558e445b052360f1ed8ee27ecf48e6eBehdad Esfahbod		lookaheadX;		/* Array of coverage tables
2174ca5290f4994e1b2db4dac03f7a22b7071441ba06Behdad Esfahbod					 * in lookahead sequence, in glyph
2175ca5290f4994e1b2db4dac03f7a22b7071441ba06Behdad Esfahbod					 * sequence order */
2176dcb6b60254951a2831c03f3196962d229f7e556cBehdad Esfahbod  ArrayOf<LookupRecord>
217702e1e5c63fa4f896053fa3c21e495239e1e9caa2Behdad Esfahbod		lookupX;		/* Array of LookupRecords--in
2178dcb6b60254951a2831c03f3196962d229f7e556cBehdad Esfahbod					 * design order) */
2179b3651231bf80bb7009214547a75ed90e21815c68Behdad Esfahbod  public:
2180bea34c7cbb583cf7660776e95cab3171590b8427Behdad Esfahbod  DEFINE_SIZE_MIN (10);
2181ca5290f4994e1b2db4dac03f7a22b7071441ba06Behdad Esfahbod};
2182ca5290f4994e1b2db4dac03f7a22b7071441ba06Behdad Esfahbod
218360d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbodstruct ChainContext
218460d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod{
218544fc237b53ebfbaf8a539de16ad735d2c6afc52bBehdad Esfahbod  template <typename context_t>
21869c5a9ee967120c8a968a1160c420e03620d46c24Behdad Esfahbod  inline typename context_t::return_t dispatch (context_t *c) const
2187e8cfdd7fa8d0fb66e0a261f3547e5824897e5131Behdad Esfahbod  {
218800f6a8e334ec4c586e4e633a95b411ccb50306d3Behdad Esfahbod    TRACE_DISPATCH (this, u.format);
2189f396fbb000dc1c8acddbf6a16e193b328c5e551eBehdad Esfahbod    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
2190e8cfdd7fa8d0fb66e0a261f3547e5824897e5131Behdad Esfahbod    switch (u.format) {
2191b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    case 1: return_trace (c->dispatch (u.format1));
2192b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    case 2: return_trace (c->dispatch (u.format2));
2193b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    case 3: return_trace (c->dispatch (u.format3));
2194b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    default:return_trace (c->default_return_value ());
2195e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod    }
2196e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod  }
2197e72b360ac6381b549249b8836fa3e70b909d3437Behdad Esfahbod
2198ec8d2494694275dfbbac2dd0d33ca2894b0463d6Behdad Esfahbod  protected:
2199ca5290f4994e1b2db4dac03f7a22b7071441ba06Behdad Esfahbod  union {
22006f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod  UINT16		format;	/* Format identifier */
2201dacebcadae36b35531d635d81df2afb937677b7aBehdad Esfahbod  ChainContextFormat1	format1;
2202dacebcadae36b35531d635d81df2afb937677b7aBehdad Esfahbod  ChainContextFormat2	format2;
2203dacebcadae36b35531d635d81df2afb937677b7aBehdad Esfahbod  ChainContextFormat3	format3;
2204ca5290f4994e1b2db4dac03f7a22b7071441ba06Behdad Esfahbod  } u;
2205ca5290f4994e1b2db4dac03f7a22b7071441ba06Behdad Esfahbod};
2206ca5290f4994e1b2db4dac03f7a22b7071441ba06Behdad Esfahbod
2207ca5290f4994e1b2db4dac03f7a22b7071441ba06Behdad Esfahbod
2208095a1257cc3cc56b044b4cd842a92f0d0f933a50Behdad Esfahbodtemplate <typename T>
2209d468f9af5b9fdc2713b0b86f28129e4190ee5053Behdad Esfahbodstruct ExtensionFormat1
2210d468f9af5b9fdc2713b0b86f28129e4190ee5053Behdad Esfahbod{
2211d468f9af5b9fdc2713b0b86f28129e4190ee5053Behdad Esfahbod  inline unsigned int get_type (void) const { return extensionLookupType; }
2212d468f9af5b9fdc2713b0b86f28129e4190ee5053Behdad Esfahbod
2213095a1257cc3cc56b044b4cd842a92f0d0f933a50Behdad Esfahbod  template <typename X>
2214095a1257cc3cc56b044b4cd842a92f0d0f933a50Behdad Esfahbod  inline const X& get_subtable (void) const
2215095a1257cc3cc56b044b4cd842a92f0d0f933a50Behdad Esfahbod  {
2216095a1257cc3cc56b044b4cd842a92f0d0f933a50Behdad Esfahbod    unsigned int offset = extensionOffset;
2217095a1257cc3cc56b044b4cd842a92f0d0f933a50Behdad Esfahbod    if (unlikely (!offset)) return Null(typename T::LookupSubTable);
2218095a1257cc3cc56b044b4cd842a92f0d0f933a50Behdad Esfahbod    return StructAtOffset<typename T::LookupSubTable> (this, offset);
2219095a1257cc3cc56b044b4cd842a92f0d0f933a50Behdad Esfahbod  }
2220095a1257cc3cc56b044b4cd842a92f0d0f933a50Behdad Esfahbod
2221095a1257cc3cc56b044b4cd842a92f0d0f933a50Behdad Esfahbod  template <typename context_t>
2222095a1257cc3cc56b044b4cd842a92f0d0f933a50Behdad Esfahbod  inline typename context_t::return_t dispatch (context_t *c) const
2223095a1257cc3cc56b044b4cd842a92f0d0f933a50Behdad Esfahbod  {
2224095a1257cc3cc56b044b4cd842a92f0d0f933a50Behdad Esfahbod    TRACE_DISPATCH (this, format);
2225f396fbb000dc1c8acddbf6a16e193b328c5e551eBehdad Esfahbod    if (unlikely (!c->may_dispatch (this, this))) return_trace (c->no_dispatch_return_value ());
2226b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    return_trace (get_subtable<typename T::LookupSubTable> ().dispatch (c, get_type ()));
2227095a1257cc3cc56b044b4cd842a92f0d0f933a50Behdad Esfahbod  }
2228095a1257cc3cc56b044b4cd842a92f0d0f933a50Behdad Esfahbod
2229095a1257cc3cc56b044b4cd842a92f0d0f933a50Behdad Esfahbod  /* This is called from may_dispatch() above with hb_sanitize_context_t. */
2230de2118ed7a998a1df9b28fd1be96b4af89ed82c3Behdad Esfahbod  inline bool sanitize (hb_sanitize_context_t *c) const
2231de2118ed7a998a1df9b28fd1be96b4af89ed82c3Behdad Esfahbod  {
2232be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_SANITIZE (this);
2233b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    return_trace (c->check_struct (this) && extensionOffset != 0);
223470de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod  }
223570de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod
2236ec8d2494694275dfbbac2dd0d33ca2894b0463d6Behdad Esfahbod  protected:
22376f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod  UINT16	format;			/* Format identifier. Set to 1. */
22386f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod  UINT16	extensionLookupType;	/* Lookup type of subtable referenced
2239d468f9af5b9fdc2713b0b86f28129e4190ee5053Behdad Esfahbod					 * by ExtensionOffset (i.e. the
2240d468f9af5b9fdc2713b0b86f28129e4190ee5053Behdad Esfahbod					 * extension subtable). */
22416f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod  UINT32		extensionOffset;	/* Offset to the extension subtable,
224281f2af40f9afd5bb9695018e6baddcd4aa3361c1Behdad Esfahbod					 * of lookup type subtable. */
2243b3651231bf80bb7009214547a75ed90e21815c68Behdad Esfahbod  public:
2244b3651231bf80bb7009214547a75ed90e21815c68Behdad Esfahbod  DEFINE_SIZE_STATIC (8);
2245d468f9af5b9fdc2713b0b86f28129e4190ee5053Behdad Esfahbod};
2246d468f9af5b9fdc2713b0b86f28129e4190ee5053Behdad Esfahbod
2247653eeb26450053b731b46346606931f5ae88db72Behdad Esfahbodtemplate <typename T>
2248d468f9af5b9fdc2713b0b86f28129e4190ee5053Behdad Esfahbodstruct Extension
2249d468f9af5b9fdc2713b0b86f28129e4190ee5053Behdad Esfahbod{
2250d468f9af5b9fdc2713b0b86f28129e4190ee5053Behdad Esfahbod  inline unsigned int get_type (void) const
2251d468f9af5b9fdc2713b0b86f28129e4190ee5053Behdad Esfahbod  {
2252d468f9af5b9fdc2713b0b86f28129e4190ee5053Behdad Esfahbod    switch (u.format) {
2253dacebcadae36b35531d635d81df2afb937677b7aBehdad Esfahbod    case 1: return u.format1.get_type ();
2254d468f9af5b9fdc2713b0b86f28129e4190ee5053Behdad Esfahbod    default:return 0;
2255d468f9af5b9fdc2713b0b86f28129e4190ee5053Behdad Esfahbod    }
2256d468f9af5b9fdc2713b0b86f28129e4190ee5053Behdad Esfahbod  }
22577dddd4e72bc35be962d93dc1b76c7e26c63aaa6dBehdad Esfahbod  template <typename X>
22587dddd4e72bc35be962d93dc1b76c7e26c63aaa6dBehdad Esfahbod  inline const X& get_subtable (void) const
22597dddd4e72bc35be962d93dc1b76c7e26c63aaa6dBehdad Esfahbod  {
2260095a1257cc3cc56b044b4cd842a92f0d0f933a50Behdad Esfahbod    switch (u.format) {
2261095a1257cc3cc56b044b4cd842a92f0d0f933a50Behdad Esfahbod    case 1: return u.format1.template get_subtable<typename T::LookupSubTable> ();
2262095a1257cc3cc56b044b4cd842a92f0d0f933a50Behdad Esfahbod    default:return Null(typename T::LookupSubTable);
2263095a1257cc3cc56b044b4cd842a92f0d0f933a50Behdad Esfahbod    }
22647dddd4e72bc35be962d93dc1b76c7e26c63aaa6dBehdad Esfahbod  }
22657dddd4e72bc35be962d93dc1b76c7e26c63aaa6dBehdad Esfahbod
2266653eeb26450053b731b46346606931f5ae88db72Behdad Esfahbod  template <typename context_t>
22679c5a9ee967120c8a968a1160c420e03620d46c24Behdad Esfahbod  inline typename context_t::return_t dispatch (context_t *c) const
2268653eeb26450053b731b46346606931f5ae88db72Behdad Esfahbod  {
2269095a1257cc3cc56b044b4cd842a92f0d0f933a50Behdad Esfahbod    TRACE_DISPATCH (this, u.format);
2270f396fbb000dc1c8acddbf6a16e193b328c5e551eBehdad Esfahbod    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
227170de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod    switch (u.format) {
2272b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    case 1: return_trace (u.format1.dispatch (c));
2273b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    default:return_trace (c->default_return_value ());
227470de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod    }
227570de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod  }
227670de50c11ed7037b20eb6814ff60f6e32a9944e4Behdad Esfahbod
2277ec8d2494694275dfbbac2dd0d33ca2894b0463d6Behdad Esfahbod  protected:
2278d468f9af5b9fdc2713b0b86f28129e4190ee5053Behdad Esfahbod  union {
22796f335ed1e52c6161fa0b0295776856fc07f7f46fBehdad Esfahbod  UINT16		format;		/* Format identifier */
2280095a1257cc3cc56b044b4cd842a92f0d0f933a50Behdad Esfahbod  ExtensionFormat1<T>	format1;
2281d468f9af5b9fdc2713b0b86f28129e4190ee5053Behdad Esfahbod  } u;
2282d468f9af5b9fdc2713b0b86f28129e4190ee5053Behdad Esfahbod};
2283d468f9af5b9fdc2713b0b86f28129e4190ee5053Behdad Esfahbod
2284d468f9af5b9fdc2713b0b86f28129e4190ee5053Behdad Esfahbod
2285f45107fe0904414f1266648a6c42849c494fe611Behdad Esfahbod/*
2286f45107fe0904414f1266648a6c42849c494fe611Behdad Esfahbod * GSUB/GPOS Common
2287f45107fe0904414f1266648a6c42849c494fe611Behdad Esfahbod */
2288f45107fe0904414f1266648a6c42849c494fe611Behdad Esfahbod
228960d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbodstruct GSUBGPOS
229060d77cf05fddc5304b4b1fc19cdedba15cbee1e9Behdad Esfahbod{
2291bff3c0fde5da04a70d1f7aeeb9fa2a75fe5c07f6Behdad Esfahbod  inline unsigned int get_script_count (void) const
2292bff3c0fde5da04a70d1f7aeeb9fa2a75fe5c07f6Behdad Esfahbod  { return (this+scriptList).len; }
2293bff3c0fde5da04a70d1f7aeeb9fa2a75fe5c07f6Behdad Esfahbod  inline const Tag& get_script_tag (unsigned int i) const
2294bff3c0fde5da04a70d1f7aeeb9fa2a75fe5c07f6Behdad Esfahbod  { return (this+scriptList).get_tag (i); }
2295e21899bc3593aa0d3adf64cee21c5de2ea219783Behdad Esfahbod  inline unsigned int get_script_tags (unsigned int start_offset,
2296e21899bc3593aa0d3adf64cee21c5de2ea219783Behdad Esfahbod				       unsigned int *script_count /* IN/OUT */,
2297e21899bc3593aa0d3adf64cee21c5de2ea219783Behdad Esfahbod				       hb_tag_t     *script_tags /* OUT */) const
2298e21899bc3593aa0d3adf64cee21c5de2ea219783Behdad Esfahbod  { return (this+scriptList).get_tags (start_offset, script_count, script_tags); }
2299bff3c0fde5da04a70d1f7aeeb9fa2a75fe5c07f6Behdad Esfahbod  inline const Script& get_script (unsigned int i) const
2300bff3c0fde5da04a70d1f7aeeb9fa2a75fe5c07f6Behdad Esfahbod  { return (this+scriptList)[i]; }
2301bff3c0fde5da04a70d1f7aeeb9fa2a75fe5c07f6Behdad Esfahbod  inline bool find_script_index (hb_tag_t tag, unsigned int *index) const
2302bff3c0fde5da04a70d1f7aeeb9fa2a75fe5c07f6Behdad Esfahbod  { return (this+scriptList).find_index (tag, index); }
2303bff3c0fde5da04a70d1f7aeeb9fa2a75fe5c07f6Behdad Esfahbod
2304bff3c0fde5da04a70d1f7aeeb9fa2a75fe5c07f6Behdad Esfahbod  inline unsigned int get_feature_count (void) const
2305bff3c0fde5da04a70d1f7aeeb9fa2a75fe5c07f6Behdad Esfahbod  { return (this+featureList).len; }
2306da132937989acb4d8ca9bd41c79f98750e7dda30Jonathan Kew  inline hb_tag_t get_feature_tag (unsigned int i) const
2307da132937989acb4d8ca9bd41c79f98750e7dda30Jonathan Kew  { return i == Index::NOT_FOUND_INDEX ? HB_TAG_NONE : (this+featureList).get_tag (i); }
2308e21899bc3593aa0d3adf64cee21c5de2ea219783Behdad Esfahbod  inline unsigned int get_feature_tags (unsigned int start_offset,
2309e21899bc3593aa0d3adf64cee21c5de2ea219783Behdad Esfahbod					unsigned int *feature_count /* IN/OUT */,
2310e21899bc3593aa0d3adf64cee21c5de2ea219783Behdad Esfahbod					hb_tag_t     *feature_tags /* OUT */) const
2311e21899bc3593aa0d3adf64cee21c5de2ea219783Behdad Esfahbod  { return (this+featureList).get_tags (start_offset, feature_count, feature_tags); }
2312bff3c0fde5da04a70d1f7aeeb9fa2a75fe5c07f6Behdad Esfahbod  inline const Feature& get_feature (unsigned int i) const
2313bff3c0fde5da04a70d1f7aeeb9fa2a75fe5c07f6Behdad Esfahbod  { return (this+featureList)[i]; }
2314bff3c0fde5da04a70d1f7aeeb9fa2a75fe5c07f6Behdad Esfahbod  inline bool find_feature_index (hb_tag_t tag, unsigned int *index) const
2315bff3c0fde5da04a70d1f7aeeb9fa2a75fe5c07f6Behdad Esfahbod  { return (this+featureList).find_index (tag, index); }
2316bff3c0fde5da04a70d1f7aeeb9fa2a75fe5c07f6Behdad Esfahbod
2317bff3c0fde5da04a70d1f7aeeb9fa2a75fe5c07f6Behdad Esfahbod  inline unsigned int get_lookup_count (void) const
2318bff3c0fde5da04a70d1f7aeeb9fa2a75fe5c07f6Behdad Esfahbod  { return (this+lookupList).len; }
2319bff3c0fde5da04a70d1f7aeeb9fa2a75fe5c07f6Behdad Esfahbod  inline const Lookup& get_lookup (unsigned int i) const
2320bff3c0fde5da04a70d1f7aeeb9fa2a75fe5c07f6Behdad Esfahbod  { return (this+lookupList)[i]; }
2321f45107fe0904414f1266648a6c42849c494fe611Behdad Esfahbod
232230c42b644eb33551aa0986287182a46f2d8c32edBehdad Esfahbod  inline bool find_variations_index (const int *coords, unsigned int num_coords,
232330c42b644eb33551aa0986287182a46f2d8c32edBehdad Esfahbod				     unsigned int *index) const
232459055b5494f802013ca3613a15e565ae1ca0c589Behdad Esfahbod  { return (version.to_int () >= 0x00010001u ? this+featureVars : Null(FeatureVariations))
232530c42b644eb33551aa0986287182a46f2d8c32edBehdad Esfahbod	   .find_index (coords, num_coords, index); }
2326ec87ba9ba32a374d49dd3e40137f75f4f4232aeeBehdad Esfahbod  inline const Feature& get_feature_variation (unsigned int feature_index,
2327ec87ba9ba32a374d49dd3e40137f75f4f4232aeeBehdad Esfahbod					       unsigned int variations_index) const
2328ec87ba9ba32a374d49dd3e40137f75f4f4232aeeBehdad Esfahbod  {
2329ec87ba9ba32a374d49dd3e40137f75f4f4232aeeBehdad Esfahbod    if (FeatureVariations::NOT_FOUND_INDEX != variations_index &&
2330ec87ba9ba32a374d49dd3e40137f75f4f4232aeeBehdad Esfahbod	version.to_int () >= 0x00010001u)
2331ec87ba9ba32a374d49dd3e40137f75f4f4232aeeBehdad Esfahbod    {
23324ebbeb7c50e5c1e934d230ceacf792602c6eb9b9Behdad Esfahbod      const Feature *feature = (this+featureVars).find_substitute (variations_index,
23334ebbeb7c50e5c1e934d230ceacf792602c6eb9b9Behdad Esfahbod								   feature_index);
2334ec87ba9ba32a374d49dd3e40137f75f4f4232aeeBehdad Esfahbod      if (feature)
2335ec87ba9ba32a374d49dd3e40137f75f4f4232aeeBehdad Esfahbod        return *feature;
2336ec87ba9ba32a374d49dd3e40137f75f4f4232aeeBehdad Esfahbod    }
2337ec87ba9ba32a374d49dd3e40137f75f4f4232aeeBehdad Esfahbod    return get_feature (feature_index);
2338ec87ba9ba32a374d49dd3e40137f75f4f4232aeeBehdad Esfahbod  }
233959055b5494f802013ca3613a15e565ae1ca0c589Behdad Esfahbod
2340de2118ed7a998a1df9b28fd1be96b4af89ed82c3Behdad Esfahbod  inline bool sanitize (hb_sanitize_context_t *c) const
2341de2118ed7a998a1df9b28fd1be96b4af89ed82c3Behdad Esfahbod  {
2342be218c688cbb037a99c8c64bb835f3c980040c0bBehdad Esfahbod    TRACE_SANITIZE (this);
2343b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod    return_trace (version.sanitize (c) &&
2344b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod		  likely (version.major == 1) &&
2345b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod		  scriptList.sanitize (c, this) &&
2346b47159011ca518c3b94d782ed16a91ffe9dd2ab2Behdad Esfahbod		  featureList.sanitize (c, this) &&
234759055b5494f802013ca3613a15e565ae1ca0c589Behdad Esfahbod		  lookupList.sanitize (c, this) &&
234859055b5494f802013ca3613a15e565ae1ca0c589Behdad Esfahbod		  (version.to_int () < 0x00010001u || featureVars.sanitize (c, this)));
2349cd3827ee567612c5500206b62840702fc956e0f5Behdad Esfahbod  }
2350cd3827ee567612c5500206b62840702fc956e0f5Behdad Esfahbod
2351212aba6189d7aaac0bab169b77ae6bdab16800a5Behdad Esfahbod  protected:
23529a13ed453ef96822a47d6e6f58332b87f38d5c59Behdad Esfahbod  FixedVersion<>version;	/* Version of the GSUB/GPOS table--initially set
23537627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod				 * to 0x00010000u */
2354f45107fe0904414f1266648a6c42849c494fe611Behdad Esfahbod  OffsetTo<ScriptList>
2355f45107fe0904414f1266648a6c42849c494fe611Behdad Esfahbod		scriptList;  	/* ScriptList table */
2356f45107fe0904414f1266648a6c42849c494fe611Behdad Esfahbod  OffsetTo<FeatureList>
2357f45107fe0904414f1266648a6c42849c494fe611Behdad Esfahbod		featureList; 	/* FeatureList table */
2358f45107fe0904414f1266648a6c42849c494fe611Behdad Esfahbod  OffsetTo<LookupList>
2359f45107fe0904414f1266648a6c42849c494fe611Behdad Esfahbod		lookupList; 	/* LookupList table */
23605e156fa5ed33cd1a8ff388833563f15930bb12f9Behdad Esfahbod  LOffsetTo<FeatureVariations>
236159055b5494f802013ca3613a15e565ae1ca0c589Behdad Esfahbod		featureVars;	/* Offset to Feature Variations
236259055b5494f802013ca3613a15e565ae1ca0c589Behdad Esfahbod				   table--from beginning of table
236359055b5494f802013ca3613a15e565ae1ca0c589Behdad Esfahbod				 * (may be NULL).  Introduced
236459055b5494f802013ca3613a15e565ae1ca0c589Behdad Esfahbod				 * in version 0x00010001. */
2365b3651231bf80bb7009214547a75ed90e21815c68Behdad Esfahbod  public:
236659055b5494f802013ca3613a15e565ae1ca0c589Behdad Esfahbod  DEFINE_SIZE_MIN (10);
2367f45107fe0904414f1266648a6c42849c494fe611Behdad Esfahbod};
236866bf7ce4e3135535c110a917178b84c4a2b1d11fBehdad Esfahbod
23696f20f72e9c58ba23db2e31afa5d331acfea3d77eBehdad Esfahbod
23707d52e6601f0e695690cd168a288466746cf25300Behdad Esfahbod} /* namespace OT */
23717c8e844d92aa604fc4b396343721ea90eb83adb8Behdad Esfahbod
2372acdba3f90b232fc12fcb200dca2584481b339118Behdad Esfahbod
23735f5b24f99f52bbc922e238b65c06061ba07c8548Behdad Esfahbod#endif /* HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH */
2374