2009-05-17 14:28:42 +02:00
|
|
|
/*
|
2011-04-21 23:14:28 +02:00
|
|
|
* Copyright © 2007,2008,2009,2010 Red Hat, Inc.
|
2012-04-24 04:26:13 +02:00
|
|
|
* Copyright © 2010,2012 Google, Inc.
|
2009-05-17 14:28:42 +02:00
|
|
|
*
|
2010-04-22 06:11:43 +02:00
|
|
|
* This is part of HarfBuzz, a text shaping library.
|
2009-05-17 14:28:42 +02:00
|
|
|
*
|
|
|
|
* Permission is hereby granted, without written agreement and without
|
|
|
|
* license or royalty fees, to use, copy, modify, and distribute this
|
|
|
|
* software and its documentation for any purpose, provided that the
|
|
|
|
* above copyright notice and the following two paragraphs appear in
|
|
|
|
* all copies of this software.
|
|
|
|
*
|
|
|
|
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
|
|
|
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
|
|
|
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
|
|
|
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
|
|
|
* DAMAGE.
|
|
|
|
*
|
|
|
|
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
|
|
|
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
|
|
|
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
|
|
|
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
|
|
|
*
|
|
|
|
* Red Hat Author(s): Behdad Esfahbod
|
2010-10-27 23:39:01 +02:00
|
|
|
* Google Author(s): Behdad Esfahbod
|
2009-05-17 14:28:42 +02:00
|
|
|
*/
|
|
|
|
|
2018-08-26 07:36:36 +02:00
|
|
|
#ifndef HB_OT_LAYOUT_GSUBGPOS_HH
|
|
|
|
#define HB_OT_LAYOUT_GSUBGPOS_HH
|
2009-05-17 14:28:42 +02:00
|
|
|
|
2018-08-26 07:36:36 +02:00
|
|
|
#include "hb.hh"
|
|
|
|
#include "hb-buffer.hh"
|
|
|
|
#include "hb-map.hh"
|
|
|
|
#include "hb-set.hh"
|
2018-09-10 22:37:19 +02:00
|
|
|
#include "hb-ot-map.hh"
|
2018-08-26 10:15:47 +02:00
|
|
|
#include "hb-ot-layout-common.hh"
|
|
|
|
#include "hb-ot-layout-gdef-table.hh"
|
2012-04-23 19:04:38 +02:00
|
|
|
|
2009-05-17 14:28:42 +02:00
|
|
|
|
2012-08-28 23:57:49 +02:00
|
|
|
namespace OT {
|
|
|
|
|
2010-07-23 21:11:18 +02:00
|
|
|
|
2018-09-03 04:47:50 +02:00
|
|
|
struct hb_intersects_context_t :
|
|
|
|
hb_dispatch_context_t<hb_intersects_context_t, bool, 0>
|
|
|
|
{
|
2018-12-17 19:01:01 +01:00
|
|
|
const char *get_name () { return "INTERSECTS"; }
|
2018-09-03 04:47:50 +02:00
|
|
|
template <typename T>
|
2018-12-16 20:08:10 +01:00
|
|
|
return_t dispatch (const T &obj) { return obj.intersects (this->glyphs); }
|
2018-12-17 19:01:01 +01:00
|
|
|
static return_t default_return_value () { return false; }
|
2018-09-03 04:47:50 +02:00
|
|
|
bool stop_sublookup_iteration (return_t r) const { return r; }
|
|
|
|
|
|
|
|
const hb_set_t *glyphs;
|
|
|
|
unsigned int debug_depth;
|
|
|
|
|
|
|
|
hb_intersects_context_t (const hb_set_t *glyphs_) :
|
|
|
|
glyphs (glyphs_),
|
|
|
|
debug_depth (0) {}
|
|
|
|
};
|
|
|
|
|
2015-10-09 18:20:58 +02:00
|
|
|
struct hb_closure_context_t :
|
2019-01-18 18:53:06 +01:00
|
|
|
hb_dispatch_context_t<hb_closure_context_t, hb_void_t, 0>
|
2012-04-23 19:04:38 +02:00
|
|
|
{
|
2018-12-17 19:01:01 +01:00
|
|
|
const char *get_name () { return "CLOSURE"; }
|
2012-11-22 05:33:13 +01:00
|
|
|
typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
|
|
|
|
template <typename T>
|
2018-12-27 15:56:41 +01:00
|
|
|
return_t dispatch (const T &obj) { obj.closure (this); return hb_void_t (); }
|
|
|
|
static return_t default_return_value () { return hb_void_t (); }
|
2018-09-03 04:47:50 +02:00
|
|
|
void recurse (unsigned int lookup_index)
|
2012-11-22 05:33:13 +01:00
|
|
|
{
|
2012-11-23 23:55:40 +01:00
|
|
|
if (unlikely (nesting_level_left == 0 || !recurse_func))
|
2018-09-03 04:47:50 +02:00
|
|
|
return;
|
2012-11-22 05:33:13 +01:00
|
|
|
|
|
|
|
nesting_level_left--;
|
|
|
|
recurse_func (this, lookup_index);
|
|
|
|
nesting_level_left++;
|
|
|
|
}
|
|
|
|
|
2018-06-12 05:24:41 +02:00
|
|
|
bool should_visit_lookup (unsigned int lookup_index)
|
2018-06-06 02:14:42 +02:00
|
|
|
{
|
|
|
|
if (is_lookup_done (lookup_index))
|
|
|
|
return false;
|
|
|
|
done_lookups->set (lookup_index, glyphs->get_population ());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool is_lookup_done (unsigned int lookup_index)
|
|
|
|
{
|
2018-07-24 18:43:27 +02:00
|
|
|
/* Have we visited this lookup with the current set of glyphs? */
|
2018-06-06 02:14:42 +02:00
|
|
|
return done_lookups->get (lookup_index) == glyphs->get_population ();
|
|
|
|
}
|
|
|
|
|
2012-04-23 19:04:38 +02:00
|
|
|
hb_face_t *face;
|
2012-04-24 04:23:17 +02:00
|
|
|
hb_set_t *glyphs;
|
2019-01-09 19:45:53 +01:00
|
|
|
hb_set_t output[1];
|
2012-11-22 05:33:13 +01:00
|
|
|
recurse_func_t recurse_func;
|
2012-04-23 19:04:38 +02:00
|
|
|
unsigned int nesting_level_left;
|
|
|
|
unsigned int debug_depth;
|
|
|
|
|
|
|
|
hb_closure_context_t (hb_face_t *face_,
|
2012-04-24 04:23:17 +02:00
|
|
|
hb_set_t *glyphs_,
|
2018-11-15 20:40:56 +01:00
|
|
|
hb_map_t *done_lookups_,
|
|
|
|
unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
|
2012-07-19 20:35:23 +02:00
|
|
|
face (face_),
|
|
|
|
glyphs (glyphs_),
|
2017-10-15 12:11:08 +02:00
|
|
|
recurse_func (nullptr),
|
2012-04-23 19:04:38 +02:00
|
|
|
nesting_level_left (nesting_level_left_),
|
2018-06-12 04:05:08 +02:00
|
|
|
debug_depth (0),
|
2018-11-15 20:40:56 +01:00
|
|
|
done_lookups (done_lookups_) {}
|
2012-11-23 23:55:40 +01:00
|
|
|
|
2018-12-17 19:01:01 +01:00
|
|
|
~hb_closure_context_t () { flush (); }
|
2018-07-24 18:43:27 +02:00
|
|
|
|
2012-11-23 23:55:40 +01:00
|
|
|
void set_recurse_func (recurse_func_t func) { recurse_func = func; }
|
2018-06-06 02:14:42 +02:00
|
|
|
|
2018-12-17 19:01:01 +01:00
|
|
|
void flush ()
|
2018-07-24 18:43:27 +02:00
|
|
|
{
|
2019-01-09 19:45:53 +01:00
|
|
|
hb_set_union (glyphs, output);
|
|
|
|
hb_set_clear (output);
|
2018-07-24 18:43:27 +02:00
|
|
|
}
|
|
|
|
|
2018-06-06 02:14:42 +02:00
|
|
|
private:
|
|
|
|
hb_map_t *done_lookups;
|
2012-04-23 19:04:38 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2015-10-09 18:20:58 +02:00
|
|
|
struct hb_would_apply_context_t :
|
|
|
|
hb_dispatch_context_t<hb_would_apply_context_t, bool, HB_DEBUG_WOULD_APPLY>
|
2012-07-19 20:35:23 +02:00
|
|
|
{
|
2018-12-17 19:01:01 +01:00
|
|
|
const char *get_name () { return "WOULD_APPLY"; }
|
2012-11-22 22:47:53 +01:00
|
|
|
template <typename T>
|
2018-12-16 20:08:10 +01:00
|
|
|
return_t dispatch (const T &obj) { return obj.would_apply (this); }
|
2018-12-17 19:01:01 +01:00
|
|
|
static return_t default_return_value () { return false; }
|
2013-01-04 08:25:27 +01:00
|
|
|
bool stop_sublookup_iteration (return_t r) const { return r; }
|
2012-11-22 22:47:53 +01:00
|
|
|
|
2012-07-19 20:35:23 +02:00
|
|
|
hb_face_t *face;
|
2012-08-08 04:25:24 +02:00
|
|
|
const hb_codepoint_t *glyphs;
|
2012-07-19 20:35:23 +02:00
|
|
|
unsigned int len;
|
2012-08-23 22:22:28 +02:00
|
|
|
bool zero_context;
|
2012-07-19 20:35:23 +02:00
|
|
|
unsigned int debug_depth;
|
|
|
|
|
|
|
|
hb_would_apply_context_t (hb_face_t *face_,
|
2012-08-08 04:25:24 +02:00
|
|
|
const hb_codepoint_t *glyphs_,
|
|
|
|
unsigned int len_,
|
2012-09-04 21:15:19 +02:00
|
|
|
bool zero_context_) :
|
2012-07-19 20:35:23 +02:00
|
|
|
face (face_),
|
2012-08-08 04:25:24 +02:00
|
|
|
glyphs (glyphs_),
|
|
|
|
len (len_),
|
2012-08-23 22:22:28 +02:00
|
|
|
zero_context (zero_context_),
|
2012-11-23 22:40:04 +01:00
|
|
|
debug_depth (0) {}
|
2012-07-19 20:35:23 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2015-10-09 18:20:58 +02:00
|
|
|
struct hb_collect_glyphs_context_t :
|
2019-01-18 20:59:18 +01:00
|
|
|
hb_dispatch_context_t<hb_collect_glyphs_context_t, hb_void_t, 0>
|
2012-11-17 04:07:06 +01:00
|
|
|
{
|
2018-12-17 19:01:01 +01:00
|
|
|
const char *get_name () { return "COLLECT_GLYPHS"; }
|
2012-11-24 00:13:48 +01:00
|
|
|
typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index);
|
2012-11-22 22:47:53 +01:00
|
|
|
template <typename T>
|
2018-12-27 15:56:41 +01:00
|
|
|
return_t dispatch (const T &obj) { obj.collect_glyphs (this); return hb_void_t (); }
|
|
|
|
static return_t default_return_value () { return hb_void_t (); }
|
2018-09-03 04:47:50 +02:00
|
|
|
void recurse (unsigned int lookup_index)
|
2012-11-22 22:47:53 +01:00
|
|
|
{
|
2012-11-24 00:13:48 +01:00
|
|
|
if (unlikely (nesting_level_left == 0 || !recurse_func))
|
2018-09-03 04:47:50 +02:00
|
|
|
return;
|
2012-11-24 00:13:48 +01:00
|
|
|
|
2017-10-15 12:11:08 +02:00
|
|
|
/* Note that GPOS sets recurse_func to nullptr already, so it doesn't get
|
2012-12-04 22:58:09 +01:00
|
|
|
* past the previous check. For GSUB, we only want to collect the output
|
2013-05-04 22:01:20 +02:00
|
|
|
* glyphs in the recursion. If output is not requested, we can go home now.
|
|
|
|
*
|
|
|
|
* Note further, that the above is not exactly correct. A recursed lookup
|
|
|
|
* is allowed to match input that is not matched in the context, but that's
|
|
|
|
* not how most fonts are built. It's possible to relax that and recurse
|
|
|
|
* with all sets here if it proves to be an issue.
|
|
|
|
*/
|
2012-12-04 23:13:09 +01:00
|
|
|
|
|
|
|
if (output == hb_set_get_empty ())
|
2018-09-03 04:47:50 +02:00
|
|
|
return;
|
2012-12-04 23:13:09 +01:00
|
|
|
|
2014-10-29 19:23:08 +01:00
|
|
|
/* Return if new lookup was recursed to before. */
|
2017-10-22 23:48:06 +02:00
|
|
|
if (recursed_lookups->has (lookup_index))
|
2018-09-03 04:47:50 +02:00
|
|
|
return;
|
2014-10-29 19:23:08 +01:00
|
|
|
|
2012-12-04 23:13:09 +01:00
|
|
|
hb_set_t *old_before = before;
|
|
|
|
hb_set_t *old_input = input;
|
|
|
|
hb_set_t *old_after = after;
|
|
|
|
before = input = after = hb_set_get_empty ();
|
2012-12-04 22:58:09 +01:00
|
|
|
|
2012-11-24 00:13:48 +01:00
|
|
|
nesting_level_left--;
|
2012-12-04 23:13:09 +01:00
|
|
|
recurse_func (this, lookup_index);
|
2012-11-24 00:13:48 +01:00
|
|
|
nesting_level_left++;
|
2012-12-04 23:13:09 +01:00
|
|
|
|
|
|
|
before = old_before;
|
|
|
|
input = old_input;
|
|
|
|
after = old_after;
|
|
|
|
|
2017-10-22 23:48:06 +02:00
|
|
|
recursed_lookups->add (lookup_index);
|
2012-11-22 22:47:53 +01:00
|
|
|
}
|
|
|
|
|
2012-11-17 04:07:06 +01:00
|
|
|
hb_face_t *face;
|
2012-12-04 23:08:41 +01:00
|
|
|
hb_set_t *before;
|
|
|
|
hb_set_t *input;
|
|
|
|
hb_set_t *after;
|
|
|
|
hb_set_t *output;
|
2012-11-24 00:13:48 +01:00
|
|
|
recurse_func_t recurse_func;
|
2017-10-22 23:48:06 +02:00
|
|
|
hb_set_t *recursed_lookups;
|
2012-11-24 00:13:48 +01:00
|
|
|
unsigned int nesting_level_left;
|
2012-11-17 04:07:06 +01:00
|
|
|
unsigned int debug_depth;
|
|
|
|
|
|
|
|
hb_collect_glyphs_context_t (hb_face_t *face_,
|
2018-10-13 12:30:05 +02:00
|
|
|
hb_set_t *glyphs_before, /* OUT. May be NULL */
|
|
|
|
hb_set_t *glyphs_input, /* OUT. May be NULL */
|
|
|
|
hb_set_t *glyphs_after, /* OUT. May be NULL */
|
|
|
|
hb_set_t *glyphs_output, /* OUT. May be NULL */
|
2015-11-03 00:43:08 +01:00
|
|
|
unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
|
2012-11-17 04:07:06 +01:00
|
|
|
face (face_),
|
2012-12-04 23:08:41 +01:00
|
|
|
before (glyphs_before ? glyphs_before : hb_set_get_empty ()),
|
|
|
|
input (glyphs_input ? glyphs_input : hb_set_get_empty ()),
|
|
|
|
after (glyphs_after ? glyphs_after : hb_set_get_empty ()),
|
|
|
|
output (glyphs_output ? glyphs_output : hb_set_get_empty ()),
|
2017-10-15 12:11:08 +02:00
|
|
|
recurse_func (nullptr),
|
2018-09-03 04:47:50 +02:00
|
|
|
recursed_lookups (hb_set_create ()),
|
2012-11-24 00:13:48 +01:00
|
|
|
nesting_level_left (nesting_level_left_),
|
2018-09-03 04:47:50 +02:00
|
|
|
debug_depth (0) {}
|
2018-12-17 19:01:01 +01:00
|
|
|
~hb_collect_glyphs_context_t () { hb_set_destroy (recursed_lookups); }
|
2012-11-24 00:13:48 +01:00
|
|
|
|
|
|
|
void set_recurse_func (recurse_func_t func) { recurse_func = func; }
|
2012-11-17 04:07:06 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
2015-02-17 17:15:34 +01:00
|
|
|
template <typename set_t>
|
2015-10-09 18:20:58 +02:00
|
|
|
struct hb_add_coverage_context_t :
|
|
|
|
hb_dispatch_context_t<hb_add_coverage_context_t<set_t>, const Coverage &, HB_DEBUG_GET_COVERAGE>
|
2012-11-22 20:38:10 +01:00
|
|
|
{
|
2018-12-17 19:01:01 +01:00
|
|
|
const char *get_name () { return "GET_COVERAGE"; }
|
2012-11-22 20:38:10 +01:00
|
|
|
typedef const Coverage &return_t;
|
|
|
|
template <typename T>
|
2018-12-16 20:08:10 +01:00
|
|
|
return_t dispatch (const T &obj) { return obj.get_coverage (); }
|
2018-12-17 19:01:01 +01:00
|
|
|
static return_t default_return_value () { return Null(Coverage); }
|
2015-02-17 17:15:34 +01:00
|
|
|
bool stop_sublookup_iteration (return_t r) const
|
|
|
|
{
|
|
|
|
r.add_coverage (set);
|
|
|
|
return false;
|
|
|
|
}
|
2012-11-22 22:47:53 +01:00
|
|
|
|
2015-02-17 17:15:34 +01:00
|
|
|
hb_add_coverage_context_t (set_t *set_) :
|
|
|
|
set (set_),
|
2012-11-23 22:40:04 +01:00
|
|
|
debug_depth (0) {}
|
|
|
|
|
2015-02-17 17:15:34 +01:00
|
|
|
set_t *set;
|
2012-11-23 22:40:04 +01:00
|
|
|
unsigned int debug_depth;
|
2012-11-22 20:38:10 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2018-01-18 01:46:51 +01:00
|
|
|
struct hb_ot_apply_context_t :
|
|
|
|
hb_dispatch_context_t<hb_ot_apply_context_t, bool, HB_DEBUG_APPLY>
|
2010-04-29 08:19:21 +02:00
|
|
|
{
|
[OTLayout] Ignore default-ignorables when matching GSUB/GPOS
When matching lookups, be smart about default-ignorable characters.
In particular:
Do nothing specific about ZWNJ, but for the other default-ignorables:
If the lookup in question uses the ignorable character in a sequence,
then match it as we used to do. However, if the sequence match will
fail because the default-ignorable blocked it, try skipping the
ignorable character and continue.
The most immediate thing it means is that if Lam-Alef forms a ligature,
then Lam-ZWJ-Alef will do to. Finally!
One exception: when matching for GPOS, or for backtrack/lookahead of
GSUB, we ignore ZWNJ too. That's the right thing to do.
It certainly is possible to build fonts that this feature will result
in undesirable glyphs, but it's hard to think of a real-world case
that that would happen.
This *does* break Indic shaping right now, since Indic Unicode has
specific rules for what ZWJ/ZWNJ mean, and skipping ZWJ is breaking
those rules. That will be fixed in upcoming commits.
2013-02-14 13:43:13 +01:00
|
|
|
struct matcher_t
|
2012-01-17 04:05:08 +01:00
|
|
|
{
|
2018-12-17 19:01:01 +01:00
|
|
|
matcher_t () :
|
[OTLayout] Ignore default-ignorables when matching GSUB/GPOS
When matching lookups, be smart about default-ignorable characters.
In particular:
Do nothing specific about ZWNJ, but for the other default-ignorables:
If the lookup in question uses the ignorable character in a sequence,
then match it as we used to do. However, if the sequence match will
fail because the default-ignorable blocked it, try skipping the
ignorable character and continue.
The most immediate thing it means is that if Lam-Alef forms a ligature,
then Lam-ZWJ-Alef will do to. Finally!
One exception: when matching for GPOS, or for backtrack/lookahead of
GSUB, we ignore ZWNJ too. That's the right thing to do.
It certainly is possible to build fonts that this feature will result
in undesirable glyphs, but it's hard to think of a real-world case
that that would happen.
This *does* break Indic shaping right now, since Indic Unicode has
specific rules for what ZWJ/ZWNJ mean, and skipping ZWJ is breaking
those rules. That will be fixed in upcoming commits.
2013-02-14 13:43:13 +01:00
|
|
|
lookup_props (0),
|
[Indic-like] Disable automatic joiner handling for basic shaping features
Not for Arabic, but for Indic-like scripts. ZWJ/ZWNJ have special
meanings in those scripts, so let font lookups take full control.
This undoes the regression caused by automatic-joiners handling
introduced two commits ago.
We only disable automatic joiner handling for the "basic shaping
features" of Indic, Myanmar, and SEAsian shapers. The "presentation
forms" and other features are still applied with automatic-joiner
handling.
This change also changes the test suite failure statistics, such that
a few scripts show more "failures". The most affected is Kannada.
However, upon inspection, we believe that in most, if not all, of the
new failures, we are producing results superior to Uniscribe. Hard to
count those!
Here's an example of what is fixed by the recent joiner-handling
changes:
https://bugs.freedesktop.org/show_bug.cgi?id=58714
New numbers, for future reference:
BENGALI: 353892 out of 354188 tests passed. 296 failed (0.0835714%)
DEVANAGARI: 707336 out of 707394 tests passed. 58 failed (0.00819911%)
GUJARATI: 366262 out of 366457 tests passed. 195 failed (0.0532122%)
GURMUKHI: 60706 out of 60747 tests passed. 41 failed (0.067493%)
KANNADA: 950680 out of 951913 tests passed. 1233 failed (0.129529%)
KHMER: 299074 out of 299124 tests passed. 50 failed (0.0167155%)
LAO: 53611 out of 53644 tests passed. 33 failed (0.0615167%)
MALAYALAM: 1047983 out of 1048334 tests passed. 351 failed (0.0334817%)
ORIYA: 42320 out of 42329 tests passed. 9 failed (0.021262%)
SINHALA: 271539 out of 271847 tests passed. 308 failed (0.113299%)
TAMIL: 1091753 out of 1091754 tests passed. 1 failed (9.15957e-05%)
TELUGU: 970555 out of 970573 tests passed. 18 failed (0.00185457%)
TIBETAN: 208469 out of 208469 tests passed. 0 failed (0%)
2013-02-14 16:40:12 +01:00
|
|
|
ignore_zwnj (false),
|
|
|
|
ignore_zwj (false),
|
[OTLayout] Ignore default-ignorables when matching GSUB/GPOS
When matching lookups, be smart about default-ignorable characters.
In particular:
Do nothing specific about ZWNJ, but for the other default-ignorables:
If the lookup in question uses the ignorable character in a sequence,
then match it as we used to do. However, if the sequence match will
fail because the default-ignorable blocked it, try skipping the
ignorable character and continue.
The most immediate thing it means is that if Lam-Alef forms a ligature,
then Lam-ZWJ-Alef will do to. Finally!
One exception: when matching for GPOS, or for backtrack/lookahead of
GSUB, we ignore ZWNJ too. That's the right thing to do.
It certainly is possible to build fonts that this feature will result
in undesirable glyphs, but it's hard to think of a real-world case
that that would happen.
This *does* break Indic shaping right now, since Indic Unicode has
specific rules for what ZWJ/ZWNJ mean, and skipping ZWJ is breaking
those rules. That will be fixed in upcoming commits.
2013-02-14 13:43:13 +01:00
|
|
|
mask (-1),
|
|
|
|
#define arg1(arg) (arg) /* Remove the macro to see why it's needed! */
|
|
|
|
syllable arg1(0),
|
|
|
|
#undef arg1
|
2017-10-15 12:11:08 +02:00
|
|
|
match_func (nullptr),
|
2018-10-30 08:59:09 +01:00
|
|
|
match_data (nullptr) {}
|
[OTLayout] Ignore default-ignorables when matching GSUB/GPOS
When matching lookups, be smart about default-ignorable characters.
In particular:
Do nothing specific about ZWNJ, but for the other default-ignorables:
If the lookup in question uses the ignorable character in a sequence,
then match it as we used to do. However, if the sequence match will
fail because the default-ignorable blocked it, try skipping the
ignorable character and continue.
The most immediate thing it means is that if Lam-Alef forms a ligature,
then Lam-ZWJ-Alef will do to. Finally!
One exception: when matching for GPOS, or for backtrack/lookahead of
GSUB, we ignore ZWNJ too. That's the right thing to do.
It certainly is possible to build fonts that this feature will result
in undesirable glyphs, but it's hard to think of a real-world case
that that would happen.
This *does* break Indic shaping right now, since Indic Unicode has
specific rules for what ZWJ/ZWNJ mean, and skipping ZWJ is breaking
those rules. That will be fixed in upcoming commits.
2013-02-14 13:43:13 +01:00
|
|
|
|
2018-01-10 03:07:30 +01:00
|
|
|
typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data);
|
[OTLayout] Ignore default-ignorables when matching GSUB/GPOS
When matching lookups, be smart about default-ignorable characters.
In particular:
Do nothing specific about ZWNJ, but for the other default-ignorables:
If the lookup in question uses the ignorable character in a sequence,
then match it as we used to do. However, if the sequence match will
fail because the default-ignorable blocked it, try skipping the
ignorable character and continue.
The most immediate thing it means is that if Lam-Alef forms a ligature,
then Lam-ZWJ-Alef will do to. Finally!
One exception: when matching for GPOS, or for backtrack/lookahead of
GSUB, we ignore ZWNJ too. That's the right thing to do.
It certainly is possible to build fonts that this feature will result
in undesirable glyphs, but it's hard to think of a real-world case
that that would happen.
This *does* break Indic shaping right now, since Indic Unicode has
specific rules for what ZWJ/ZWNJ mean, and skipping ZWJ is breaking
those rules. That will be fixed in upcoming commits.
2013-02-14 13:43:13 +01:00
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; }
|
|
|
|
void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; }
|
|
|
|
void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
|
|
|
|
void set_mask (hb_mask_t mask_) { mask = mask_; }
|
|
|
|
void set_syllable (uint8_t syllable_) { syllable = syllable_; }
|
|
|
|
void set_match_func (match_func_t match_func_,
|
[OTLayout] Ignore default-ignorables when matching GSUB/GPOS
When matching lookups, be smart about default-ignorable characters.
In particular:
Do nothing specific about ZWNJ, but for the other default-ignorables:
If the lookup in question uses the ignorable character in a sequence,
then match it as we used to do. However, if the sequence match will
fail because the default-ignorable blocked it, try skipping the
ignorable character and continue.
The most immediate thing it means is that if Lam-Alef forms a ligature,
then Lam-ZWJ-Alef will do to. Finally!
One exception: when matching for GPOS, or for backtrack/lookahead of
GSUB, we ignore ZWNJ too. That's the right thing to do.
It certainly is possible to build fonts that this feature will result
in undesirable glyphs, but it's hard to think of a real-world case
that that would happen.
This *does* break Indic shaping right now, since Indic Unicode has
specific rules for what ZWJ/ZWNJ mean, and skipping ZWJ is breaking
those rules. That will be fixed in upcoming commits.
2013-02-14 13:43:13 +01:00
|
|
|
const void *match_data_)
|
|
|
|
{ match_func = match_func_; match_data = match_data_; }
|
|
|
|
|
2013-02-21 21:07:03 +01:00
|
|
|
enum may_match_t {
|
|
|
|
MATCH_NO,
|
|
|
|
MATCH_YES,
|
|
|
|
MATCH_MAYBE
|
|
|
|
};
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
may_match_t may_match (const hb_glyph_info_t &info,
|
2018-11-15 20:40:56 +01:00
|
|
|
const HBUINT16 *glyph_data) const
|
2012-01-17 04:05:08 +01:00
|
|
|
{
|
2013-02-21 21:07:03 +01:00
|
|
|
if (!(info.mask & mask) ||
|
|
|
|
(syllable && syllable != info.syllable ()))
|
|
|
|
return MATCH_NO;
|
|
|
|
|
|
|
|
if (match_func)
|
2018-11-15 20:40:56 +01:00
|
|
|
return match_func (info.codepoint, *glyph_data, match_data) ? MATCH_YES : MATCH_NO;
|
2013-02-21 21:07:03 +01:00
|
|
|
|
|
|
|
return MATCH_MAYBE;
|
2012-01-17 04:05:08 +01:00
|
|
|
}
|
[OTLayout] Ignore default-ignorables when matching GSUB/GPOS
When matching lookups, be smart about default-ignorable characters.
In particular:
Do nothing specific about ZWNJ, but for the other default-ignorables:
If the lookup in question uses the ignorable character in a sequence,
then match it as we used to do. However, if the sequence match will
fail because the default-ignorable blocked it, try skipping the
ignorable character and continue.
The most immediate thing it means is that if Lam-Alef forms a ligature,
then Lam-ZWJ-Alef will do to. Finally!
One exception: when matching for GPOS, or for backtrack/lookahead of
GSUB, we ignore ZWNJ too. That's the right thing to do.
It certainly is possible to build fonts that this feature will result
in undesirable glyphs, but it's hard to think of a real-world case
that that would happen.
This *does* break Indic shaping right now, since Indic Unicode has
specific rules for what ZWJ/ZWNJ mean, and skipping ZWJ is breaking
those rules. That will be fixed in upcoming commits.
2013-02-14 13:43:13 +01:00
|
|
|
|
|
|
|
enum may_skip_t {
|
|
|
|
SKIP_NO,
|
|
|
|
SKIP_YES,
|
|
|
|
SKIP_MAYBE
|
|
|
|
};
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
may_skip_t may_skip (const hb_ot_apply_context_t *c,
|
|
|
|
const hb_glyph_info_t &info) const
|
2013-02-13 17:22:42 +01:00
|
|
|
{
|
2014-07-16 19:44:01 +02:00
|
|
|
if (!c->check_glyph_property (&info, lookup_props))
|
[OTLayout] Ignore default-ignorables when matching GSUB/GPOS
When matching lookups, be smart about default-ignorable characters.
In particular:
Do nothing specific about ZWNJ, but for the other default-ignorables:
If the lookup in question uses the ignorable character in a sequence,
then match it as we used to do. However, if the sequence match will
fail because the default-ignorable blocked it, try skipping the
ignorable character and continue.
The most immediate thing it means is that if Lam-Alef forms a ligature,
then Lam-ZWJ-Alef will do to. Finally!
One exception: when matching for GPOS, or for backtrack/lookahead of
GSUB, we ignore ZWNJ too. That's the right thing to do.
It certainly is possible to build fonts that this feature will result
in undesirable glyphs, but it's hard to think of a real-world case
that that would happen.
This *does* break Indic shaping right now, since Indic Unicode has
specific rules for what ZWJ/ZWNJ mean, and skipping ZWJ is breaking
those rules. That will be fixed in upcoming commits.
2013-02-14 13:43:13 +01:00
|
|
|
return SKIP_YES;
|
|
|
|
|
2017-05-17 20:32:47 +02:00
|
|
|
if (unlikely (_hb_glyph_info_is_default_ignorable_and_not_hidden (&info) &&
|
2013-02-14 16:46:52 +01:00
|
|
|
(ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) &&
|
2015-07-22 18:41:31 +02:00
|
|
|
(ignore_zwj || !_hb_glyph_info_is_zwj (&info))))
|
[OTLayout] Ignore default-ignorables when matching GSUB/GPOS
When matching lookups, be smart about default-ignorable characters.
In particular:
Do nothing specific about ZWNJ, but for the other default-ignorables:
If the lookup in question uses the ignorable character in a sequence,
then match it as we used to do. However, if the sequence match will
fail because the default-ignorable blocked it, try skipping the
ignorable character and continue.
The most immediate thing it means is that if Lam-Alef forms a ligature,
then Lam-ZWJ-Alef will do to. Finally!
One exception: when matching for GPOS, or for backtrack/lookahead of
GSUB, we ignore ZWNJ too. That's the right thing to do.
It certainly is possible to build fonts that this feature will result
in undesirable glyphs, but it's hard to think of a real-world case
that that would happen.
This *does* break Indic shaping right now, since Indic Unicode has
specific rules for what ZWJ/ZWNJ mean, and skipping ZWJ is breaking
those rules. That will be fixed in upcoming commits.
2013-02-14 13:43:13 +01:00
|
|
|
return SKIP_MAYBE;
|
|
|
|
|
|
|
|
return SKIP_NO;
|
2013-02-13 17:22:42 +01:00
|
|
|
}
|
[OTLayout] Ignore default-ignorables when matching GSUB/GPOS
When matching lookups, be smart about default-ignorable characters.
In particular:
Do nothing specific about ZWNJ, but for the other default-ignorables:
If the lookup in question uses the ignorable character in a sequence,
then match it as we used to do. However, if the sequence match will
fail because the default-ignorable blocked it, try skipping the
ignorable character and continue.
The most immediate thing it means is that if Lam-Alef forms a ligature,
then Lam-ZWJ-Alef will do to. Finally!
One exception: when matching for GPOS, or for backtrack/lookahead of
GSUB, we ignore ZWNJ too. That's the right thing to do.
It certainly is possible to build fonts that this feature will result
in undesirable glyphs, but it's hard to think of a real-world case
that that would happen.
This *does* break Indic shaping right now, since Indic Unicode has
specific rules for what ZWJ/ZWNJ mean, and skipping ZWJ is breaking
those rules. That will be fixed in upcoming commits.
2013-02-14 13:43:13 +01:00
|
|
|
|
|
|
|
protected:
|
|
|
|
unsigned int lookup_props;
|
|
|
|
bool ignore_zwnj;
|
2013-02-14 16:46:52 +01:00
|
|
|
bool ignore_zwj;
|
[OTLayout] Ignore default-ignorables when matching GSUB/GPOS
When matching lookups, be smart about default-ignorable characters.
In particular:
Do nothing specific about ZWNJ, but for the other default-ignorables:
If the lookup in question uses the ignorable character in a sequence,
then match it as we used to do. However, if the sequence match will
fail because the default-ignorable blocked it, try skipping the
ignorable character and continue.
The most immediate thing it means is that if Lam-Alef forms a ligature,
then Lam-ZWJ-Alef will do to. Finally!
One exception: when matching for GPOS, or for backtrack/lookahead of
GSUB, we ignore ZWNJ too. That's the right thing to do.
It certainly is possible to build fonts that this feature will result
in undesirable glyphs, but it's hard to think of a real-world case
that that would happen.
This *does* break Indic shaping right now, since Indic Unicode has
specific rules for what ZWJ/ZWNJ mean, and skipping ZWJ is breaking
those rules. That will be fixed in upcoming commits.
2013-02-14 13:43:13 +01:00
|
|
|
hb_mask_t mask;
|
|
|
|
uint8_t syllable;
|
|
|
|
match_func_t match_func;
|
|
|
|
const void *match_data;
|
|
|
|
};
|
|
|
|
|
2015-01-29 13:08:41 +01:00
|
|
|
struct skipping_iterator_t
|
[OTLayout] Ignore default-ignorables when matching GSUB/GPOS
When matching lookups, be smart about default-ignorable characters.
In particular:
Do nothing specific about ZWNJ, but for the other default-ignorables:
If the lookup in question uses the ignorable character in a sequence,
then match it as we used to do. However, if the sequence match will
fail because the default-ignorable blocked it, try skipping the
ignorable character and continue.
The most immediate thing it means is that if Lam-Alef forms a ligature,
then Lam-ZWJ-Alef will do to. Finally!
One exception: when matching for GPOS, or for backtrack/lookahead of
GSUB, we ignore ZWNJ too. That's the right thing to do.
It certainly is possible to build fonts that this feature will result
in undesirable glyphs, but it's hard to think of a real-world case
that that would happen.
This *does* break Indic shaping right now, since Indic Unicode has
specific rules for what ZWJ/ZWNJ mean, and skipping ZWJ is breaking
those rules. That will be fixed in upcoming commits.
2013-02-14 13:43:13 +01:00
|
|
|
{
|
2018-12-16 20:08:10 +01:00
|
|
|
void init (hb_ot_apply_context_t *c_, bool context_match = false)
|
2012-01-17 04:05:08 +01:00
|
|
|
{
|
2015-01-29 13:48:48 +01:00
|
|
|
c = c_;
|
2017-10-15 12:11:08 +02:00
|
|
|
match_glyph_data = nullptr;
|
|
|
|
matcher.set_match_func (nullptr, nullptr);
|
[OTLayout] Ignore default-ignorables when matching GSUB/GPOS
When matching lookups, be smart about default-ignorable characters.
In particular:
Do nothing specific about ZWNJ, but for the other default-ignorables:
If the lookup in question uses the ignorable character in a sequence,
then match it as we used to do. However, if the sequence match will
fail because the default-ignorable blocked it, try skipping the
ignorable character and continue.
The most immediate thing it means is that if Lam-Alef forms a ligature,
then Lam-ZWJ-Alef will do to. Finally!
One exception: when matching for GPOS, or for backtrack/lookahead of
GSUB, we ignore ZWNJ too. That's the right thing to do.
It certainly is possible to build fonts that this feature will result
in undesirable glyphs, but it's hard to think of a real-world case
that that would happen.
This *does* break Indic shaping right now, since Indic Unicode has
specific rules for what ZWJ/ZWNJ mean, and skipping ZWJ is breaking
those rules. That will be fixed in upcoming commits.
2013-02-14 13:43:13 +01:00
|
|
|
matcher.set_lookup_props (c->lookup_props);
|
2018-09-24 04:33:38 +02:00
|
|
|
/* Ignore ZWNJ if we are matching GPOS, or matching GSUB context and asked to. */
|
2017-07-14 13:43:34 +02:00
|
|
|
matcher.set_ignore_zwnj (c->table_index == 1 || (context_match && c->auto_zwnj));
|
2018-09-24 04:33:38 +02:00
|
|
|
/* Ignore ZWJ if we are matching context, or asked to. */
|
|
|
|
matcher.set_ignore_zwj (context_match || c->auto_zwj);
|
2015-01-29 13:48:48 +01:00
|
|
|
matcher.set_mask (context_match ? -1 : c->lookup_mask);
|
|
|
|
}
|
2018-12-16 20:08:10 +01:00
|
|
|
void set_lookup_props (unsigned int lookup_props)
|
2015-01-29 13:48:48 +01:00
|
|
|
{
|
|
|
|
matcher.set_lookup_props (lookup_props);
|
2012-01-17 04:05:08 +01:00
|
|
|
}
|
2018-12-16 20:08:10 +01:00
|
|
|
void set_match_func (matcher_t::match_func_t match_func_,
|
|
|
|
const void *match_data_,
|
|
|
|
const HBUINT16 glyph_data[])
|
2012-06-09 04:04:23 +02:00
|
|
|
{
|
2015-10-21 15:20:55 +02:00
|
|
|
matcher.set_match_func (match_func_, match_data_);
|
[OTLayout] Ignore default-ignorables when matching GSUB/GPOS
When matching lookups, be smart about default-ignorable characters.
In particular:
Do nothing specific about ZWNJ, but for the other default-ignorables:
If the lookup in question uses the ignorable character in a sequence,
then match it as we used to do. However, if the sequence match will
fail because the default-ignorable blocked it, try skipping the
ignorable character and continue.
The most immediate thing it means is that if Lam-Alef forms a ligature,
then Lam-ZWJ-Alef will do to. Finally!
One exception: when matching for GPOS, or for backtrack/lookahead of
GSUB, we ignore ZWNJ too. That's the right thing to do.
It certainly is possible to build fonts that this feature will result
in undesirable glyphs, but it's hard to think of a real-world case
that that would happen.
This *does* break Indic shaping right now, since Indic Unicode has
specific rules for what ZWJ/ZWNJ mean, and skipping ZWJ is breaking
those rules. That will be fixed in upcoming commits.
2013-02-14 13:43:13 +01:00
|
|
|
match_glyph_data = glyph_data;
|
2012-06-09 04:04:23 +02:00
|
|
|
}
|
[OTLayout] Ignore default-ignorables when matching GSUB/GPOS
When matching lookups, be smart about default-ignorable characters.
In particular:
Do nothing specific about ZWNJ, but for the other default-ignorables:
If the lookup in question uses the ignorable character in a sequence,
then match it as we used to do. However, if the sequence match will
fail because the default-ignorable blocked it, try skipping the
ignorable character and continue.
The most immediate thing it means is that if Lam-Alef forms a ligature,
then Lam-ZWJ-Alef will do to. Finally!
One exception: when matching for GPOS, or for backtrack/lookahead of
GSUB, we ignore ZWNJ too. That's the right thing to do.
It certainly is possible to build fonts that this feature will result
in undesirable glyphs, but it's hard to think of a real-world case
that that would happen.
This *does* break Indic shaping right now, since Indic Unicode has
specific rules for what ZWJ/ZWNJ mean, and skipping ZWJ is breaking
those rules. That will be fixed in upcoming commits.
2013-02-14 13:43:13 +01:00
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
void reset (unsigned int start_index_,
|
2015-01-29 13:40:39 +01:00
|
|
|
unsigned int num_items_)
|
|
|
|
{
|
|
|
|
idx = start_index_;
|
|
|
|
num_items = num_items_;
|
|
|
|
end = c->buffer->len;
|
|
|
|
matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
|
|
|
|
}
|
|
|
|
|
2018-12-17 19:01:01 +01:00
|
|
|
void reject () { num_items++; match_glyph_data--; }
|
2015-01-29 13:08:41 +01:00
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
matcher_t::may_skip_t
|
|
|
|
may_skip (const hb_glyph_info_t &info) const
|
2018-12-17 19:01:01 +01:00
|
|
|
{ return matcher.may_skip (c, info); }
|
2017-10-02 20:02:45 +02:00
|
|
|
|
2018-12-17 19:01:01 +01:00
|
|
|
bool next ()
|
2012-01-17 04:05:08 +01:00
|
|
|
{
|
2012-01-18 22:07:53 +01:00
|
|
|
assert (num_items > 0);
|
2015-01-29 11:38:01 +01:00
|
|
|
while (idx + num_items < end)
|
2012-01-17 04:05:08 +01:00
|
|
|
{
|
2012-01-18 00:08:41 +01:00
|
|
|
idx++;
|
[OTLayout] Ignore default-ignorables when matching GSUB/GPOS
When matching lookups, be smart about default-ignorable characters.
In particular:
Do nothing specific about ZWNJ, but for the other default-ignorables:
If the lookup in question uses the ignorable character in a sequence,
then match it as we used to do. However, if the sequence match will
fail because the default-ignorable blocked it, try skipping the
ignorable character and continue.
The most immediate thing it means is that if Lam-Alef forms a ligature,
then Lam-ZWJ-Alef will do to. Finally!
One exception: when matching for GPOS, or for backtrack/lookahead of
GSUB, we ignore ZWNJ too. That's the right thing to do.
It certainly is possible to build fonts that this feature will result
in undesirable glyphs, but it's hard to think of a real-world case
that that would happen.
This *does* break Indic shaping right now, since Indic Unicode has
specific rules for what ZWJ/ZWNJ mean, and skipping ZWJ is breaking
those rules. That will be fixed in upcoming commits.
2013-02-14 13:43:13 +01:00
|
|
|
const hb_glyph_info_t &info = c->buffer->info[idx];
|
|
|
|
|
2013-02-21 20:51:40 +01:00
|
|
|
matcher_t::may_skip_t skip = matcher.may_skip (c, info);
|
[OTLayout] Ignore default-ignorables when matching GSUB/GPOS
When matching lookups, be smart about default-ignorable characters.
In particular:
Do nothing specific about ZWNJ, but for the other default-ignorables:
If the lookup in question uses the ignorable character in a sequence,
then match it as we used to do. However, if the sequence match will
fail because the default-ignorable blocked it, try skipping the
ignorable character and continue.
The most immediate thing it means is that if Lam-Alef forms a ligature,
then Lam-ZWJ-Alef will do to. Finally!
One exception: when matching for GPOS, or for backtrack/lookahead of
GSUB, we ignore ZWNJ too. That's the right thing to do.
It certainly is possible to build fonts that this feature will result
in undesirable glyphs, but it's hard to think of a real-world case
that that would happen.
This *does* break Indic shaping right now, since Indic Unicode has
specific rules for what ZWJ/ZWNJ mean, and skipping ZWJ is breaking
those rules. That will be fixed in upcoming commits.
2013-02-14 13:43:13 +01:00
|
|
|
if (unlikely (skip == matcher_t::SKIP_YES))
|
|
|
|
continue;
|
|
|
|
|
2013-02-21 21:07:03 +01:00
|
|
|
matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
|
2013-02-21 21:37:51 +01:00
|
|
|
if (match == matcher_t::MATCH_YES ||
|
|
|
|
(match == matcher_t::MATCH_MAYBE &&
|
|
|
|
skip == matcher_t::SKIP_NO))
|
[OTLayout] Ignore default-ignorables when matching GSUB/GPOS
When matching lookups, be smart about default-ignorable characters.
In particular:
Do nothing specific about ZWNJ, but for the other default-ignorables:
If the lookup in question uses the ignorable character in a sequence,
then match it as we used to do. However, if the sequence match will
fail because the default-ignorable blocked it, try skipping the
ignorable character and continue.
The most immediate thing it means is that if Lam-Alef forms a ligature,
then Lam-ZWJ-Alef will do to. Finally!
One exception: when matching for GPOS, or for backtrack/lookahead of
GSUB, we ignore ZWNJ too. That's the right thing to do.
It certainly is possible to build fonts that this feature will result
in undesirable glyphs, but it's hard to think of a real-world case
that that would happen.
This *does* break Indic shaping right now, since Indic Unicode has
specific rules for what ZWJ/ZWNJ mean, and skipping ZWJ is breaking
those rules. That will be fixed in upcoming commits.
2013-02-14 13:43:13 +01:00
|
|
|
{
|
|
|
|
num_items--;
|
|
|
|
match_glyph_data++;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (skip == matcher_t::SKIP_NO)
|
2013-02-21 21:37:51 +01:00
|
|
|
return false;
|
[OTLayout] Ignore default-ignorables when matching GSUB/GPOS
When matching lookups, be smart about default-ignorable characters.
In particular:
Do nothing specific about ZWNJ, but for the other default-ignorables:
If the lookup in question uses the ignorable character in a sequence,
then match it as we used to do. However, if the sequence match will
fail because the default-ignorable blocked it, try skipping the
ignorable character and continue.
The most immediate thing it means is that if Lam-Alef forms a ligature,
then Lam-ZWJ-Alef will do to. Finally!
One exception: when matching for GPOS, or for backtrack/lookahead of
GSUB, we ignore ZWNJ too. That's the right thing to do.
It certainly is possible to build fonts that this feature will result
in undesirable glyphs, but it's hard to think of a real-world case
that that would happen.
This *does* break Indic shaping right now, since Indic Unicode has
specific rules for what ZWJ/ZWNJ mean, and skipping ZWJ is breaking
those rules. That will be fixed in upcoming commits.
2013-02-14 13:43:13 +01:00
|
|
|
}
|
|
|
|
return false;
|
2012-01-17 04:05:08 +01:00
|
|
|
}
|
2018-12-17 19:01:01 +01:00
|
|
|
bool prev ()
|
2012-01-17 04:05:08 +01:00
|
|
|
{
|
2012-01-18 22:07:53 +01:00
|
|
|
assert (num_items > 0);
|
2018-07-05 11:33:48 +02:00
|
|
|
while (idx > num_items - 1)
|
2012-01-17 04:05:08 +01:00
|
|
|
{
|
|
|
|
idx--;
|
[OTLayout] Ignore default-ignorables when matching GSUB/GPOS
When matching lookups, be smart about default-ignorable characters.
In particular:
Do nothing specific about ZWNJ, but for the other default-ignorables:
If the lookup in question uses the ignorable character in a sequence,
then match it as we used to do. However, if the sequence match will
fail because the default-ignorable blocked it, try skipping the
ignorable character and continue.
The most immediate thing it means is that if Lam-Alef forms a ligature,
then Lam-ZWJ-Alef will do to. Finally!
One exception: when matching for GPOS, or for backtrack/lookahead of
GSUB, we ignore ZWNJ too. That's the right thing to do.
It certainly is possible to build fonts that this feature will result
in undesirable glyphs, but it's hard to think of a real-world case
that that would happen.
This *does* break Indic shaping right now, since Indic Unicode has
specific rules for what ZWJ/ZWNJ mean, and skipping ZWJ is breaking
those rules. That will be fixed in upcoming commits.
2013-02-14 13:43:13 +01:00
|
|
|
const hb_glyph_info_t &info = c->buffer->out_info[idx];
|
|
|
|
|
2013-02-21 20:51:40 +01:00
|
|
|
matcher_t::may_skip_t skip = matcher.may_skip (c, info);
|
[OTLayout] Ignore default-ignorables when matching GSUB/GPOS
When matching lookups, be smart about default-ignorable characters.
In particular:
Do nothing specific about ZWNJ, but for the other default-ignorables:
If the lookup in question uses the ignorable character in a sequence,
then match it as we used to do. However, if the sequence match will
fail because the default-ignorable blocked it, try skipping the
ignorable character and continue.
The most immediate thing it means is that if Lam-Alef forms a ligature,
then Lam-ZWJ-Alef will do to. Finally!
One exception: when matching for GPOS, or for backtrack/lookahead of
GSUB, we ignore ZWNJ too. That's the right thing to do.
It certainly is possible to build fonts that this feature will result
in undesirable glyphs, but it's hard to think of a real-world case
that that would happen.
This *does* break Indic shaping right now, since Indic Unicode has
specific rules for what ZWJ/ZWNJ mean, and skipping ZWJ is breaking
those rules. That will be fixed in upcoming commits.
2013-02-14 13:43:13 +01:00
|
|
|
if (unlikely (skip == matcher_t::SKIP_YES))
|
|
|
|
continue;
|
|
|
|
|
2013-02-21 21:07:03 +01:00
|
|
|
matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
|
2013-02-21 21:37:51 +01:00
|
|
|
if (match == matcher_t::MATCH_YES ||
|
|
|
|
(match == matcher_t::MATCH_MAYBE &&
|
|
|
|
skip == matcher_t::SKIP_NO))
|
[OTLayout] Ignore default-ignorables when matching GSUB/GPOS
When matching lookups, be smart about default-ignorable characters.
In particular:
Do nothing specific about ZWNJ, but for the other default-ignorables:
If the lookup in question uses the ignorable character in a sequence,
then match it as we used to do. However, if the sequence match will
fail because the default-ignorable blocked it, try skipping the
ignorable character and continue.
The most immediate thing it means is that if Lam-Alef forms a ligature,
then Lam-ZWJ-Alef will do to. Finally!
One exception: when matching for GPOS, or for backtrack/lookahead of
GSUB, we ignore ZWNJ too. That's the right thing to do.
It certainly is possible to build fonts that this feature will result
in undesirable glyphs, but it's hard to think of a real-world case
that that would happen.
This *does* break Indic shaping right now, since Indic Unicode has
specific rules for what ZWJ/ZWNJ mean, and skipping ZWJ is breaking
those rules. That will be fixed in upcoming commits.
2013-02-14 13:43:13 +01:00
|
|
|
{
|
|
|
|
num_items--;
|
|
|
|
match_glyph_data++;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (skip == matcher_t::SKIP_NO)
|
2013-02-21 21:37:51 +01:00
|
|
|
return false;
|
[OTLayout] Ignore default-ignorables when matching GSUB/GPOS
When matching lookups, be smart about default-ignorable characters.
In particular:
Do nothing specific about ZWNJ, but for the other default-ignorables:
If the lookup in question uses the ignorable character in a sequence,
then match it as we used to do. However, if the sequence match will
fail because the default-ignorable blocked it, try skipping the
ignorable character and continue.
The most immediate thing it means is that if Lam-Alef forms a ligature,
then Lam-ZWJ-Alef will do to. Finally!
One exception: when matching for GPOS, or for backtrack/lookahead of
GSUB, we ignore ZWNJ too. That's the right thing to do.
It certainly is possible to build fonts that this feature will result
in undesirable glyphs, but it's hard to think of a real-world case
that that would happen.
This *does* break Indic shaping right now, since Indic Unicode has
specific rules for what ZWJ/ZWNJ mean, and skipping ZWJ is breaking
those rules. That will be fixed in upcoming commits.
2013-02-14 13:43:13 +01:00
|
|
|
}
|
|
|
|
return false;
|
2012-01-17 04:05:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int idx;
|
2012-07-24 21:40:37 +02:00
|
|
|
protected:
|
2018-01-18 01:46:51 +01:00
|
|
|
hb_ot_apply_context_t *c;
|
[OTLayout] Ignore default-ignorables when matching GSUB/GPOS
When matching lookups, be smart about default-ignorable characters.
In particular:
Do nothing specific about ZWNJ, but for the other default-ignorables:
If the lookup in question uses the ignorable character in a sequence,
then match it as we used to do. However, if the sequence match will
fail because the default-ignorable blocked it, try skipping the
ignorable character and continue.
The most immediate thing it means is that if Lam-Alef forms a ligature,
then Lam-ZWJ-Alef will do to. Finally!
One exception: when matching for GPOS, or for backtrack/lookahead of
GSUB, we ignore ZWNJ too. That's the right thing to do.
It certainly is possible to build fonts that this feature will result
in undesirable glyphs, but it's hard to think of a real-world case
that that would happen.
This *does* break Indic shaping right now, since Indic Unicode has
specific rules for what ZWJ/ZWNJ mean, and skipping ZWJ is breaking
those rules. That will be fixed in upcoming commits.
2013-02-14 13:43:13 +01:00
|
|
|
matcher_t matcher;
|
2018-01-10 03:07:30 +01:00
|
|
|
const HBUINT16 *match_glyph_data;
|
[OTLayout] Ignore default-ignorables when matching GSUB/GPOS
When matching lookups, be smart about default-ignorable characters.
In particular:
Do nothing specific about ZWNJ, but for the other default-ignorables:
If the lookup in question uses the ignorable character in a sequence,
then match it as we used to do. However, if the sequence match will
fail because the default-ignorable blocked it, try skipping the
ignorable character and continue.
The most immediate thing it means is that if Lam-Alef forms a ligature,
then Lam-ZWJ-Alef will do to. Finally!
One exception: when matching for GPOS, or for backtrack/lookahead of
GSUB, we ignore ZWNJ too. That's the right thing to do.
It certainly is possible to build fonts that this feature will result
in undesirable glyphs, but it's hard to think of a real-world case
that that would happen.
This *does* break Indic shaping right now, since Indic Unicode has
specific rules for what ZWJ/ZWNJ mean, and skipping ZWJ is breaking
those rules. That will be fixed in upcoming commits.
2013-02-14 13:43:13 +01:00
|
|
|
|
2012-01-17 04:05:08 +01:00
|
|
|
unsigned int num_items;
|
2015-01-29 13:08:41 +01:00
|
|
|
unsigned int end;
|
2012-01-17 04:05:08 +01:00
|
|
|
};
|
|
|
|
|
2015-01-29 13:32:05 +01:00
|
|
|
|
2018-12-17 19:01:01 +01:00
|
|
|
const char *get_name () { return "APPLY"; }
|
2018-01-18 01:46:51 +01:00
|
|
|
typedef return_t (*recurse_func_t) (hb_ot_apply_context_t *c, unsigned int lookup_index);
|
2015-01-29 13:32:05 +01:00
|
|
|
template <typename T>
|
2018-12-16 20:08:10 +01:00
|
|
|
return_t dispatch (const T &obj) { return obj.apply (this); }
|
2018-12-17 19:01:01 +01:00
|
|
|
static return_t default_return_value () { return false; }
|
2015-01-29 13:32:05 +01:00
|
|
|
bool stop_sublookup_iteration (return_t r) const { return r; }
|
2018-01-27 03:14:05 +01:00
|
|
|
return_t recurse (unsigned int sub_lookup_index)
|
2015-01-29 13:32:05 +01:00
|
|
|
{
|
2017-11-15 06:53:48 +01:00
|
|
|
if (unlikely (nesting_level_left == 0 || !recurse_func || buffer->max_ops-- <= 0))
|
2015-01-29 13:32:05 +01:00
|
|
|
return default_return_value ();
|
|
|
|
|
|
|
|
nesting_level_left--;
|
2018-01-27 03:14:05 +01:00
|
|
|
bool ret = recurse_func (this, sub_lookup_index);
|
2015-01-29 13:32:05 +01:00
|
|
|
nesting_level_left++;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-07-14 13:43:34 +02:00
|
|
|
skipping_iterator_t iter_input, iter_context;
|
|
|
|
|
2015-01-29 13:32:05 +01:00
|
|
|
hb_font_t *font;
|
|
|
|
hb_face_t *face;
|
|
|
|
hb_buffer_t *buffer;
|
|
|
|
recurse_func_t recurse_func;
|
|
|
|
const GDEF &gdef;
|
2016-09-10 09:22:24 +02:00
|
|
|
const VariationStore &var_store;
|
2017-07-14 13:43:34 +02:00
|
|
|
|
|
|
|
hb_direction_t direction;
|
|
|
|
hb_mask_t lookup_mask;
|
|
|
|
unsigned int table_index; /* GSUB/GPOS */
|
2015-08-18 15:36:43 +02:00
|
|
|
unsigned int lookup_index;
|
2017-07-14 13:43:34 +02:00
|
|
|
unsigned int lookup_props;
|
|
|
|
unsigned int nesting_level_left;
|
2015-01-29 13:32:05 +01:00
|
|
|
unsigned int debug_depth;
|
|
|
|
|
2018-09-10 16:24:52 +02:00
|
|
|
bool has_glyph_classes;
|
2017-07-14 13:43:34 +02:00
|
|
|
bool auto_zwnj;
|
|
|
|
bool auto_zwj;
|
2018-01-25 20:22:03 +01:00
|
|
|
bool random;
|
2018-09-10 16:24:52 +02:00
|
|
|
|
2018-09-11 10:57:48 +02:00
|
|
|
uint32_t random_state;
|
2017-07-14 13:43:34 +02:00
|
|
|
|
2015-01-29 13:32:05 +01:00
|
|
|
|
2018-01-18 01:46:51 +01:00
|
|
|
hb_ot_apply_context_t (unsigned int table_index_,
|
2015-01-29 13:32:05 +01:00
|
|
|
hb_font_t *font_,
|
|
|
|
hb_buffer_t *buffer_) :
|
2017-07-14 13:43:34 +02:00
|
|
|
iter_input (), iter_context (),
|
2015-01-29 13:32:05 +01:00
|
|
|
font (font_), face (font->face), buffer (buffer_),
|
2017-10-15 12:11:08 +02:00
|
|
|
recurse_func (nullptr),
|
2018-11-06 05:19:04 +01:00
|
|
|
gdef (*face->table.GDEF->table),
|
2016-09-10 02:03:11 +02:00
|
|
|
var_store (gdef.get_var_store ()),
|
2017-07-14 13:43:34 +02:00
|
|
|
direction (buffer_->props.direction),
|
|
|
|
lookup_mask (1),
|
|
|
|
table_index (table_index_),
|
2015-08-18 15:36:43 +02:00
|
|
|
lookup_index ((unsigned int) -1),
|
2017-07-14 13:43:34 +02:00
|
|
|
lookup_props (0),
|
|
|
|
nesting_level_left (HB_MAX_NESTING_LEVEL),
|
|
|
|
debug_depth (0),
|
2018-09-10 16:24:52 +02:00
|
|
|
has_glyph_classes (gdef.has_glyph_classes ()),
|
2017-07-14 13:43:34 +02:00
|
|
|
auto_zwnj (true),
|
|
|
|
auto_zwj (true),
|
2018-01-25 20:22:03 +01:00
|
|
|
random (false),
|
2018-09-25 00:30:50 +02:00
|
|
|
random_state (1) { init_iters (); }
|
2015-01-29 13:32:05 +01:00
|
|
|
|
2018-12-17 19:01:01 +01:00
|
|
|
void init_iters ()
|
2015-01-29 13:59:42 +01:00
|
|
|
{
|
|
|
|
iter_input.init (this, false);
|
|
|
|
iter_context.init (this, true);
|
|
|
|
}
|
2015-01-29 13:32:05 +01:00
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; init_iters (); }
|
|
|
|
void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; init_iters (); }
|
|
|
|
void set_auto_zwnj (bool auto_zwnj_) { auto_zwnj = auto_zwnj_; init_iters (); }
|
|
|
|
void set_random (bool random_) { random = random_; }
|
|
|
|
void set_recurse_func (recurse_func_t func) { recurse_func = func; }
|
|
|
|
void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; }
|
|
|
|
void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; init_iters (); }
|
2018-09-24 04:00:34 +02:00
|
|
|
|
2018-12-17 19:01:01 +01:00
|
|
|
uint32_t random_number ()
|
2018-09-11 10:51:19 +02:00
|
|
|
{
|
2018-09-11 10:57:48 +02:00
|
|
|
/* http://www.cplusplus.com/reference/random/minstd_rand/ */
|
|
|
|
random_state = random_state * 48271 % 2147483647;
|
|
|
|
return random_state;
|
2018-09-11 10:51:19 +02:00
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool match_properties_mark (hb_codepoint_t glyph,
|
|
|
|
unsigned int glyph_props,
|
|
|
|
unsigned int match_props) const
|
2012-07-31 01:47:53 +02:00
|
|
|
{
|
|
|
|
/* If using mark filtering sets, the high short of
|
2015-04-08 23:39:00 +02:00
|
|
|
* match_props has the set index.
|
2012-07-31 01:47:53 +02:00
|
|
|
*/
|
2015-04-08 23:39:00 +02:00
|
|
|
if (match_props & LookupFlag::UseMarkFilteringSet)
|
|
|
|
return gdef.mark_set_covers (match_props >> 16, glyph);
|
2012-07-31 01:47:53 +02:00
|
|
|
|
2015-04-08 23:39:00 +02:00
|
|
|
/* The second byte of match_props has the meaning
|
2012-07-31 01:47:53 +02:00
|
|
|
* "ignore marks of attachment type different than
|
|
|
|
* the attachment type specified."
|
|
|
|
*/
|
2015-04-08 23:39:00 +02:00
|
|
|
if (match_props & LookupFlag::MarkAttachmentType)
|
|
|
|
return (match_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType);
|
2012-07-31 01:47:53 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool check_glyph_property (const hb_glyph_info_t *info,
|
|
|
|
unsigned int match_props) const
|
2012-07-31 01:47:53 +02:00
|
|
|
{
|
2014-07-16 19:44:01 +02:00
|
|
|
hb_codepoint_t glyph = info->codepoint;
|
|
|
|
unsigned int glyph_props = _hb_glyph_info_get_glyph_props (info);
|
|
|
|
|
2012-07-31 01:47:53 +02:00
|
|
|
/* Not covered, if, for example, glyph class is ligature and
|
2015-04-08 23:39:00 +02:00
|
|
|
* match_props includes LookupFlags::IgnoreLigatures
|
2012-07-31 01:47:53 +02:00
|
|
|
*/
|
2015-04-08 23:39:00 +02:00
|
|
|
if (glyph_props & match_props & LookupFlag::IgnoreFlags)
|
2012-07-31 01:47:53 +02:00
|
|
|
return false;
|
|
|
|
|
2012-11-16 22:34:29 +01:00
|
|
|
if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK))
|
2015-04-08 23:39:00 +02:00
|
|
|
return match_properties_mark (glyph, glyph_props, match_props);
|
2012-07-31 01:47:53 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
void _set_glyph_props (hb_codepoint_t glyph_index,
|
2013-10-28 00:20:59 +01:00
|
|
|
unsigned int class_guess = 0,
|
[indic] Don't reorder reph/pref if ligature was expanded
Normally if you want to, say, conditionally prevent a 'pref', you
would use blocking contextual matching. Some designers instead
form the 'pref' form, then undo it in context. To detect that
we now also remember glyphs that went through MultipleSubst.
In the only place that this is used, Uniscribe seems to only care
about the "last" transformation between Ligature and Multiple
substitions. Ie. if you ligate, expand, and ligate again, it
moves the pref, but if you ligate and expand it doesn't. That's
why we clear the MULTIPLIED bit when setting LIGATED.
Micro-test added. Test: U+0D2F,0D4D,0D30 with font from:
[1]
https://code.google.com/a/google.com/p/noto-alpha/issues/detail?id=186#c29
2014-06-04 22:57:42 +02:00
|
|
|
bool ligature = false,
|
|
|
|
bool component = false) const
|
2012-07-16 22:13:32 +02:00
|
|
|
{
|
2013-10-18 01:05:58 +02:00
|
|
|
unsigned int add_in = _hb_glyph_info_get_glyph_props (&buffer->cur()) &
|
|
|
|
HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE;
|
|
|
|
add_in |= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED;
|
|
|
|
if (ligature)
|
[indic] Don't reorder reph/pref if ligature was expanded
Normally if you want to, say, conditionally prevent a 'pref', you
would use blocking contextual matching. Some designers instead
form the 'pref' form, then undo it in context. To detect that
we now also remember glyphs that went through MultipleSubst.
In the only place that this is used, Uniscribe seems to only care
about the "last" transformation between Ligature and Multiple
substitions. Ie. if you ligate, expand, and ligate again, it
moves the pref, but if you ligate and expand it doesn't. That's
why we clear the MULTIPLIED bit when setting LIGATED.
Micro-test added. Test: U+0D2F,0D4D,0D30 with font from:
[1]
https://code.google.com/a/google.com/p/noto-alpha/issues/detail?id=186#c29
2014-06-04 22:57:42 +02:00
|
|
|
{
|
2013-10-18 01:05:58 +02:00
|
|
|
add_in |= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED;
|
[indic] Don't reorder reph/pref if ligature was expanded
Normally if you want to, say, conditionally prevent a 'pref', you
would use blocking contextual matching. Some designers instead
form the 'pref' form, then undo it in context. To detect that
we now also remember glyphs that went through MultipleSubst.
In the only place that this is used, Uniscribe seems to only care
about the "last" transformation between Ligature and Multiple
substitions. Ie. if you ligate, expand, and ligate again, it
moves the pref, but if you ligate and expand it doesn't. That's
why we clear the MULTIPLIED bit when setting LIGATED.
Micro-test added. Test: U+0D2F,0D4D,0D30 with font from:
[1]
https://code.google.com/a/google.com/p/noto-alpha/issues/detail?id=186#c29
2014-06-04 22:57:42 +02:00
|
|
|
/* In the only place that the MULTIPLIED bit is used, Uniscribe
|
|
|
|
* seems to only care about the "last" transformation between
|
2018-10-19 17:49:21 +02:00
|
|
|
* Ligature and Multiple substitutions. Ie. if you ligate, expand,
|
[indic] Don't reorder reph/pref if ligature was expanded
Normally if you want to, say, conditionally prevent a 'pref', you
would use blocking contextual matching. Some designers instead
form the 'pref' form, then undo it in context. To detect that
we now also remember glyphs that went through MultipleSubst.
In the only place that this is used, Uniscribe seems to only care
about the "last" transformation between Ligature and Multiple
substitions. Ie. if you ligate, expand, and ligate again, it
moves the pref, but if you ligate and expand it doesn't. That's
why we clear the MULTIPLIED bit when setting LIGATED.
Micro-test added. Test: U+0D2F,0D4D,0D30 with font from:
[1]
https://code.google.com/a/google.com/p/noto-alpha/issues/detail?id=186#c29
2014-06-04 22:57:42 +02:00
|
|
|
* and ligate again, it forgives the multiplication and acts as
|
|
|
|
* if only ligation happened. As such, clear MULTIPLIED bit.
|
|
|
|
*/
|
|
|
|
add_in &= ~HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
|
|
|
|
}
|
|
|
|
if (component)
|
|
|
|
add_in |= HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
|
2012-07-31 00:46:41 +02:00
|
|
|
if (likely (has_glyph_classes))
|
2013-10-18 00:45:59 +02:00
|
|
|
_hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | gdef.get_glyph_props (glyph_index));
|
2012-07-31 01:30:01 +02:00
|
|
|
else if (class_guess)
|
2013-10-18 01:05:58 +02:00
|
|
|
_hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | class_guess);
|
2012-07-16 22:13:32 +02:00
|
|
|
}
|
2012-01-17 04:05:08 +01:00
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
void replace_glyph (hb_codepoint_t glyph_index) const
|
2012-06-09 03:44:06 +02:00
|
|
|
{
|
2013-10-18 00:06:30 +02:00
|
|
|
_set_glyph_props (glyph_index);
|
|
|
|
buffer->replace_glyph (glyph_index);
|
2012-06-09 03:44:06 +02:00
|
|
|
}
|
2018-12-16 20:08:10 +01:00
|
|
|
void replace_glyph_inplace (hb_codepoint_t glyph_index) const
|
2010-10-27 23:39:01 +02:00
|
|
|
{
|
2013-10-18 00:06:30 +02:00
|
|
|
_set_glyph_props (glyph_index);
|
|
|
|
buffer->cur().codepoint = glyph_index;
|
|
|
|
}
|
2018-12-16 20:08:10 +01:00
|
|
|
void replace_glyph_with_ligature (hb_codepoint_t glyph_index,
|
2013-10-18 00:06:30 +02:00
|
|
|
unsigned int class_guess) const
|
|
|
|
{
|
2013-10-18 01:05:58 +02:00
|
|
|
_set_glyph_props (glyph_index, class_guess, true);
|
2010-10-27 23:39:01 +02:00
|
|
|
buffer->replace_glyph (glyph_index);
|
|
|
|
}
|
2018-12-16 20:08:10 +01:00
|
|
|
void output_glyph_for_component (hb_codepoint_t glyph_index,
|
[indic] Don't reorder reph/pref if ligature was expanded
Normally if you want to, say, conditionally prevent a 'pref', you
would use blocking contextual matching. Some designers instead
form the 'pref' form, then undo it in context. To detect that
we now also remember glyphs that went through MultipleSubst.
In the only place that this is used, Uniscribe seems to only care
about the "last" transformation between Ligature and Multiple
substitions. Ie. if you ligate, expand, and ligate again, it
moves the pref, but if you ligate and expand it doesn't. That's
why we clear the MULTIPLIED bit when setting LIGATED.
Micro-test added. Test: U+0D2F,0D4D,0D30 with font from:
[1]
https://code.google.com/a/google.com/p/noto-alpha/issues/detail?id=186#c29
2014-06-04 22:57:42 +02:00
|
|
|
unsigned int class_guess) const
|
2012-07-31 00:36:42 +02:00
|
|
|
{
|
[indic] Don't reorder reph/pref if ligature was expanded
Normally if you want to, say, conditionally prevent a 'pref', you
would use blocking contextual matching. Some designers instead
form the 'pref' form, then undo it in context. To detect that
we now also remember glyphs that went through MultipleSubst.
In the only place that this is used, Uniscribe seems to only care
about the "last" transformation between Ligature and Multiple
substitions. Ie. if you ligate, expand, and ligate again, it
moves the pref, but if you ligate and expand it doesn't. That's
why we clear the MULTIPLIED bit when setting LIGATED.
Micro-test added. Test: U+0D2F,0D4D,0D30 with font from:
[1]
https://code.google.com/a/google.com/p/noto-alpha/issues/detail?id=186#c29
2014-06-04 22:57:42 +02:00
|
|
|
_set_glyph_props (glyph_index, class_guess, false, true);
|
2013-10-18 00:06:30 +02:00
|
|
|
buffer->output_glyph (glyph_index);
|
2012-07-31 00:36:42 +02:00
|
|
|
}
|
2010-04-29 08:19:21 +02:00
|
|
|
};
|
|
|
|
|
2009-05-17 14:28:42 +02:00
|
|
|
|
2018-10-10 18:07:49 +02:00
|
|
|
struct hb_get_subtables_context_t :
|
|
|
|
hb_dispatch_context_t<hb_get_subtables_context_t, hb_void_t, HB_DEBUG_APPLY>
|
|
|
|
{
|
|
|
|
template <typename Type>
|
2018-12-16 20:08:10 +01:00
|
|
|
static bool apply_to (const void *obj, OT::hb_ot_apply_context_t *c)
|
2018-10-10 18:07:49 +02:00
|
|
|
{
|
|
|
|
const Type *typed_obj = (const Type *) obj;
|
|
|
|
return typed_obj->apply (c);
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef bool (*hb_apply_func_t) (const void *obj, OT::hb_ot_apply_context_t *c);
|
|
|
|
|
|
|
|
struct hb_applicable_t
|
|
|
|
{
|
|
|
|
template <typename T>
|
2018-12-16 20:08:10 +01:00
|
|
|
void init (const T &obj_, hb_apply_func_t apply_func_)
|
2018-10-10 18:07:49 +02:00
|
|
|
{
|
|
|
|
obj = &obj_;
|
|
|
|
apply_func = apply_func_;
|
|
|
|
digest.init ();
|
|
|
|
obj_.get_coverage ().add_coverage (&digest);
|
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool apply (OT::hb_ot_apply_context_t *c) const
|
2018-10-10 18:07:49 +02:00
|
|
|
{
|
|
|
|
return digest.may_have (c->buffer->cur().codepoint) && apply_func (obj, c);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
const void *obj;
|
|
|
|
hb_apply_func_t apply_func;
|
|
|
|
hb_set_digest_t digest;
|
|
|
|
};
|
|
|
|
|
2018-12-27 23:56:22 +01:00
|
|
|
typedef hb_vector_t<hb_applicable_t> array_t;
|
2018-10-10 18:07:49 +02:00
|
|
|
|
|
|
|
/* Dispatch interface. */
|
2018-12-17 19:01:01 +01:00
|
|
|
const char *get_name () { return "GET_SUBTABLES"; }
|
2018-10-10 18:07:49 +02:00
|
|
|
template <typename T>
|
2018-12-16 20:08:10 +01:00
|
|
|
return_t dispatch (const T &obj)
|
2018-10-10 18:07:49 +02:00
|
|
|
{
|
|
|
|
hb_applicable_t *entry = array.push();
|
|
|
|
entry->init (obj, apply_to<T>);
|
2018-12-27 15:56:41 +01:00
|
|
|
return hb_void_t ();
|
2018-10-10 18:07:49 +02:00
|
|
|
}
|
2018-12-27 15:56:41 +01:00
|
|
|
static return_t default_return_value () { return hb_void_t (); }
|
2018-10-10 18:07:49 +02:00
|
|
|
|
|
|
|
hb_get_subtables_context_t (array_t &array_) :
|
|
|
|
array (array_),
|
|
|
|
debug_depth (0) {}
|
|
|
|
|
|
|
|
array_t &array;
|
|
|
|
unsigned int debug_depth;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
2010-05-05 07:13:09 +02:00
|
|
|
|
2018-09-03 04:47:50 +02:00
|
|
|
typedef bool (*intersects_func_t) (const hb_set_t *glyphs, const HBUINT16 &value, const void *data);
|
2018-01-10 03:07:30 +01:00
|
|
|
typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const HBUINT16 &value, const void *data);
|
|
|
|
typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data);
|
2009-05-17 14:28:42 +02:00
|
|
|
|
2012-04-23 22:54:58 +02:00
|
|
|
struct ContextClosureFuncs
|
|
|
|
{
|
|
|
|
intersects_func_t intersects;
|
|
|
|
};
|
2012-11-24 00:54:59 +01:00
|
|
|
struct ContextCollectGlyphsFuncs
|
|
|
|
{
|
|
|
|
collect_glyphs_func_t collect;
|
|
|
|
};
|
2012-04-23 22:54:58 +02:00
|
|
|
struct ContextApplyFuncs
|
2009-05-20 05:58:54 +02:00
|
|
|
{
|
2009-05-18 04:11:30 +02:00
|
|
|
match_func_t match;
|
2009-05-17 14:28:42 +02:00
|
|
|
};
|
|
|
|
|
2012-11-24 00:54:59 +01:00
|
|
|
|
2018-09-03 04:47:50 +02:00
|
|
|
static inline bool intersects_glyph (const hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
|
2012-04-23 22:54:58 +02:00
|
|
|
{
|
|
|
|
return glyphs->has (value);
|
|
|
|
}
|
2018-09-03 04:47:50 +02:00
|
|
|
static inline bool intersects_class (const hb_set_t *glyphs, const HBUINT16 &value, const void *data)
|
2012-04-23 22:54:58 +02:00
|
|
|
{
|
|
|
|
const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
|
|
|
|
return class_def.intersects_class (glyphs, value);
|
|
|
|
}
|
2018-09-03 04:47:50 +02:00
|
|
|
static inline bool intersects_coverage (const hb_set_t *glyphs, const HBUINT16 &value, const void *data)
|
2012-04-23 22:54:58 +02:00
|
|
|
{
|
|
|
|
const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
|
|
|
|
return (data+coverage).intersects (glyphs);
|
|
|
|
}
|
|
|
|
|
2018-09-03 04:47:50 +02:00
|
|
|
static inline bool intersects_array (const hb_set_t *glyphs,
|
2012-04-23 22:54:58 +02:00
|
|
|
unsigned int count,
|
2018-01-10 03:07:30 +01:00
|
|
|
const HBUINT16 values[],
|
2012-04-23 22:54:58 +02:00
|
|
|
intersects_func_t intersects_func,
|
|
|
|
const void *intersects_data)
|
|
|
|
{
|
2019-02-15 00:43:20 +01:00
|
|
|
for (auto it = hb_iter (values, count); it; ++it)
|
|
|
|
if (likely (!intersects_func (glyphs, *it, intersects_data)))
|
2012-04-23 22:54:58 +02:00
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-05-18 08:36:18 +02:00
|
|
|
|
2018-01-10 03:07:30 +01:00
|
|
|
static inline void collect_glyph (hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
|
2012-11-24 00:54:59 +01:00
|
|
|
{
|
|
|
|
glyphs->add (value);
|
|
|
|
}
|
2018-01-10 03:07:30 +01:00
|
|
|
static inline void collect_class (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
|
2012-11-24 00:54:59 +01:00
|
|
|
{
|
|
|
|
const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
|
2017-12-16 17:07:37 +01:00
|
|
|
class_def.add_class (glyphs, value);
|
2012-11-24 00:54:59 +01:00
|
|
|
}
|
2018-01-10 03:07:30 +01:00
|
|
|
static inline void collect_coverage (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
|
2012-11-24 00:54:59 +01:00
|
|
|
{
|
|
|
|
const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
|
|
|
|
(data+coverage).add_coverage (glyphs);
|
|
|
|
}
|
2012-12-06 00:46:04 +01:00
|
|
|
static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED,
|
2012-11-24 07:55:34 +01:00
|
|
|
hb_set_t *glyphs,
|
2012-11-24 00:54:59 +01:00
|
|
|
unsigned int count,
|
2018-01-10 03:07:30 +01:00
|
|
|
const HBUINT16 values[],
|
2012-11-24 00:54:59 +01:00
|
|
|
collect_glyphs_func_t collect_func,
|
|
|
|
const void *collect_data)
|
|
|
|
{
|
2019-02-15 00:43:20 +01:00
|
|
|
for (auto it = hb_iter (values, count); it; ++it)
|
|
|
|
collect_func (glyphs, *it, collect_data);
|
2012-11-24 00:54:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-01-10 03:07:30 +01:00
|
|
|
static inline bool match_glyph (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data HB_UNUSED)
|
2009-05-20 05:58:54 +02:00
|
|
|
{
|
2009-05-18 04:11:30 +02:00
|
|
|
return glyph_id == value;
|
|
|
|
}
|
2018-01-10 03:07:30 +01:00
|
|
|
static inline bool match_class (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data)
|
2009-05-20 05:58:54 +02:00
|
|
|
{
|
2009-08-04 17:38:50 +02:00
|
|
|
const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
|
2009-05-18 04:11:30 +02:00
|
|
|
return class_def.get_class (glyph_id) == value;
|
|
|
|
}
|
2018-01-10 03:07:30 +01:00
|
|
|
static inline bool match_coverage (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data)
|
2009-05-20 05:58:54 +02:00
|
|
|
{
|
2009-05-19 00:30:25 +02:00
|
|
|
const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
|
2012-04-23 22:54:58 +02:00
|
|
|
return (data+coverage).get_coverage (glyph_id) != NOT_COVERED;
|
2009-05-18 04:11:30 +02:00
|
|
|
}
|
|
|
|
|
2012-07-19 20:35:23 +02:00
|
|
|
static inline bool would_match_input (hb_would_apply_context_t *c,
|
|
|
|
unsigned int count, /* Including the first glyph (not matched) */
|
2018-01-10 03:07:30 +01:00
|
|
|
const HBUINT16 input[], /* Array of input values--start with second glyph */
|
2012-07-19 20:35:23 +02:00
|
|
|
match_func_t match_func,
|
|
|
|
const void *match_data)
|
|
|
|
{
|
|
|
|
if (count != c->len)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
for (unsigned int i = 1; i < count; i++)
|
2012-08-08 04:25:24 +02:00
|
|
|
if (likely (!match_func (c->glyphs[i], input[i - 1], match_data)))
|
2012-07-19 20:35:23 +02:00
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2018-01-18 01:46:51 +01:00
|
|
|
static inline bool match_input (hb_ot_apply_context_t *c,
|
2009-05-18 09:56:39 +02:00
|
|
|
unsigned int count, /* Including the first glyph (not matched) */
|
2018-01-10 03:07:30 +01:00
|
|
|
const HBUINT16 input[], /* Array of input values--start with second glyph */
|
2009-05-18 09:56:39 +02:00
|
|
|
match_func_t match_func,
|
2010-05-10 23:47:22 +02:00
|
|
|
const void *match_data,
|
2013-10-17 13:55:48 +02:00
|
|
|
unsigned int *end_offset,
|
2015-11-03 00:43:08 +01:00
|
|
|
unsigned int match_positions[HB_MAX_CONTEXT_LENGTH],
|
2017-10-15 12:11:08 +02:00
|
|
|
unsigned int *p_total_component_count = nullptr)
|
2009-05-18 09:56:39 +02:00
|
|
|
{
|
2017-10-15 12:11:08 +02:00
|
|
|
TRACE_APPLY (nullptr);
|
2012-08-29 04:24:51 +02:00
|
|
|
|
2015-11-03 00:43:08 +01:00
|
|
|
if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return_trace (false);
|
2013-10-14 18:51:39 +02:00
|
|
|
|
2013-10-17 13:58:31 +02:00
|
|
|
hb_buffer_t *buffer = c->buffer;
|
|
|
|
|
2018-01-18 01:46:51 +01:00
|
|
|
hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
|
2015-01-29 13:40:39 +01:00
|
|
|
skippy_iter.reset (buffer->idx, count - 1);
|
[OTLayout] Ignore default-ignorables when matching GSUB/GPOS
When matching lookups, be smart about default-ignorable characters.
In particular:
Do nothing specific about ZWNJ, but for the other default-ignorables:
If the lookup in question uses the ignorable character in a sequence,
then match it as we used to do. However, if the sequence match will
fail because the default-ignorable blocked it, try skipping the
ignorable character and continue.
The most immediate thing it means is that if Lam-Alef forms a ligature,
then Lam-ZWJ-Alef will do to. Finally!
One exception: when matching for GPOS, or for backtrack/lookahead of
GSUB, we ignore ZWNJ too. That's the right thing to do.
It certainly is possible to build fonts that this feature will result
in undesirable glyphs, but it's hard to think of a real-world case
that that would happen.
This *does* break Indic shaping right now, since Indic Unicode has
specific rules for what ZWJ/ZWNJ mean, and skipping ZWJ is breaking
those rules. That will be fixed in upcoming commits.
2013-02-14 13:43:13 +01:00
|
|
|
skippy_iter.set_match_func (match_func, match_data, input);
|
2012-08-29 04:24:51 +02:00
|
|
|
|
2012-08-29 04:58:55 +02:00
|
|
|
/*
|
|
|
|
* This is perhaps the trickiest part of OpenType... Remarks:
|
|
|
|
*
|
|
|
|
* - If all components of the ligature were marks, we call this a mark ligature.
|
|
|
|
*
|
|
|
|
* - If there is no GDEF, and the ligature is NOT a mark ligature, we categorize
|
|
|
|
* it as a ligature glyph.
|
|
|
|
*
|
|
|
|
* - Ligatures cannot be formed across glyphs attached to different components
|
|
|
|
* of previous ligatures. Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and
|
|
|
|
* LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother.
|
2017-10-02 20:02:45 +02:00
|
|
|
* However, it would be wrong to ligate that SHADDA,FATHA sequence.
|
|
|
|
* There are a couple of exceptions to this:
|
|
|
|
*
|
|
|
|
* o If a ligature tries ligating with marks that belong to it itself, go ahead,
|
|
|
|
* assuming that the font designer knows what they are doing (otherwise it can
|
|
|
|
* break Indic stuff when a matra wants to ligate with a conjunct,
|
|
|
|
*
|
|
|
|
* o If two marks want to ligate and they belong to different components of the
|
|
|
|
* same ligature glyph, and said ligature glyph is to be ignored according to
|
|
|
|
* mark-filtering rules, then allow.
|
2017-11-20 20:49:22 +01:00
|
|
|
* https://github.com/harfbuzz/harfbuzz/issues/545
|
2012-08-29 04:58:55 +02:00
|
|
|
*/
|
|
|
|
|
2012-08-29 04:24:51 +02:00
|
|
|
unsigned int total_component_count = 0;
|
2013-10-18 00:02:43 +02:00
|
|
|
total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur());
|
2012-08-29 04:24:51 +02:00
|
|
|
|
2013-10-18 00:02:43 +02:00
|
|
|
unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
|
|
|
|
unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
|
2009-05-18 09:56:39 +02:00
|
|
|
|
2017-10-04 15:06:48 +02:00
|
|
|
enum {
|
|
|
|
LIGBASE_NOT_CHECKED,
|
|
|
|
LIGBASE_MAY_NOT_SKIP,
|
|
|
|
LIGBASE_MAY_SKIP
|
|
|
|
} ligbase = LIGBASE_NOT_CHECKED;
|
|
|
|
|
2013-10-17 13:58:31 +02:00
|
|
|
match_positions[0] = buffer->idx;
|
2012-01-16 23:03:55 +01:00
|
|
|
for (unsigned int i = 1; i < count; i++)
|
2009-05-20 05:58:54 +02:00
|
|
|
{
|
2015-09-29 15:57:02 +02:00
|
|
|
if (!skippy_iter.next ()) return_trace (false);
|
2013-10-17 13:55:48 +02:00
|
|
|
|
|
|
|
match_positions[i] = skippy_iter.idx;
|
2012-08-29 04:24:51 +02:00
|
|
|
|
2013-10-18 00:02:43 +02:00
|
|
|
unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]);
|
|
|
|
unsigned int this_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]);
|
2012-08-29 04:24:51 +02:00
|
|
|
|
2017-10-02 20:02:45 +02:00
|
|
|
if (first_lig_id && first_lig_comp)
|
|
|
|
{
|
2012-08-29 04:24:51 +02:00
|
|
|
/* If first component was attached to a previous ligature component,
|
|
|
|
* all subsequent components should be attached to the same ligature
|
2017-10-02 20:02:45 +02:00
|
|
|
* component, otherwise we shouldn't ligate them... */
|
2012-08-29 04:24:51 +02:00
|
|
|
if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp)
|
2017-10-02 20:02:45 +02:00
|
|
|
{
|
2018-11-15 20:40:56 +01:00
|
|
|
/* ...unless, we are attached to a base ligature and that base
|
2017-10-02 20:02:45 +02:00
|
|
|
* ligature is ignorable. */
|
2018-11-15 20:40:56 +01:00
|
|
|
if (ligbase == LIGBASE_NOT_CHECKED)
|
2017-10-02 20:02:45 +02:00
|
|
|
{
|
2017-10-04 15:06:48 +02:00
|
|
|
bool found = false;
|
|
|
|
const hb_glyph_info_t *out = buffer->out_info;
|
|
|
|
unsigned int j = buffer->out_len;
|
|
|
|
while (j && _hb_glyph_info_get_lig_id (&out[j - 1]) == first_lig_id)
|
2017-10-02 20:02:45 +02:00
|
|
|
{
|
2017-10-04 15:06:48 +02:00
|
|
|
if (_hb_glyph_info_get_lig_comp (&out[j - 1]) == 0)
|
|
|
|
{
|
|
|
|
j--;
|
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
2017-10-02 20:02:45 +02:00
|
|
|
j--;
|
|
|
|
}
|
|
|
|
|
2018-01-27 03:14:05 +01:00
|
|
|
if (found && skippy_iter.may_skip (out[j]) == hb_ot_apply_context_t::matcher_t::SKIP_YES)
|
2017-10-04 15:06:48 +02:00
|
|
|
ligbase = LIGBASE_MAY_SKIP;
|
|
|
|
else
|
|
|
|
ligbase = LIGBASE_MAY_NOT_SKIP;
|
|
|
|
}
|
2017-10-02 20:02:45 +02:00
|
|
|
|
2018-11-15 20:40:56 +01:00
|
|
|
if (ligbase == LIGBASE_MAY_NOT_SKIP)
|
2017-10-02 20:02:45 +02:00
|
|
|
return_trace (false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2017-10-04 15:06:48 +02:00
|
|
|
{
|
2012-08-29 04:24:51 +02:00
|
|
|
/* If first component was NOT attached to a previous ligature component,
|
|
|
|
* all subsequent components should also NOT be attached to any ligature
|
|
|
|
* component, unless they are attached to the first component itself! */
|
|
|
|
if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id))
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (false);
|
2012-08-29 04:24:51 +02:00
|
|
|
}
|
|
|
|
|
2013-10-18 00:02:43 +02:00
|
|
|
total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->info[skippy_iter.idx]);
|
2009-05-18 09:56:39 +02:00
|
|
|
}
|
|
|
|
|
2013-10-17 13:58:31 +02:00
|
|
|
*end_offset = skippy_iter.idx - buffer->idx + 1;
|
2009-05-18 09:56:39 +02:00
|
|
|
|
2012-08-29 04:58:55 +02:00
|
|
|
if (p_total_component_count)
|
|
|
|
*p_total_component_count = total_component_count;
|
|
|
|
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (true);
|
2009-05-18 09:56:39 +02:00
|
|
|
}
|
2018-01-18 01:46:51 +01:00
|
|
|
static inline bool ligate_input (hb_ot_apply_context_t *c,
|
2013-10-17 13:49:51 +02:00
|
|
|
unsigned int count, /* Including the first glyph */
|
2018-10-20 03:09:52 +02:00
|
|
|
const unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
|
2013-10-17 13:49:51 +02:00
|
|
|
unsigned int match_length,
|
2012-08-29 05:18:22 +02:00
|
|
|
hb_codepoint_t lig_glyph,
|
|
|
|
unsigned int total_component_count)
|
|
|
|
{
|
2017-10-15 12:11:08 +02:00
|
|
|
TRACE_APPLY (nullptr);
|
2013-10-17 13:49:51 +02:00
|
|
|
|
2013-10-17 13:58:31 +02:00
|
|
|
hb_buffer_t *buffer = c->buffer;
|
|
|
|
|
|
|
|
buffer->merge_clusters (buffer->idx, buffer->idx + match_length);
|
[OTLayout] Ignore default-ignorables when matching GSUB/GPOS
When matching lookups, be smart about default-ignorable characters.
In particular:
Do nothing specific about ZWNJ, but for the other default-ignorables:
If the lookup in question uses the ignorable character in a sequence,
then match it as we used to do. However, if the sequence match will
fail because the default-ignorable blocked it, try skipping the
ignorable character and continue.
The most immediate thing it means is that if Lam-Alef forms a ligature,
then Lam-ZWJ-Alef will do to. Finally!
One exception: when matching for GPOS, or for backtrack/lookahead of
GSUB, we ignore ZWNJ too. That's the right thing to do.
It certainly is possible to build fonts that this feature will result
in undesirable glyphs, but it's hard to think of a real-world case
that that would happen.
This *does* break Indic shaping right now, since Indic Unicode has
specific rules for what ZWJ/ZWNJ mean, and skipping ZWJ is breaking
those rules. That will be fixed in upcoming commits.
2013-02-14 13:43:13 +01:00
|
|
|
|
2018-10-02 16:05:26 +02:00
|
|
|
/* - If a base and one or more marks ligate, consider that as a base, NOT
|
|
|
|
* ligature, such that all following marks can still attach to it.
|
|
|
|
* https://github.com/harfbuzz/harfbuzz/issues/1109
|
|
|
|
*
|
|
|
|
* - If all components of the ligature were marks, we call this a mark ligature.
|
2018-10-02 15:02:16 +02:00
|
|
|
* If it *is* a mark ligature, we don't allocate a new ligature id, and leave
|
2012-08-29 05:18:22 +02:00
|
|
|
* the ligature to keep its old ligature id. This will allow it to attach to
|
|
|
|
* a base ligature in GPOS. Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH,
|
2018-10-02 15:02:16 +02:00
|
|
|
* and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA with a
|
2012-08-29 05:18:22 +02:00
|
|
|
* ligature id and component value of 2. Then if SHADDA,FATHA form a ligature
|
|
|
|
* later, we don't want them to lose their ligature id/component, otherwise
|
|
|
|
* GPOS will fail to correctly position the mark ligature on top of the
|
|
|
|
* LAM,LAM,HEH ligature. See:
|
|
|
|
* https://bugzilla.gnome.org/show_bug.cgi?id=676343
|
|
|
|
*
|
|
|
|
* - If a ligature is formed of components that some of which are also ligatures
|
|
|
|
* themselves, and those ligature components had marks attached to *their*
|
|
|
|
* components, we have to attach the marks to the new ligature component
|
|
|
|
* positions! Now *that*'s tricky! And these marks may be following the
|
|
|
|
* last component of the whole sequence, so we should loop forward looking
|
|
|
|
* for them and update them.
|
|
|
|
*
|
|
|
|
* Eg. the sequence is LAM,LAM,SHADDA,FATHA,HEH, and the font first forms a
|
|
|
|
* 'calt' ligature of LAM,HEH, leaving the SHADDA and FATHA with a ligature
|
|
|
|
* id and component == 1. Now, during 'liga', the LAM and the LAM-HEH ligature
|
|
|
|
* form a LAM-LAM-HEH ligature. We need to reassign the SHADDA and FATHA to
|
|
|
|
* the new ligature with a component value of 2.
|
|
|
|
*
|
|
|
|
* This in fact happened to a font... See:
|
|
|
|
* https://bugzilla.gnome.org/show_bug.cgi?id=437633
|
|
|
|
*/
|
|
|
|
|
2018-10-02 16:05:26 +02:00
|
|
|
bool is_base_ligature = _hb_glyph_info_is_base_glyph (&buffer->info[match_positions[0]]);
|
|
|
|
bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->info[match_positions[0]]);
|
|
|
|
for (unsigned int i = 1; i < count; i++)
|
2018-10-02 15:02:16 +02:00
|
|
|
if (!_hb_glyph_info_is_mark (&buffer->info[match_positions[i]]))
|
|
|
|
{
|
2018-10-02 16:05:26 +02:00
|
|
|
is_base_ligature = false;
|
2018-10-02 15:02:16 +02:00
|
|
|
is_mark_ligature = false;
|
|
|
|
break;
|
|
|
|
}
|
2018-10-02 16:05:26 +02:00
|
|
|
bool is_ligature = !is_base_ligature && !is_mark_ligature;
|
2018-10-02 15:02:16 +02:00
|
|
|
|
2018-10-02 16:05:26 +02:00
|
|
|
unsigned int klass = is_ligature ? HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE : 0;
|
|
|
|
unsigned int lig_id = is_ligature ? _hb_allocate_lig_id (buffer) : 0;
|
2013-10-18 00:02:43 +02:00
|
|
|
unsigned int last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
|
|
|
|
unsigned int last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
|
2012-08-29 05:18:22 +02:00
|
|
|
unsigned int components_so_far = last_num_components;
|
|
|
|
|
2018-10-02 16:05:26 +02:00
|
|
|
if (is_ligature)
|
2013-05-27 20:48:34 +02:00
|
|
|
{
|
2013-10-18 00:02:43 +02:00
|
|
|
_hb_glyph_info_set_lig_props_for_ligature (&buffer->cur(), lig_id, total_component_count);
|
2013-10-17 13:58:31 +02:00
|
|
|
if (_hb_glyph_info_get_general_category (&buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
|
2013-10-28 21:00:37 +01:00
|
|
|
{
|
2015-11-03 02:44:05 +01:00
|
|
|
_hb_glyph_info_set_general_category (&buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER);
|
2013-10-28 21:00:37 +01:00
|
|
|
}
|
2013-05-27 20:48:34 +02:00
|
|
|
}
|
2013-10-18 00:06:30 +02:00
|
|
|
c->replace_glyph_with_ligature (lig_glyph, klass);
|
2012-08-29 05:18:22 +02:00
|
|
|
|
|
|
|
for (unsigned int i = 1; i < count; i++)
|
|
|
|
{
|
2018-06-01 05:03:00 +02:00
|
|
|
while (buffer->idx < match_positions[i] && buffer->successful)
|
2012-08-29 05:18:22 +02:00
|
|
|
{
|
2018-10-02 16:05:26 +02:00
|
|
|
if (is_ligature)
|
|
|
|
{
|
2018-11-15 20:40:56 +01:00
|
|
|
unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
|
2015-12-17 16:21:14 +01:00
|
|
|
if (this_comp == 0)
|
2015-12-17 16:23:09 +01:00
|
|
|
this_comp = last_num_components;
|
2012-08-29 05:18:22 +02:00
|
|
|
unsigned int new_lig_comp = components_so_far - last_num_components +
|
2015-12-17 16:21:14 +01:00
|
|
|
MIN (this_comp, last_num_components);
|
|
|
|
_hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp);
|
2012-08-29 05:18:22 +02:00
|
|
|
}
|
2013-10-17 13:58:31 +02:00
|
|
|
buffer->next_glyph ();
|
2012-08-29 05:18:22 +02:00
|
|
|
}
|
|
|
|
|
2013-10-18 00:02:43 +02:00
|
|
|
last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
|
|
|
|
last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
|
2012-08-29 05:18:22 +02:00
|
|
|
components_so_far += last_num_components;
|
|
|
|
|
|
|
|
/* Skip the base glyph */
|
2013-10-17 13:58:31 +02:00
|
|
|
buffer->idx++;
|
2012-08-29 05:18:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!is_mark_ligature && last_lig_id) {
|
|
|
|
/* Re-adjust components for any marks following. */
|
2013-10-17 13:58:31 +02:00
|
|
|
for (unsigned int i = buffer->idx; i < buffer->len; i++) {
|
2013-10-18 00:02:43 +02:00
|
|
|
if (last_lig_id == _hb_glyph_info_get_lig_id (&buffer->info[i])) {
|
2018-11-15 20:40:56 +01:00
|
|
|
unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->info[i]);
|
2015-12-17 16:21:14 +01:00
|
|
|
if (!this_comp)
|
|
|
|
break;
|
2012-08-29 05:18:22 +02:00
|
|
|
unsigned int new_lig_comp = components_so_far - last_num_components +
|
2015-12-17 16:21:14 +01:00
|
|
|
MIN (this_comp, last_num_components);
|
2013-10-18 00:02:43 +02:00
|
|
|
_hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp);
|
2012-08-29 05:18:22 +02:00
|
|
|
} else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (true);
|
2012-08-29 05:18:22 +02:00
|
|
|
}
|
2009-05-18 09:56:39 +02:00
|
|
|
|
2018-01-18 01:46:51 +01:00
|
|
|
static inline bool match_backtrack (hb_ot_apply_context_t *c,
|
2009-05-18 09:47:31 +02:00
|
|
|
unsigned int count,
|
2018-01-10 03:07:30 +01:00
|
|
|
const HBUINT16 backtrack[],
|
2009-05-18 09:47:31 +02:00
|
|
|
match_func_t match_func,
|
2016-05-02 14:47:45 +02:00
|
|
|
const void *match_data,
|
|
|
|
unsigned int *match_start)
|
2009-05-18 09:47:31 +02:00
|
|
|
{
|
2017-10-15 12:11:08 +02:00
|
|
|
TRACE_APPLY (nullptr);
|
2012-08-29 04:24:51 +02:00
|
|
|
|
2018-01-18 01:46:51 +01:00
|
|
|
hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
|
2015-01-29 13:40:39 +01:00
|
|
|
skippy_iter.reset (c->buffer->backtrack_len (), count);
|
[OTLayout] Ignore default-ignorables when matching GSUB/GPOS
When matching lookups, be smart about default-ignorable characters.
In particular:
Do nothing specific about ZWNJ, but for the other default-ignorables:
If the lookup in question uses the ignorable character in a sequence,
then match it as we used to do. However, if the sequence match will
fail because the default-ignorable blocked it, try skipping the
ignorable character and continue.
The most immediate thing it means is that if Lam-Alef forms a ligature,
then Lam-ZWJ-Alef will do to. Finally!
One exception: when matching for GPOS, or for backtrack/lookahead of
GSUB, we ignore ZWNJ too. That's the right thing to do.
It certainly is possible to build fonts that this feature will result
in undesirable glyphs, but it's hard to think of a real-world case
that that would happen.
This *does* break Indic shaping right now, since Indic Unicode has
specific rules for what ZWJ/ZWNJ mean, and skipping ZWJ is breaking
those rules. That will be fixed in upcoming commits.
2013-02-14 13:43:13 +01:00
|
|
|
skippy_iter.set_match_func (match_func, match_data, backtrack);
|
2009-05-18 09:47:31 +02:00
|
|
|
|
2012-01-16 22:43:26 +01:00
|
|
|
for (unsigned int i = 0; i < count; i++)
|
2012-01-17 04:05:08 +01:00
|
|
|
if (!skippy_iter.prev ())
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (false);
|
2009-05-18 09:47:31 +02:00
|
|
|
|
2016-05-02 14:47:45 +02:00
|
|
|
*match_start = skippy_iter.idx;
|
|
|
|
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (true);
|
2009-05-18 09:47:31 +02:00
|
|
|
}
|
|
|
|
|
2018-01-18 01:46:51 +01:00
|
|
|
static inline bool match_lookahead (hb_ot_apply_context_t *c,
|
2009-05-18 09:56:39 +02:00
|
|
|
unsigned int count,
|
2018-01-10 03:07:30 +01:00
|
|
|
const HBUINT16 lookahead[],
|
2009-05-18 09:56:39 +02:00
|
|
|
match_func_t match_func,
|
2010-05-10 23:47:22 +02:00
|
|
|
const void *match_data,
|
2016-05-02 14:47:45 +02:00
|
|
|
unsigned int offset,
|
|
|
|
unsigned int *end_index)
|
2009-05-18 08:36:18 +02:00
|
|
|
{
|
2017-10-15 12:11:08 +02:00
|
|
|
TRACE_APPLY (nullptr);
|
2012-08-29 04:24:51 +02:00
|
|
|
|
2018-01-18 01:46:51 +01:00
|
|
|
hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
|
2015-01-29 13:40:39 +01:00
|
|
|
skippy_iter.reset (c->buffer->idx + offset - 1, count);
|
[OTLayout] Ignore default-ignorables when matching GSUB/GPOS
When matching lookups, be smart about default-ignorable characters.
In particular:
Do nothing specific about ZWNJ, but for the other default-ignorables:
If the lookup in question uses the ignorable character in a sequence,
then match it as we used to do. However, if the sequence match will
fail because the default-ignorable blocked it, try skipping the
ignorable character and continue.
The most immediate thing it means is that if Lam-Alef forms a ligature,
then Lam-ZWJ-Alef will do to. Finally!
One exception: when matching for GPOS, or for backtrack/lookahead of
GSUB, we ignore ZWNJ too. That's the right thing to do.
It certainly is possible to build fonts that this feature will result
in undesirable glyphs, but it's hard to think of a real-world case
that that would happen.
This *does* break Indic shaping right now, since Indic Unicode has
specific rules for what ZWJ/ZWNJ mean, and skipping ZWJ is breaking
those rules. That will be fixed in upcoming commits.
2013-02-14 13:43:13 +01:00
|
|
|
skippy_iter.set_match_func (match_func, match_data, lookahead);
|
2009-05-17 14:28:42 +02:00
|
|
|
|
2012-01-16 23:03:55 +01:00
|
|
|
for (unsigned int i = 0; i < count; i++)
|
2012-01-17 04:05:08 +01:00
|
|
|
if (!skippy_iter.next ())
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (false);
|
2009-05-17 14:28:42 +02:00
|
|
|
|
2016-05-02 14:47:45 +02:00
|
|
|
*end_index = skippy_iter.idx + 1;
|
|
|
|
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (true);
|
2009-05-18 08:36:18 +02:00
|
|
|
}
|
|
|
|
|
2010-07-23 21:11:18 +02:00
|
|
|
|
2009-05-18 08:36:18 +02:00
|
|
|
|
2009-05-20 05:58:54 +02:00
|
|
|
struct LookupRecord
|
|
|
|
{
|
2018-12-16 20:08:10 +01:00
|
|
|
bool sanitize (hb_sanitize_context_t *c) const
|
2015-02-17 15:27:44 +01:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_SANITIZE (this);
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (c->check_struct (this));
|
2009-08-04 08:09:34 +02:00
|
|
|
}
|
|
|
|
|
2018-01-10 03:07:30 +01:00
|
|
|
HBUINT16 sequenceIndex; /* Index into current glyph
|
2009-05-18 08:36:18 +02:00
|
|
|
* sequence--first glyph = 0 */
|
2018-01-10 03:07:30 +01:00
|
|
|
HBUINT16 lookupListIndex; /* Lookup to apply to that
|
2009-05-18 08:36:18 +02:00
|
|
|
* position--zero--based */
|
2010-05-10 22:38:32 +02:00
|
|
|
public:
|
|
|
|
DEFINE_SIZE_STATIC (4);
|
2009-05-18 08:36:18 +02:00
|
|
|
};
|
|
|
|
|
2012-11-24 00:54:59 +01:00
|
|
|
template <typename context_t>
|
|
|
|
static inline void recurse_lookups (context_t *c,
|
|
|
|
unsigned int lookupCount,
|
|
|
|
const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
|
2012-04-23 22:54:58 +02:00
|
|
|
{
|
|
|
|
for (unsigned int i = 0; i < lookupCount; i++)
|
2013-07-23 01:07:53 +02:00
|
|
|
c->recurse (lookupRecord[i].lookupListIndex);
|
2012-04-23 22:54:58 +02:00
|
|
|
}
|
2010-07-23 21:11:18 +02:00
|
|
|
|
2018-01-18 01:46:51 +01:00
|
|
|
static inline bool apply_lookup (hb_ot_apply_context_t *c,
|
2009-05-18 09:47:31 +02:00
|
|
|
unsigned int count, /* Including the first glyph */
|
2015-11-03 00:43:08 +01:00
|
|
|
unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
|
2009-05-18 09:47:31 +02:00
|
|
|
unsigned int lookupCount,
|
2013-10-14 18:51:39 +02:00
|
|
|
const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
|
|
|
|
unsigned int match_length)
|
2009-05-18 08:36:18 +02:00
|
|
|
{
|
2017-10-15 12:11:08 +02:00
|
|
|
TRACE_APPLY (nullptr);
|
2012-11-23 21:06:59 +01:00
|
|
|
|
2013-10-14 18:51:39 +02:00
|
|
|
hb_buffer_t *buffer = c->buffer;
|
2017-02-17 04:03:24 +01:00
|
|
|
int end;
|
2009-09-21 19:58:56 +02:00
|
|
|
|
2013-10-14 18:51:39 +02:00
|
|
|
/* All positions are distance from beginning of *output* buffer.
|
|
|
|
* Adjust. */
|
|
|
|
{
|
|
|
|
unsigned int bl = buffer->backtrack_len ();
|
|
|
|
end = bl + match_length;
|
[OTLayout] Ignore default-ignorables when matching GSUB/GPOS
When matching lookups, be smart about default-ignorable characters.
In particular:
Do nothing specific about ZWNJ, but for the other default-ignorables:
If the lookup in question uses the ignorable character in a sequence,
then match it as we used to do. However, if the sequence match will
fail because the default-ignorable blocked it, try skipping the
ignorable character and continue.
The most immediate thing it means is that if Lam-Alef forms a ligature,
then Lam-ZWJ-Alef will do to. Finally!
One exception: when matching for GPOS, or for backtrack/lookahead of
GSUB, we ignore ZWNJ too. That's the right thing to do.
It certainly is possible to build fonts that this feature will result
in undesirable glyphs, but it's hard to think of a real-world case
that that would happen.
This *does* break Indic shaping right now, since Indic Unicode has
specific rules for what ZWJ/ZWNJ mean, and skipping ZWJ is breaking
those rules. That will be fixed in upcoming commits.
2013-02-14 13:43:13 +01:00
|
|
|
|
2013-10-14 18:51:39 +02:00
|
|
|
int delta = bl - buffer->idx;
|
|
|
|
/* Convert positions to new indexing. */
|
|
|
|
for (unsigned int j = 0; j < count; j++)
|
|
|
|
match_positions[j] += delta;
|
|
|
|
}
|
[OTLayout] Ignore default-ignorables when matching GSUB/GPOS
When matching lookups, be smart about default-ignorable characters.
In particular:
Do nothing specific about ZWNJ, but for the other default-ignorables:
If the lookup in question uses the ignorable character in a sequence,
then match it as we used to do. However, if the sequence match will
fail because the default-ignorable blocked it, try skipping the
ignorable character and continue.
The most immediate thing it means is that if Lam-Alef forms a ligature,
then Lam-ZWJ-Alef will do to. Finally!
One exception: when matching for GPOS, or for backtrack/lookahead of
GSUB, we ignore ZWNJ too. That's the right thing to do.
It certainly is possible to build fonts that this feature will result
in undesirable glyphs, but it's hard to think of a real-world case
that that would happen.
This *does* break Indic shaping right now, since Indic Unicode has
specific rules for what ZWJ/ZWNJ mean, and skipping ZWJ is breaking
those rules. That will be fixed in upcoming commits.
2013-02-14 13:43:13 +01:00
|
|
|
|
2018-06-01 05:03:00 +02:00
|
|
|
for (unsigned int i = 0; i < lookupCount && buffer->successful; i++)
|
2009-05-20 05:58:54 +02:00
|
|
|
{
|
2013-10-14 18:51:39 +02:00
|
|
|
unsigned int idx = lookupRecord[i].sequenceIndex;
|
|
|
|
if (idx >= count)
|
|
|
|
continue;
|
Followup fix for 3f9e2dced298c3d00f31b2dfc38685bb071a3a22
During GSUB, if a ligation happens, subsequence context input matching
matches the new indexing. During GPOS however, the indices never
change. So just go one by one.
Fixes 'dist' positioning with mmrtext.ttf and the following sequence:
U+1014,U+1039,U+1011,U+1014,U+1039,U+1011,U+1014,U+1039,U+1011
Reported by Jonathan Kew.
2013-07-18 22:29:50 +02:00
|
|
|
|
2015-11-19 21:39:09 +01:00
|
|
|
/* Don't recurse to ourself at same position.
|
|
|
|
* Note that this test is too naive, it doesn't catch longer loops. */
|
|
|
|
if (idx == 0 && lookupRecord[i].lookupListIndex == c->lookup_index)
|
|
|
|
continue;
|
|
|
|
|
2017-11-15 00:47:55 +01:00
|
|
|
if (unlikely (!buffer->move_to (match_positions[idx])))
|
|
|
|
break;
|
2013-02-14 13:41:03 +01:00
|
|
|
|
2017-11-15 06:53:48 +01:00
|
|
|
if (unlikely (buffer->max_ops <= 0))
|
|
|
|
break;
|
|
|
|
|
2013-10-14 18:51:39 +02:00
|
|
|
unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
|
|
|
|
if (!c->recurse (lookupRecord[i].lookupListIndex))
|
|
|
|
continue;
|
2013-02-14 13:41:03 +01:00
|
|
|
|
2013-10-14 18:51:39 +02:00
|
|
|
unsigned int new_len = buffer->backtrack_len () + buffer->lookahead_len ();
|
|
|
|
int delta = new_len - orig_len;
|
2009-05-18 10:15:25 +02:00
|
|
|
|
2013-10-14 18:51:39 +02:00
|
|
|
if (!delta)
|
2018-11-15 20:40:56 +01:00
|
|
|
continue;
|
Followup fix for 3f9e2dced298c3d00f31b2dfc38685bb071a3a22
During GSUB, if a ligation happens, subsequence context input matching
matches the new indexing. During GPOS however, the indices never
change. So just go one by one.
Fixes 'dist' positioning with mmrtext.ttf and the following sequence:
U+1014,U+1039,U+1011,U+1014,U+1039,U+1011,U+1014,U+1039,U+1011
Reported by Jonathan Kew.
2013-07-18 22:29:50 +02:00
|
|
|
|
2017-03-05 22:51:01 +01:00
|
|
|
/* Recursed lookup changed buffer len. Adjust.
|
|
|
|
*
|
|
|
|
* TODO:
|
|
|
|
*
|
|
|
|
* Right now, if buffer length increased by n, we assume n new glyphs
|
|
|
|
* were added right after the current position, and if buffer length
|
|
|
|
* was decreased by n, we assume n match positions after the current
|
|
|
|
* one where removed. The former (buffer length increased) case is
|
|
|
|
* fine, but the decrease case can be improved in at least two ways,
|
|
|
|
* both of which are significant:
|
|
|
|
*
|
|
|
|
* - If recursed-to lookup is MultipleSubst and buffer length
|
|
|
|
* decreased, then it's current match position that was deleted,
|
|
|
|
* NOT the one after it.
|
|
|
|
*
|
|
|
|
* - If buffer length was decreased by n, it does not necessarily
|
|
|
|
* mean that n match positions where removed, as there might
|
|
|
|
* have been marks and default-ignorables in the sequence. We
|
|
|
|
* should instead drop match positions between current-position
|
|
|
|
* and current-position + n instead.
|
|
|
|
*
|
|
|
|
* It should be possible to construct tests for both of these cases.
|
|
|
|
*/
|
2009-05-17 14:28:42 +02:00
|
|
|
|
2017-02-17 04:03:24 +01:00
|
|
|
end += delta;
|
2017-03-10 22:23:02 +01:00
|
|
|
if (end <= int (match_positions[idx]))
|
2016-05-06 17:19:19 +02:00
|
|
|
{
|
2016-12-22 06:10:43 +01:00
|
|
|
/* End might end up being smaller than match_positions[idx] if the recursed
|
2017-03-10 22:23:02 +01:00
|
|
|
* lookup ended up removing many items, more than we have had matched.
|
2016-12-22 06:10:43 +01:00
|
|
|
* Just never rewind end back and get out of here.
|
|
|
|
* https://bugs.chromium.org/p/chromium/issues/detail?id=659496 */
|
|
|
|
end = match_positions[idx];
|
2017-03-10 22:23:02 +01:00
|
|
|
/* There can't be any further changes. */
|
2016-05-06 17:19:19 +02:00
|
|
|
break;
|
|
|
|
}
|
2009-05-17 14:28:42 +02:00
|
|
|
|
2013-10-14 18:51:39 +02:00
|
|
|
unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */
|
|
|
|
|
|
|
|
if (delta > 0)
|
|
|
|
{
|
2015-11-03 00:43:08 +01:00
|
|
|
if (unlikely (delta + count > HB_MAX_CONTEXT_LENGTH))
|
2013-10-14 18:51:39 +02:00
|
|
|
break;
|
2009-05-17 14:28:42 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-03-10 22:23:02 +01:00
|
|
|
/* NOTE: delta is negative. */
|
2013-10-14 18:51:39 +02:00
|
|
|
delta = MAX (delta, (int) next - (int) count);
|
|
|
|
next -= delta;
|
2009-05-17 14:28:42 +02:00
|
|
|
}
|
2013-10-14 18:51:39 +02:00
|
|
|
|
|
|
|
/* Shift! */
|
|
|
|
memmove (match_positions + next + delta, match_positions + next,
|
|
|
|
(count - next) * sizeof (match_positions[0]));
|
|
|
|
next += delta;
|
|
|
|
count += delta;
|
|
|
|
|
|
|
|
/* Fill in new entries. */
|
|
|
|
for (unsigned int j = idx + 1; j < next; j++)
|
|
|
|
match_positions[j] = match_positions[j - 1] + 1;
|
|
|
|
|
|
|
|
/* And fixup the rest. */
|
|
|
|
for (; next < count; next++)
|
|
|
|
match_positions[next] += delta;
|
2009-05-17 14:28:42 +02:00
|
|
|
}
|
|
|
|
|
2013-10-14 18:51:39 +02:00
|
|
|
buffer->move_to (end);
|
|
|
|
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (true);
|
2009-05-17 14:28:42 +02:00
|
|
|
}
|
2009-05-18 04:11:30 +02:00
|
|
|
|
2010-07-23 21:11:18 +02:00
|
|
|
|
2009-05-18 08:36:18 +02:00
|
|
|
|
|
|
|
/* Contextual lookups */
|
|
|
|
|
2012-04-23 22:54:58 +02:00
|
|
|
struct ContextClosureLookupContext
|
|
|
|
{
|
|
|
|
ContextClosureFuncs funcs;
|
|
|
|
const void *intersects_data;
|
|
|
|
};
|
|
|
|
|
2012-11-24 00:54:59 +01:00
|
|
|
struct ContextCollectGlyphsLookupContext
|
|
|
|
{
|
|
|
|
ContextCollectGlyphsFuncs funcs;
|
|
|
|
const void *collect_data;
|
|
|
|
};
|
|
|
|
|
2012-04-23 22:54:58 +02:00
|
|
|
struct ContextApplyLookupContext
|
2009-05-20 05:58:54 +02:00
|
|
|
{
|
2012-04-23 22:54:58 +02:00
|
|
|
ContextApplyFuncs funcs;
|
2010-05-10 23:47:22 +02:00
|
|
|
const void *match_data;
|
2009-05-18 08:36:18 +02:00
|
|
|
};
|
|
|
|
|
2018-09-03 04:47:50 +02:00
|
|
|
static inline bool context_intersects (const hb_set_t *glyphs,
|
|
|
|
unsigned int inputCount, /* Including the first glyph (not matched) */
|
|
|
|
const HBUINT16 input[], /* Array of input values--start with second glyph */
|
|
|
|
ContextClosureLookupContext &lookup_context)
|
|
|
|
{
|
|
|
|
return intersects_array (glyphs,
|
|
|
|
inputCount ? inputCount - 1 : 0, input,
|
|
|
|
lookup_context.funcs.intersects, lookup_context.intersects_data);
|
|
|
|
}
|
|
|
|
|
2012-04-24 05:03:12 +02:00
|
|
|
static inline void context_closure_lookup (hb_closure_context_t *c,
|
2012-04-23 22:54:58 +02:00
|
|
|
unsigned int inputCount, /* Including the first glyph (not matched) */
|
2018-01-10 03:07:30 +01:00
|
|
|
const HBUINT16 input[], /* Array of input values--start with second glyph */
|
2012-04-23 22:54:58 +02:00
|
|
|
unsigned int lookupCount,
|
|
|
|
const LookupRecord lookupRecord[],
|
|
|
|
ContextClosureLookupContext &lookup_context)
|
|
|
|
{
|
2018-09-03 04:47:50 +02:00
|
|
|
if (context_intersects (c->glyphs,
|
|
|
|
inputCount, input,
|
|
|
|
lookup_context))
|
2012-11-24 00:54:59 +01:00
|
|
|
recurse_lookups (c,
|
|
|
|
lookupCount, lookupRecord);
|
2012-04-23 22:54:58 +02:00
|
|
|
}
|
|
|
|
|
2012-11-24 00:54:59 +01:00
|
|
|
static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
|
|
|
|
unsigned int inputCount, /* Including the first glyph (not matched) */
|
2018-01-10 03:07:30 +01:00
|
|
|
const HBUINT16 input[], /* Array of input values--start with second glyph */
|
2012-11-24 00:54:59 +01:00
|
|
|
unsigned int lookupCount,
|
|
|
|
const LookupRecord lookupRecord[],
|
|
|
|
ContextCollectGlyphsLookupContext &lookup_context)
|
|
|
|
{
|
2012-12-04 23:08:41 +01:00
|
|
|
collect_array (c, c->input,
|
2012-11-24 00:54:59 +01:00
|
|
|
inputCount ? inputCount - 1 : 0, input,
|
|
|
|
lookup_context.funcs.collect, lookup_context.collect_data);
|
|
|
|
recurse_lookups (c,
|
|
|
|
lookupCount, lookupRecord);
|
|
|
|
}
|
2012-04-23 22:54:58 +02:00
|
|
|
|
2012-07-19 20:35:23 +02:00
|
|
|
static inline bool context_would_apply_lookup (hb_would_apply_context_t *c,
|
|
|
|
unsigned int inputCount, /* Including the first glyph (not matched) */
|
2018-01-10 03:07:30 +01:00
|
|
|
const HBUINT16 input[], /* Array of input values--start with second glyph */
|
2012-12-06 00:46:04 +01:00
|
|
|
unsigned int lookupCount HB_UNUSED,
|
|
|
|
const LookupRecord lookupRecord[] HB_UNUSED,
|
2012-07-19 20:35:23 +02:00
|
|
|
ContextApplyLookupContext &lookup_context)
|
|
|
|
{
|
|
|
|
return would_match_input (c,
|
|
|
|
inputCount, input,
|
|
|
|
lookup_context.funcs.match, lookup_context.match_data);
|
|
|
|
}
|
2018-01-18 01:46:51 +01:00
|
|
|
static inline bool context_apply_lookup (hb_ot_apply_context_t *c,
|
2012-04-23 22:54:58 +02:00
|
|
|
unsigned int inputCount, /* Including the first glyph (not matched) */
|
2018-01-10 03:07:30 +01:00
|
|
|
const HBUINT16 input[], /* Array of input values--start with second glyph */
|
2012-04-23 22:54:58 +02:00
|
|
|
unsigned int lookupCount,
|
|
|
|
const LookupRecord lookupRecord[],
|
|
|
|
ContextApplyLookupContext &lookup_context)
|
2009-05-18 08:36:18 +02:00
|
|
|
{
|
2013-10-14 18:51:39 +02:00
|
|
|
unsigned int match_length = 0;
|
2015-11-03 00:43:08 +01:00
|
|
|
unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
|
2010-05-13 20:18:49 +02:00
|
|
|
return match_input (c,
|
2010-05-05 07:37:58 +02:00
|
|
|
inputCount, input,
|
2013-10-14 18:51:39 +02:00
|
|
|
lookup_context.funcs.match, lookup_context.match_data,
|
|
|
|
&match_length, match_positions)
|
2016-05-02 14:47:45 +02:00
|
|
|
&& (c->buffer->unsafe_to_break (c->buffer->idx, c->buffer->idx + match_length),
|
|
|
|
apply_lookup (c,
|
2013-10-14 18:51:39 +02:00
|
|
|
inputCount, match_positions,
|
|
|
|
lookupCount, lookupRecord,
|
2016-05-02 14:47:45 +02:00
|
|
|
match_length));
|
2009-05-18 08:36:18 +02:00
|
|
|
}
|
|
|
|
|
2009-05-20 05:58:54 +02:00
|
|
|
struct Rule
|
|
|
|
{
|
2018-12-16 20:08:10 +01:00
|
|
|
bool intersects (const hb_set_t *glyphs, ContextClosureLookupContext &lookup_context) const
|
2018-09-03 04:47:50 +02:00
|
|
|
{
|
|
|
|
return context_intersects (glyphs,
|
2018-09-10 23:02:24 +02:00
|
|
|
inputCount, inputZ.arrayZ,
|
2018-09-03 04:47:50 +02:00
|
|
|
lookup_context);
|
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
|
2012-04-23 22:54:58 +02:00
|
|
|
{
|
2018-11-02 17:23:26 +01:00
|
|
|
const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord> >
|
|
|
|
(inputZ.as_array ((inputCount ? inputCount - 1 : 0)));
|
2012-04-24 05:03:12 +02:00
|
|
|
context_closure_lookup (c,
|
2018-09-10 23:02:24 +02:00
|
|
|
inputCount, inputZ.arrayZ,
|
|
|
|
lookupCount, lookupRecord.arrayZ,
|
2012-04-24 05:03:12 +02:00
|
|
|
lookup_context);
|
2012-04-23 22:54:58 +02:00
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
void collect_glyphs (hb_collect_glyphs_context_t *c,
|
|
|
|
ContextCollectGlyphsLookupContext &lookup_context) const
|
2012-11-24 00:54:59 +01:00
|
|
|
{
|
2018-11-02 17:23:26 +01:00
|
|
|
const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord> >
|
|
|
|
(inputZ.as_array (inputCount ? inputCount - 1 : 0));
|
2012-11-24 00:54:59 +01:00
|
|
|
context_collect_glyphs_lookup (c,
|
2018-09-10 23:02:24 +02:00
|
|
|
inputCount, inputZ.arrayZ,
|
|
|
|
lookupCount, lookupRecord.arrayZ,
|
2012-11-24 00:54:59 +01:00
|
|
|
lookup_context);
|
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool would_apply (hb_would_apply_context_t *c,
|
|
|
|
ContextApplyLookupContext &lookup_context) const
|
2012-07-19 20:35:23 +02:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_WOULD_APPLY (this);
|
2018-11-02 17:23:26 +01:00
|
|
|
const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord> >
|
|
|
|
(inputZ.as_array (inputCount ? inputCount - 1 : 0));
|
2018-09-10 23:02:24 +02:00
|
|
|
return_trace (context_would_apply_lookup (c, inputCount, inputZ.arrayZ, lookupCount, lookupRecord.arrayZ, lookup_context));
|
2012-07-19 20:35:23 +02:00
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool apply (hb_ot_apply_context_t *c,
|
|
|
|
ContextApplyLookupContext &lookup_context) const
|
2009-05-20 05:58:54 +02:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_APPLY (this);
|
2018-11-02 17:23:26 +01:00
|
|
|
const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord> >
|
|
|
|
(inputZ.as_array (inputCount ? inputCount - 1 : 0));
|
2018-09-10 23:02:24 +02:00
|
|
|
return_trace (context_apply_lookup (c, inputCount, inputZ.arrayZ, lookupCount, lookupRecord.arrayZ, lookup_context));
|
2009-05-17 14:28:42 +02:00
|
|
|
}
|
|
|
|
|
2009-08-04 06:58:28 +02:00
|
|
|
public:
|
2018-12-16 20:08:10 +01:00
|
|
|
bool sanitize (hb_sanitize_context_t *c) const
|
2015-02-17 15:27:44 +01:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_SANITIZE (this);
|
2017-11-03 22:16:26 +01:00
|
|
|
return_trace (inputCount.sanitize (c) &&
|
|
|
|
lookupCount.sanitize (c) &&
|
2018-09-10 23:02:24 +02:00
|
|
|
c->check_range (inputZ.arrayZ,
|
2018-11-30 21:16:57 +01:00
|
|
|
inputZ.item_size * (inputCount ? inputCount - 1 : 0) +
|
2018-02-07 21:09:56 +01:00
|
|
|
LookupRecord::static_size * lookupCount));
|
2009-08-04 06:58:28 +02:00
|
|
|
}
|
|
|
|
|
2012-07-24 21:40:37 +02:00
|
|
|
protected:
|
2018-01-10 03:07:30 +01:00
|
|
|
HBUINT16 inputCount; /* Total number of glyphs in input
|
2012-04-23 22:54:58 +02:00
|
|
|
* glyph sequence--includes the first
|
2009-05-17 14:28:42 +02:00
|
|
|
* glyph */
|
2018-01-10 03:07:30 +01:00
|
|
|
HBUINT16 lookupCount; /* Number of LookupRecords */
|
2018-09-10 23:02:24 +02:00
|
|
|
UnsizedArrayOf<HBUINT16>
|
|
|
|
inputZ; /* Array of match inputs--start with
|
2009-05-17 14:28:42 +02:00
|
|
|
* second glyph */
|
2018-09-10 23:02:24 +02:00
|
|
|
/*UnsizedArrayOf<LookupRecord>
|
|
|
|
lookupRecordX;*/ /* Array of LookupRecords--in
|
2009-05-17 14:28:42 +02:00
|
|
|
* design order */
|
2010-05-10 22:38:32 +02:00
|
|
|
public:
|
2018-02-07 21:09:56 +01:00
|
|
|
DEFINE_SIZE_ARRAY (4, inputZ);
|
2009-05-17 14:28:42 +02:00
|
|
|
};
|
|
|
|
|
2009-05-20 05:58:54 +02:00
|
|
|
struct RuleSet
|
|
|
|
{
|
2018-12-16 20:08:10 +01:00
|
|
|
bool intersects (const hb_set_t *glyphs,
|
|
|
|
ContextClosureLookupContext &lookup_context) const
|
2018-09-03 04:47:50 +02:00
|
|
|
{
|
2019-02-15 00:14:37 +01:00
|
|
|
for (auto it = hb_iter (rule); it; ++it)
|
|
|
|
if ((this+*it).intersects (glyphs, lookup_context))
|
2018-11-15 20:40:56 +01:00
|
|
|
return true;
|
2018-09-03 04:47:50 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
void closure (hb_closure_context_t *c,
|
|
|
|
ContextClosureLookupContext &lookup_context) const
|
2012-04-23 22:54:58 +02:00
|
|
|
{
|
2019-02-15 00:13:16 +01:00
|
|
|
for (auto it = hb_iter (rule); it; ++it)
|
|
|
|
(this+*it).closure (c, lookup_context);
|
2012-04-23 22:54:58 +02:00
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
void collect_glyphs (hb_collect_glyphs_context_t *c,
|
|
|
|
ContextCollectGlyphsLookupContext &lookup_context) const
|
2012-11-24 00:54:59 +01:00
|
|
|
{
|
2019-02-15 00:43:20 +01:00
|
|
|
for (auto it = hb_iter (rule); it; ++it)
|
|
|
|
(this+*it).collect_glyphs (c, lookup_context);
|
2012-11-24 00:54:59 +01:00
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool would_apply (hb_would_apply_context_t *c,
|
|
|
|
ContextApplyLookupContext &lookup_context) const
|
2012-07-19 20:35:23 +02:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_WOULD_APPLY (this);
|
2019-02-15 00:43:20 +01:00
|
|
|
for (auto it = hb_iter (rule); it; ++it)
|
|
|
|
if ((this+*it).would_apply (c, lookup_context))
|
2018-11-15 20:40:56 +01:00
|
|
|
return_trace (true);
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (false);
|
2012-07-19 20:35:23 +02:00
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool apply (hb_ot_apply_context_t *c,
|
|
|
|
ContextApplyLookupContext &lookup_context) const
|
2009-05-20 05:58:54 +02:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_APPLY (this);
|
2019-02-15 00:43:20 +01:00
|
|
|
for (auto it = hb_iter (rule); it; ++it)
|
|
|
|
if ((this+*it).apply (c, lookup_context))
|
2018-11-15 20:40:56 +01:00
|
|
|
return_trace (true);
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (false);
|
2009-05-17 14:28:42 +02:00
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool sanitize (hb_sanitize_context_t *c) const
|
2015-02-17 15:27:44 +01:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_SANITIZE (this);
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (rule.sanitize (c, this));
|
2009-08-04 06:58:28 +02:00
|
|
|
}
|
|
|
|
|
2012-07-24 21:40:37 +02:00
|
|
|
protected:
|
2009-05-17 14:28:42 +02:00
|
|
|
OffsetArrayOf<Rule>
|
2009-05-18 04:11:30 +02:00
|
|
|
rule; /* Array of Rule tables
|
2009-05-17 14:28:42 +02:00
|
|
|
* ordered by preference */
|
2010-05-11 00:08:46 +02:00
|
|
|
public:
|
2010-05-11 01:01:17 +02:00
|
|
|
DEFINE_SIZE_ARRAY (2, rule);
|
2009-05-17 14:28:42 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2009-05-20 05:58:54 +02:00
|
|
|
struct ContextFormat1
|
|
|
|
{
|
2018-12-16 20:08:10 +01:00
|
|
|
bool intersects (const hb_set_t *glyphs) const
|
2018-09-03 04:47:50 +02:00
|
|
|
{
|
|
|
|
struct ContextClosureLookupContext lookup_context = {
|
|
|
|
{intersects_glyph},
|
|
|
|
nullptr
|
|
|
|
};
|
2019-01-10 06:00:13 +01:00
|
|
|
for (auto it = hb_zip (this+coverage, ruleSet)
|
|
|
|
| hb_filter (*glyphs, hb_first)
|
|
|
|
| hb_map (hb_second); it; ++it)
|
|
|
|
if ((this+*it).intersects (glyphs, lookup_context))
|
|
|
|
return true;
|
2018-09-03 04:47:50 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
void closure (hb_closure_context_t *c) const
|
2012-04-23 19:04:38 +02:00
|
|
|
{
|
2012-04-23 22:54:58 +02:00
|
|
|
struct ContextClosureLookupContext lookup_context = {
|
2012-11-22 05:33:13 +01:00
|
|
|
{intersects_glyph},
|
2017-10-15 12:11:08 +02:00
|
|
|
nullptr
|
2012-04-23 22:54:58 +02:00
|
|
|
};
|
2019-01-10 06:00:13 +01:00
|
|
|
for (auto it = hb_zip (this+coverage, ruleSet)
|
|
|
|
| hb_filter (*c->glyphs, hb_first)
|
|
|
|
| hb_map (hb_second); it; ++it)
|
|
|
|
(this+*it).closure (c, lookup_context);
|
2012-04-23 19:04:38 +02:00
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
void collect_glyphs (hb_collect_glyphs_context_t *c) const
|
2012-11-24 00:13:48 +01:00
|
|
|
{
|
2012-12-04 23:08:41 +01:00
|
|
|
(this+coverage).add_coverage (c->input);
|
2012-11-24 00:54:59 +01:00
|
|
|
|
|
|
|
struct ContextCollectGlyphsLookupContext lookup_context = {
|
|
|
|
{collect_glyph},
|
2017-10-15 12:11:08 +02:00
|
|
|
nullptr
|
2012-11-24 00:54:59 +01:00
|
|
|
};
|
|
|
|
|
2019-02-15 00:43:20 +01:00
|
|
|
for (auto it = hb_iter (ruleSet); it; ++it)
|
|
|
|
(this+*it).collect_glyphs (c, lookup_context);
|
2012-11-24 00:13:48 +01:00
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool would_apply (hb_would_apply_context_t *c) const
|
2012-07-19 20:35:23 +02:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_WOULD_APPLY (this);
|
2012-07-19 20:35:23 +02:00
|
|
|
|
2012-11-25 01:13:55 +01:00
|
|
|
const RuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
|
2012-07-19 20:35:23 +02:00
|
|
|
struct ContextApplyLookupContext lookup_context = {
|
2012-11-22 22:05:59 +01:00
|
|
|
{match_glyph},
|
2017-10-15 12:11:08 +02:00
|
|
|
nullptr
|
2012-07-19 20:35:23 +02:00
|
|
|
};
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (rule_set.would_apply (c, lookup_context));
|
2012-07-19 20:35:23 +02:00
|
|
|
}
|
|
|
|
|
2018-12-17 19:01:01 +01:00
|
|
|
const Coverage &get_coverage () const { return this+coverage; }
|
2012-11-22 05:33:13 +01:00
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool apply (hb_ot_apply_context_t *c) const
|
2009-05-20 05:58:54 +02:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_APPLY (this);
|
2012-11-25 01:13:55 +01:00
|
|
|
unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
|
2010-05-04 04:51:19 +02:00
|
|
|
if (likely (index == NOT_COVERED))
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (false);
|
2009-05-18 05:17:56 +02:00
|
|
|
|
2009-05-17 14:28:42 +02:00
|
|
|
const RuleSet &rule_set = this+ruleSet[index];
|
2012-04-23 22:54:58 +02:00
|
|
|
struct ContextApplyLookupContext lookup_context = {
|
2012-11-22 22:05:59 +01:00
|
|
|
{match_glyph},
|
2017-10-15 12:11:08 +02:00
|
|
|
nullptr
|
2009-05-17 14:28:42 +02:00
|
|
|
};
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (rule_set.apply (c, lookup_context));
|
2009-05-17 14:28:42 +02:00
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool subset (hb_subset_context_t *c) const
|
2018-09-04 02:33:34 +02:00
|
|
|
{
|
|
|
|
TRACE_SUBSET (this);
|
|
|
|
// TODO(subset)
|
|
|
|
return_trace (false);
|
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool sanitize (hb_sanitize_context_t *c) const
|
2015-02-17 15:27:44 +01:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_SANITIZE (this);
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
|
2009-08-04 06:58:28 +02:00
|
|
|
}
|
|
|
|
|
2012-07-24 21:40:37 +02:00
|
|
|
protected:
|
2018-01-10 03:07:30 +01:00
|
|
|
HBUINT16 format; /* Format identifier--format = 1 */
|
2009-05-17 14:28:42 +02:00
|
|
|
OffsetTo<Coverage>
|
|
|
|
coverage; /* Offset to Coverage table--from
|
|
|
|
* beginning of table */
|
|
|
|
OffsetArrayOf<RuleSet>
|
|
|
|
ruleSet; /* Array of RuleSet tables
|
|
|
|
* ordered by Coverage Index */
|
2010-05-10 22:57:29 +02:00
|
|
|
public:
|
2010-05-11 01:01:17 +02:00
|
|
|
DEFINE_SIZE_ARRAY (6, ruleSet);
|
2009-05-17 14:28:42 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2009-05-20 05:58:54 +02:00
|
|
|
struct ContextFormat2
|
|
|
|
{
|
2018-12-16 20:08:10 +01:00
|
|
|
bool intersects (const hb_set_t *glyphs) const
|
2018-09-03 04:47:50 +02:00
|
|
|
{
|
|
|
|
if (!(this+coverage).intersects (glyphs))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
const ClassDef &class_def = this+classDef;
|
|
|
|
|
|
|
|
struct ContextClosureLookupContext lookup_context = {
|
|
|
|
{intersects_class},
|
|
|
|
&class_def
|
|
|
|
};
|
|
|
|
|
2019-02-16 01:05:36 +01:00
|
|
|
for (auto it = hb_enumerate (ruleSet); it; ++it)
|
|
|
|
if (class_def.intersects_class (glyphs, (*it).first) &&
|
|
|
|
(this+(*it).second).intersects (glyphs, lookup_context))
|
2018-11-15 20:40:56 +01:00
|
|
|
return true;
|
2018-09-03 04:47:50 +02:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
void closure (hb_closure_context_t *c) const
|
2012-04-23 19:04:38 +02:00
|
|
|
{
|
2012-04-23 22:54:58 +02:00
|
|
|
if (!(this+coverage).intersects (c->glyphs))
|
2012-04-24 05:03:12 +02:00
|
|
|
return;
|
2012-04-23 22:54:58 +02:00
|
|
|
|
|
|
|
const ClassDef &class_def = this+classDef;
|
|
|
|
|
|
|
|
struct ContextClosureLookupContext lookup_context = {
|
2012-11-22 05:33:13 +01:00
|
|
|
{intersects_class},
|
2013-01-03 06:36:37 +01:00
|
|
|
&class_def
|
2012-04-23 22:54:58 +02:00
|
|
|
};
|
|
|
|
|
2019-02-16 01:05:36 +01:00
|
|
|
for (auto it = hb_enumerate (ruleSet); it; ++it)
|
|
|
|
if (class_def.intersects_class (c->glyphs, (*it).first))
|
|
|
|
(this+(*it).second).closure (c, lookup_context);
|
2012-04-23 19:04:38 +02:00
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
void collect_glyphs (hb_collect_glyphs_context_t *c) const
|
2012-11-24 00:13:48 +01:00
|
|
|
{
|
2012-12-04 23:08:41 +01:00
|
|
|
(this+coverage).add_coverage (c->input);
|
2012-11-24 00:54:59 +01:00
|
|
|
|
2013-01-03 06:36:37 +01:00
|
|
|
const ClassDef &class_def = this+classDef;
|
2012-11-24 00:54:59 +01:00
|
|
|
struct ContextCollectGlyphsLookupContext lookup_context = {
|
|
|
|
{collect_class},
|
2013-01-03 06:36:37 +01:00
|
|
|
&class_def
|
2012-11-24 00:54:59 +01:00
|
|
|
};
|
|
|
|
|
2019-02-15 02:10:04 +01:00
|
|
|
for (auto it = hb_iter (ruleSet); it; ++it)
|
|
|
|
(this+*it).collect_glyphs (c, lookup_context);
|
2012-11-24 00:13:48 +01:00
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool would_apply (hb_would_apply_context_t *c) const
|
2012-07-19 20:35:23 +02:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_WOULD_APPLY (this);
|
2012-07-19 20:35:23 +02:00
|
|
|
|
|
|
|
const ClassDef &class_def = this+classDef;
|
2012-11-25 01:16:34 +01:00
|
|
|
unsigned int index = class_def.get_class (c->glyphs[0]);
|
2012-07-19 20:35:23 +02:00
|
|
|
const RuleSet &rule_set = this+ruleSet[index];
|
|
|
|
struct ContextApplyLookupContext lookup_context = {
|
2012-11-22 22:05:59 +01:00
|
|
|
{match_class},
|
2012-07-19 20:35:23 +02:00
|
|
|
&class_def
|
|
|
|
};
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (rule_set.would_apply (c, lookup_context));
|
2012-07-19 20:35:23 +02:00
|
|
|
}
|
|
|
|
|
2018-12-17 19:01:01 +01:00
|
|
|
const Coverage &get_coverage () const { return this+coverage; }
|
2012-11-22 05:33:13 +01:00
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool apply (hb_ot_apply_context_t *c) const
|
2009-05-20 05:58:54 +02:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_APPLY (this);
|
2012-11-25 01:13:55 +01:00
|
|
|
unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
|
2015-09-29 15:57:02 +02:00
|
|
|
if (likely (index == NOT_COVERED)) return_trace (false);
|
2009-05-18 05:17:56 +02:00
|
|
|
|
|
|
|
const ClassDef &class_def = this+classDef;
|
2012-11-25 01:16:34 +01:00
|
|
|
index = class_def.get_class (c->buffer->cur().codepoint);
|
2009-05-17 14:28:42 +02:00
|
|
|
const RuleSet &rule_set = this+ruleSet[index];
|
2012-04-23 22:54:58 +02:00
|
|
|
struct ContextApplyLookupContext lookup_context = {
|
2012-11-22 22:05:59 +01:00
|
|
|
{match_class},
|
2010-05-10 23:47:22 +02:00
|
|
|
&class_def
|
2009-05-17 14:28:42 +02:00
|
|
|
};
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (rule_set.apply (c, lookup_context));
|
2009-05-17 14:28:42 +02:00
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool subset (hb_subset_context_t *c) const
|
2018-09-04 02:33:34 +02:00
|
|
|
{
|
|
|
|
TRACE_SUBSET (this);
|
|
|
|
// TODO(subset)
|
|
|
|
return_trace (false);
|
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool sanitize (hb_sanitize_context_t *c) const
|
2015-02-17 15:27:44 +01:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_SANITIZE (this);
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this));
|
2009-08-04 06:58:28 +02:00
|
|
|
}
|
|
|
|
|
2012-07-24 21:40:37 +02:00
|
|
|
protected:
|
2018-01-10 03:07:30 +01:00
|
|
|
HBUINT16 format; /* Format identifier--format = 2 */
|
2009-05-17 14:28:42 +02:00
|
|
|
OffsetTo<Coverage>
|
|
|
|
coverage; /* Offset to Coverage table--from
|
|
|
|
* beginning of table */
|
|
|
|
OffsetTo<ClassDef>
|
|
|
|
classDef; /* Offset to glyph ClassDef table--from
|
|
|
|
* beginning of table */
|
|
|
|
OffsetArrayOf<RuleSet>
|
|
|
|
ruleSet; /* Array of RuleSet tables
|
|
|
|
* ordered by class */
|
2010-05-10 22:57:29 +02:00
|
|
|
public:
|
2010-05-11 01:01:17 +02:00
|
|
|
DEFINE_SIZE_ARRAY (8, ruleSet);
|
2009-05-17 14:28:42 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2009-05-20 05:58:54 +02:00
|
|
|
struct ContextFormat3
|
|
|
|
{
|
2018-12-16 20:08:10 +01:00
|
|
|
bool intersects (const hb_set_t *glyphs) const
|
2018-09-03 04:47:50 +02:00
|
|
|
{
|
2018-12-01 02:45:40 +01:00
|
|
|
if (!(this+coverageZ[0]).intersects (glyphs))
|
2018-09-03 04:47:50 +02:00
|
|
|
return false;
|
|
|
|
|
|
|
|
struct ContextClosureLookupContext lookup_context = {
|
|
|
|
{intersects_coverage},
|
|
|
|
this
|
|
|
|
};
|
|
|
|
return context_intersects (glyphs,
|
2018-09-10 23:02:24 +02:00
|
|
|
glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
|
2018-09-03 04:47:50 +02:00
|
|
|
lookup_context);
|
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
void closure (hb_closure_context_t *c) const
|
2012-04-23 19:04:38 +02:00
|
|
|
{
|
2018-12-01 02:45:40 +01:00
|
|
|
if (!(this+coverageZ[0]).intersects (c->glyphs))
|
2012-04-24 05:03:12 +02:00
|
|
|
return;
|
2012-04-23 22:54:58 +02:00
|
|
|
|
2018-11-02 17:23:26 +01:00
|
|
|
const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
|
2012-04-23 22:54:58 +02:00
|
|
|
struct ContextClosureLookupContext lookup_context = {
|
2012-11-22 05:33:13 +01:00
|
|
|
{intersects_coverage},
|
2012-04-23 22:54:58 +02:00
|
|
|
this
|
|
|
|
};
|
2012-04-24 05:03:12 +02:00
|
|
|
context_closure_lookup (c,
|
2018-09-10 23:02:24 +02:00
|
|
|
glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
|
2012-04-24 05:03:12 +02:00
|
|
|
lookupCount, lookupRecord,
|
|
|
|
lookup_context);
|
2012-04-23 19:04:38 +02:00
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
void collect_glyphs (hb_collect_glyphs_context_t *c) const
|
2012-11-24 00:13:48 +01:00
|
|
|
{
|
2018-12-01 02:45:40 +01:00
|
|
|
(this+coverageZ[0]).add_coverage (c->input);
|
2012-11-24 00:54:59 +01:00
|
|
|
|
2018-11-02 17:23:26 +01:00
|
|
|
const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
|
2012-11-24 00:54:59 +01:00
|
|
|
struct ContextCollectGlyphsLookupContext lookup_context = {
|
|
|
|
{collect_coverage},
|
2012-11-30 07:38:24 +01:00
|
|
|
this
|
2012-11-24 00:54:59 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
context_collect_glyphs_lookup (c,
|
2018-09-10 23:02:24 +02:00
|
|
|
glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
|
2012-11-24 00:54:59 +01:00
|
|
|
lookupCount, lookupRecord,
|
|
|
|
lookup_context);
|
2012-11-24 00:13:48 +01:00
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool would_apply (hb_would_apply_context_t *c) const
|
2012-07-19 20:35:23 +02:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_WOULD_APPLY (this);
|
2012-07-19 20:35:23 +02:00
|
|
|
|
2018-11-02 17:23:26 +01:00
|
|
|
const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
|
2012-07-19 20:35:23 +02:00
|
|
|
struct ContextApplyLookupContext lookup_context = {
|
2012-11-22 22:05:59 +01:00
|
|
|
{match_coverage},
|
2012-07-19 20:35:23 +02:00
|
|
|
this
|
|
|
|
};
|
2018-09-10 23:02:24 +02:00
|
|
|
return_trace (context_would_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), lookupCount, lookupRecord, lookup_context));
|
2012-07-19 20:35:23 +02:00
|
|
|
}
|
|
|
|
|
2018-12-17 19:01:01 +01:00
|
|
|
const Coverage &get_coverage () const { return this+coverageZ[0]; }
|
2012-11-22 05:33:13 +01:00
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool apply (hb_ot_apply_context_t *c) const
|
2009-05-20 05:58:54 +02:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_APPLY (this);
|
2018-12-01 02:45:40 +01:00
|
|
|
unsigned int index = (this+coverageZ[0]).get_coverage (c->buffer->cur().codepoint);
|
2015-09-29 15:57:02 +02:00
|
|
|
if (likely (index == NOT_COVERED)) return_trace (false);
|
2009-05-17 14:28:42 +02:00
|
|
|
|
2018-11-02 17:23:26 +01:00
|
|
|
const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
|
2012-04-23 22:54:58 +02:00
|
|
|
struct ContextApplyLookupContext lookup_context = {
|
2012-11-22 22:05:59 +01:00
|
|
|
{match_coverage},
|
2010-05-10 23:47:22 +02:00
|
|
|
this
|
2009-05-17 14:28:42 +02:00
|
|
|
};
|
2018-09-10 23:02:24 +02:00
|
|
|
return_trace (context_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), lookupCount, lookupRecord, lookup_context));
|
2009-05-17 14:28:42 +02:00
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool subset (hb_subset_context_t *c) const
|
2018-09-04 02:33:34 +02:00
|
|
|
{
|
|
|
|
TRACE_SUBSET (this);
|
|
|
|
// TODO(subset)
|
|
|
|
return_trace (false);
|
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool sanitize (hb_sanitize_context_t *c) const
|
2015-02-17 15:27:44 +01:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_SANITIZE (this);
|
2015-09-29 15:57:02 +02:00
|
|
|
if (!c->check_struct (this)) return_trace (false);
|
2009-08-04 06:58:28 +02:00
|
|
|
unsigned int count = glyphCount;
|
2018-12-01 02:45:40 +01:00
|
|
|
if (!count) return_trace (false); /* We want to access coverageZ[0] freely. */
|
2018-09-10 23:18:07 +02:00
|
|
|
if (!c->check_array (coverageZ.arrayZ, count)) return_trace (false);
|
2009-08-04 06:58:28 +02:00
|
|
|
for (unsigned int i = 0; i < count; i++)
|
2015-09-29 15:57:02 +02:00
|
|
|
if (!coverageZ[i].sanitize (c, this)) return_trace (false);
|
2018-11-02 17:23:26 +01:00
|
|
|
const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
|
2018-09-10 23:18:07 +02:00
|
|
|
return_trace (c->check_array (lookupRecord, lookupCount));
|
2009-08-04 06:58:28 +02:00
|
|
|
}
|
|
|
|
|
2012-07-24 21:40:37 +02:00
|
|
|
protected:
|
2018-01-10 03:07:30 +01:00
|
|
|
HBUINT16 format; /* Format identifier--format = 3 */
|
|
|
|
HBUINT16 glyphCount; /* Number of glyphs in the input glyph
|
2009-05-17 14:28:42 +02:00
|
|
|
* sequence */
|
2018-01-10 03:07:30 +01:00
|
|
|
HBUINT16 lookupCount; /* Number of LookupRecords */
|
2018-09-10 23:02:24 +02:00
|
|
|
UnsizedArrayOf<OffsetTo<Coverage> >
|
|
|
|
coverageZ; /* Array of offsets to Coverage
|
2009-05-18 05:17:56 +02:00
|
|
|
* table in glyph sequence order */
|
2018-09-10 23:02:24 +02:00
|
|
|
/*UnsizedArrayOf<LookupRecord>
|
|
|
|
lookupRecordX;*/ /* Array of LookupRecords--in
|
2009-05-17 14:28:42 +02:00
|
|
|
* design order */
|
2010-05-10 22:38:32 +02:00
|
|
|
public:
|
2018-02-07 21:09:56 +01:00
|
|
|
DEFINE_SIZE_ARRAY (6, coverageZ);
|
2009-05-17 14:28:42 +02:00
|
|
|
};
|
|
|
|
|
2009-05-20 05:58:54 +02:00
|
|
|
struct Context
|
|
|
|
{
|
2012-11-22 05:33:13 +01:00
|
|
|
template <typename context_t>
|
2018-12-16 20:08:10 +01:00
|
|
|
typename context_t::return_t dispatch (context_t *c) const
|
2012-11-17 04:07:06 +01:00
|
|
|
{
|
2014-12-13 05:36:49 +01:00
|
|
|
TRACE_DISPATCH (this, u.format);
|
2015-10-09 18:25:55 +02:00
|
|
|
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
|
2012-11-17 04:07:06 +01:00
|
|
|
switch (u.format) {
|
2015-09-29 15:57:02 +02:00
|
|
|
case 1: return_trace (c->dispatch (u.format1));
|
|
|
|
case 2: return_trace (c->dispatch (u.format2));
|
|
|
|
case 3: return_trace (c->dispatch (u.format3));
|
|
|
|
default:return_trace (c->default_return_value ());
|
2012-07-19 20:35:23 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-24 21:40:37 +02:00
|
|
|
protected:
|
2009-05-17 14:28:42 +02:00
|
|
|
union {
|
2018-01-10 03:07:30 +01:00
|
|
|
HBUINT16 format; /* Format identifier */
|
2010-05-11 01:45:41 +02:00
|
|
|
ContextFormat1 format1;
|
|
|
|
ContextFormat2 format2;
|
|
|
|
ContextFormat3 format3;
|
2009-05-17 14:28:42 +02:00
|
|
|
} u;
|
|
|
|
};
|
|
|
|
|
2009-05-18 02:48:27 +02:00
|
|
|
|
|
|
|
/* Chaining Contextual lookups */
|
|
|
|
|
2012-04-23 22:54:58 +02:00
|
|
|
struct ChainContextClosureLookupContext
|
2009-05-20 05:58:54 +02:00
|
|
|
{
|
2012-04-23 22:54:58 +02:00
|
|
|
ContextClosureFuncs funcs;
|
|
|
|
const void *intersects_data[3];
|
|
|
|
};
|
|
|
|
|
2012-11-24 07:55:34 +01:00
|
|
|
struct ChainContextCollectGlyphsLookupContext
|
|
|
|
{
|
|
|
|
ContextCollectGlyphsFuncs funcs;
|
|
|
|
const void *collect_data[3];
|
|
|
|
};
|
|
|
|
|
2012-04-23 22:54:58 +02:00
|
|
|
struct ChainContextApplyLookupContext
|
|
|
|
{
|
|
|
|
ContextApplyFuncs funcs;
|
2010-05-10 23:47:22 +02:00
|
|
|
const void *match_data[3];
|
2009-05-18 04:11:30 +02:00
|
|
|
};
|
|
|
|
|
2018-09-03 04:47:50 +02:00
|
|
|
static inline bool chain_context_intersects (const hb_set_t *glyphs,
|
|
|
|
unsigned int backtrackCount,
|
|
|
|
const HBUINT16 backtrack[],
|
|
|
|
unsigned int inputCount, /* Including the first glyph (not matched) */
|
|
|
|
const HBUINT16 input[], /* Array of input values--start with second glyph */
|
|
|
|
unsigned int lookaheadCount,
|
|
|
|
const HBUINT16 lookahead[],
|
|
|
|
ChainContextClosureLookupContext &lookup_context)
|
|
|
|
{
|
|
|
|
return intersects_array (glyphs,
|
|
|
|
backtrackCount, backtrack,
|
2018-12-01 02:45:40 +01:00
|
|
|
lookup_context.funcs.intersects, lookup_context.intersects_data[0])
|
2018-09-03 04:47:50 +02:00
|
|
|
&& intersects_array (glyphs,
|
|
|
|
inputCount ? inputCount - 1 : 0, input,
|
|
|
|
lookup_context.funcs.intersects, lookup_context.intersects_data[1])
|
|
|
|
&& intersects_array (glyphs,
|
|
|
|
lookaheadCount, lookahead,
|
|
|
|
lookup_context.funcs.intersects, lookup_context.intersects_data[2]);
|
|
|
|
}
|
|
|
|
|
2012-04-24 05:03:12 +02:00
|
|
|
static inline void chain_context_closure_lookup (hb_closure_context_t *c,
|
2012-04-23 22:54:58 +02:00
|
|
|
unsigned int backtrackCount,
|
2018-01-10 03:07:30 +01:00
|
|
|
const HBUINT16 backtrack[],
|
2012-04-23 22:54:58 +02:00
|
|
|
unsigned int inputCount, /* Including the first glyph (not matched) */
|
2018-01-10 03:07:30 +01:00
|
|
|
const HBUINT16 input[], /* Array of input values--start with second glyph */
|
2012-04-23 22:54:58 +02:00
|
|
|
unsigned int lookaheadCount,
|
2018-01-10 03:07:30 +01:00
|
|
|
const HBUINT16 lookahead[],
|
2012-04-23 22:54:58 +02:00
|
|
|
unsigned int lookupCount,
|
|
|
|
const LookupRecord lookupRecord[],
|
|
|
|
ChainContextClosureLookupContext &lookup_context)
|
|
|
|
{
|
2018-09-03 04:47:50 +02:00
|
|
|
if (chain_context_intersects (c->glyphs,
|
|
|
|
backtrackCount, backtrack,
|
|
|
|
inputCount, input,
|
|
|
|
lookaheadCount, lookahead,
|
|
|
|
lookup_context))
|
2012-11-24 00:54:59 +01:00
|
|
|
recurse_lookups (c,
|
|
|
|
lookupCount, lookupRecord);
|
2012-04-23 22:54:58 +02:00
|
|
|
}
|
|
|
|
|
2012-11-24 07:55:34 +01:00
|
|
|
static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
|
2018-11-15 20:40:56 +01:00
|
|
|
unsigned int backtrackCount,
|
|
|
|
const HBUINT16 backtrack[],
|
|
|
|
unsigned int inputCount, /* Including the first glyph (not matched) */
|
|
|
|
const HBUINT16 input[], /* Array of input values--start with second glyph */
|
|
|
|
unsigned int lookaheadCount,
|
|
|
|
const HBUINT16 lookahead[],
|
|
|
|
unsigned int lookupCount,
|
|
|
|
const LookupRecord lookupRecord[],
|
|
|
|
ChainContextCollectGlyphsLookupContext &lookup_context)
|
2012-11-24 07:55:34 +01:00
|
|
|
{
|
2012-12-04 23:08:41 +01:00
|
|
|
collect_array (c, c->before,
|
2012-11-24 07:55:34 +01:00
|
|
|
backtrackCount, backtrack,
|
|
|
|
lookup_context.funcs.collect, lookup_context.collect_data[0]);
|
2012-12-04 23:08:41 +01:00
|
|
|
collect_array (c, c->input,
|
2012-11-24 07:55:34 +01:00
|
|
|
inputCount ? inputCount - 1 : 0, input,
|
|
|
|
lookup_context.funcs.collect, lookup_context.collect_data[1]);
|
2012-12-04 23:08:41 +01:00
|
|
|
collect_array (c, c->after,
|
2012-11-24 07:55:34 +01:00
|
|
|
lookaheadCount, lookahead,
|
|
|
|
lookup_context.funcs.collect, lookup_context.collect_data[2]);
|
|
|
|
recurse_lookups (c,
|
|
|
|
lookupCount, lookupRecord);
|
|
|
|
}
|
|
|
|
|
2012-07-19 20:35:23 +02:00
|
|
|
static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c,
|
|
|
|
unsigned int backtrackCount,
|
2018-01-10 03:07:30 +01:00
|
|
|
const HBUINT16 backtrack[] HB_UNUSED,
|
2012-07-19 20:35:23 +02:00
|
|
|
unsigned int inputCount, /* Including the first glyph (not matched) */
|
2018-01-10 03:07:30 +01:00
|
|
|
const HBUINT16 input[], /* Array of input values--start with second glyph */
|
2012-07-19 20:35:23 +02:00
|
|
|
unsigned int lookaheadCount,
|
2018-01-10 03:07:30 +01:00
|
|
|
const HBUINT16 lookahead[] HB_UNUSED,
|
2012-12-06 00:46:04 +01:00
|
|
|
unsigned int lookupCount HB_UNUSED,
|
|
|
|
const LookupRecord lookupRecord[] HB_UNUSED,
|
2012-07-19 20:35:23 +02:00
|
|
|
ChainContextApplyLookupContext &lookup_context)
|
|
|
|
{
|
2012-08-23 22:22:28 +02:00
|
|
|
return (c->zero_context ? !backtrackCount && !lookaheadCount : true)
|
2012-08-23 22:10:37 +02:00
|
|
|
&& would_match_input (c,
|
2012-07-19 20:35:23 +02:00
|
|
|
inputCount, input,
|
|
|
|
lookup_context.funcs.match, lookup_context.match_data[1]);
|
|
|
|
}
|
|
|
|
|
2018-01-18 01:46:51 +01:00
|
|
|
static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
|
2012-04-23 22:54:58 +02:00
|
|
|
unsigned int backtrackCount,
|
2018-01-10 03:07:30 +01:00
|
|
|
const HBUINT16 backtrack[],
|
2012-04-23 22:54:58 +02:00
|
|
|
unsigned int inputCount, /* Including the first glyph (not matched) */
|
2018-01-10 03:07:30 +01:00
|
|
|
const HBUINT16 input[], /* Array of input values--start with second glyph */
|
2012-04-23 22:54:58 +02:00
|
|
|
unsigned int lookaheadCount,
|
2018-01-10 03:07:30 +01:00
|
|
|
const HBUINT16 lookahead[],
|
2012-04-23 22:54:58 +02:00
|
|
|
unsigned int lookupCount,
|
|
|
|
const LookupRecord lookupRecord[],
|
|
|
|
ChainContextApplyLookupContext &lookup_context)
|
2009-05-18 08:47:57 +02:00
|
|
|
{
|
2016-05-02 14:47:45 +02:00
|
|
|
unsigned int start_index = 0, match_length = 0, end_index = 0;
|
2015-11-03 00:43:08 +01:00
|
|
|
unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
|
2012-06-09 08:26:57 +02:00
|
|
|
return match_input (c,
|
2010-05-05 07:37:58 +02:00
|
|
|
inputCount, input,
|
|
|
|
lookup_context.funcs.match, lookup_context.match_data[1],
|
2013-10-14 18:51:39 +02:00
|
|
|
&match_length, match_positions)
|
2012-06-09 08:26:57 +02:00
|
|
|
&& match_backtrack (c,
|
|
|
|
backtrackCount, backtrack,
|
2016-05-02 14:47:45 +02:00
|
|
|
lookup_context.funcs.match, lookup_context.match_data[0],
|
|
|
|
&start_index)
|
2010-05-13 20:18:49 +02:00
|
|
|
&& match_lookahead (c,
|
2010-05-05 07:37:58 +02:00
|
|
|
lookaheadCount, lookahead,
|
|
|
|
lookup_context.funcs.match, lookup_context.match_data[2],
|
2016-05-02 14:47:45 +02:00
|
|
|
match_length, &end_index)
|
|
|
|
&& (c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index),
|
2018-11-15 20:40:56 +01:00
|
|
|
apply_lookup (c,
|
|
|
|
inputCount, match_positions,
|
|
|
|
lookupCount, lookupRecord,
|
|
|
|
match_length));
|
2009-05-18 08:47:57 +02:00
|
|
|
}
|
2009-05-18 04:11:30 +02:00
|
|
|
|
2009-05-20 05:58:54 +02:00
|
|
|
struct ChainRule
|
|
|
|
{
|
2018-12-16 20:08:10 +01:00
|
|
|
bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
|
2018-09-03 04:47:50 +02:00
|
|
|
{
|
|
|
|
const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
|
|
|
|
const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
|
|
|
|
return chain_context_intersects (glyphs,
|
|
|
|
backtrack.len, backtrack.arrayZ,
|
2018-09-13 20:21:54 +02:00
|
|
|
input.lenP1, input.arrayZ,
|
2018-09-03 04:47:50 +02:00
|
|
|
lookahead.len, lookahead.arrayZ,
|
|
|
|
lookup_context);
|
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
void closure (hb_closure_context_t *c,
|
|
|
|
ChainContextClosureLookupContext &lookup_context) const
|
2012-04-23 22:54:58 +02:00
|
|
|
{
|
2018-01-10 03:07:30 +01:00
|
|
|
const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
|
|
|
|
const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
|
2012-04-23 22:54:58 +02:00
|
|
|
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
|
2012-04-24 05:03:12 +02:00
|
|
|
chain_context_closure_lookup (c,
|
2018-05-09 01:56:11 +02:00
|
|
|
backtrack.len, backtrack.arrayZ,
|
2018-09-13 20:21:54 +02:00
|
|
|
input.lenP1, input.arrayZ,
|
2018-05-09 01:56:11 +02:00
|
|
|
lookahead.len, lookahead.arrayZ,
|
|
|
|
lookup.len, lookup.arrayZ,
|
2012-04-24 05:03:12 +02:00
|
|
|
lookup_context);
|
2012-04-23 22:54:58 +02:00
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
void collect_glyphs (hb_collect_glyphs_context_t *c,
|
|
|
|
ChainContextCollectGlyphsLookupContext &lookup_context) const
|
2012-11-24 07:55:34 +01:00
|
|
|
{
|
2018-01-10 03:07:30 +01:00
|
|
|
const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
|
|
|
|
const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
|
2012-11-24 07:55:34 +01:00
|
|
|
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
|
|
|
|
chain_context_collect_glyphs_lookup (c,
|
2018-05-09 01:56:11 +02:00
|
|
|
backtrack.len, backtrack.arrayZ,
|
2018-09-13 20:21:54 +02:00
|
|
|
input.lenP1, input.arrayZ,
|
2018-05-09 01:56:11 +02:00
|
|
|
lookahead.len, lookahead.arrayZ,
|
|
|
|
lookup.len, lookup.arrayZ,
|
2012-11-24 07:55:34 +01:00
|
|
|
lookup_context);
|
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool would_apply (hb_would_apply_context_t *c,
|
|
|
|
ChainContextApplyLookupContext &lookup_context) const
|
2012-07-19 20:35:23 +02:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_WOULD_APPLY (this);
|
2018-01-10 03:07:30 +01:00
|
|
|
const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
|
|
|
|
const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
|
2012-07-19 20:35:23 +02:00
|
|
|
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (chain_context_would_apply_lookup (c,
|
2018-05-09 01:56:11 +02:00
|
|
|
backtrack.len, backtrack.arrayZ,
|
2018-09-13 20:21:54 +02:00
|
|
|
input.lenP1, input.arrayZ,
|
2018-05-09 01:56:11 +02:00
|
|
|
lookahead.len, lookahead.arrayZ, lookup.len,
|
|
|
|
lookup.arrayZ, lookup_context));
|
2012-07-19 20:35:23 +02:00
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
|
2009-05-20 05:58:54 +02:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_APPLY (this);
|
2018-01-10 03:07:30 +01:00
|
|
|
const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
|
|
|
|
const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
|
2010-04-21 21:56:11 +02:00
|
|
|
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (chain_context_apply_lookup (c,
|
2018-05-09 01:56:11 +02:00
|
|
|
backtrack.len, backtrack.arrayZ,
|
2018-09-13 20:21:54 +02:00
|
|
|
input.lenP1, input.arrayZ,
|
2018-05-09 01:56:11 +02:00
|
|
|
lookahead.len, lookahead.arrayZ, lookup.len,
|
|
|
|
lookup.arrayZ, lookup_context));
|
2009-05-18 05:17:56 +02:00
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool sanitize (hb_sanitize_context_t *c) const
|
2015-02-17 15:27:44 +01:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_SANITIZE (this);
|
2015-09-29 15:57:02 +02:00
|
|
|
if (!backtrack.sanitize (c)) return_trace (false);
|
2018-01-10 03:07:30 +01:00
|
|
|
const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
|
2015-09-29 15:57:02 +02:00
|
|
|
if (!input.sanitize (c)) return_trace (false);
|
2018-01-10 03:07:30 +01:00
|
|
|
const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
|
2015-09-29 15:57:02 +02:00
|
|
|
if (!lookahead.sanitize (c)) return_trace (false);
|
2015-02-17 15:27:44 +01:00
|
|
|
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (lookup.sanitize (c));
|
2009-08-04 06:58:28 +02:00
|
|
|
}
|
2009-05-18 02:48:27 +02:00
|
|
|
|
2012-07-24 21:40:37 +02:00
|
|
|
protected:
|
2018-01-10 03:07:30 +01:00
|
|
|
ArrayOf<HBUINT16>
|
2009-05-18 07:49:57 +02:00
|
|
|
backtrack; /* Array of backtracking values
|
2009-05-18 02:48:27 +02:00
|
|
|
* (to be matched before the input
|
|
|
|
* sequence) */
|
2018-01-10 03:07:30 +01:00
|
|
|
HeadlessArrayOf<HBUINT16>
|
2009-05-18 08:03:58 +02:00
|
|
|
inputX; /* Array of input values (start with
|
2009-05-18 02:48:27 +02:00
|
|
|
* second glyph) */
|
2018-01-10 03:07:30 +01:00
|
|
|
ArrayOf<HBUINT16>
|
2009-05-18 07:49:57 +02:00
|
|
|
lookaheadX; /* Array of lookahead values's (to be
|
2009-05-18 04:11:30 +02:00
|
|
|
* matched after the input sequence) */
|
2009-05-18 07:49:57 +02:00
|
|
|
ArrayOf<LookupRecord>
|
2009-05-18 08:47:57 +02:00
|
|
|
lookupX; /* Array of LookupRecords--in
|
2009-05-18 02:48:27 +02:00
|
|
|
* design order) */
|
2010-05-10 22:57:29 +02:00
|
|
|
public:
|
2010-05-10 23:28:16 +02:00
|
|
|
DEFINE_SIZE_MIN (8);
|
2009-05-18 02:48:27 +02:00
|
|
|
};
|
|
|
|
|
2009-05-20 05:58:54 +02:00
|
|
|
struct ChainRuleSet
|
|
|
|
{
|
2018-12-16 20:08:10 +01:00
|
|
|
bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
|
2018-09-03 04:47:50 +02:00
|
|
|
{
|
2019-02-15 00:14:37 +01:00
|
|
|
for (auto it = hb_iter (rule); it; ++it)
|
|
|
|
if ((this+*it).intersects (glyphs, lookup_context))
|
2018-11-15 20:40:56 +01:00
|
|
|
return true;
|
2018-09-03 04:47:50 +02:00
|
|
|
return false;
|
|
|
|
}
|
2018-12-16 20:08:10 +01:00
|
|
|
void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
|
2012-04-23 22:54:58 +02:00
|
|
|
{
|
2019-02-15 00:13:16 +01:00
|
|
|
for (auto it = hb_iter (rule); it; ++it)
|
|
|
|
(this+*it).closure (c, lookup_context);
|
2012-04-23 22:54:58 +02:00
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
|
2012-11-24 07:55:34 +01:00
|
|
|
{
|
2019-02-15 00:43:20 +01:00
|
|
|
for (auto it = hb_iter (rule); it; ++it)
|
|
|
|
(this+*it).collect_glyphs (c, lookup_context);
|
2012-11-24 07:55:34 +01:00
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
|
2012-07-19 20:35:23 +02:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_WOULD_APPLY (this);
|
2019-02-15 00:43:20 +01:00
|
|
|
for (auto it = hb_iter (rule); it; ++it)
|
|
|
|
if ((this+*it).would_apply (c, lookup_context))
|
2018-11-15 20:40:56 +01:00
|
|
|
return_trace (true);
|
2012-07-19 20:35:23 +02:00
|
|
|
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (false);
|
2012-07-19 20:35:23 +02:00
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
|
2009-05-20 05:58:54 +02:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_APPLY (this);
|
2019-02-15 00:43:20 +01:00
|
|
|
for (auto it = hb_iter (rule); it; ++it)
|
|
|
|
if ((this+*it).apply (c, lookup_context))
|
2018-11-15 20:40:56 +01:00
|
|
|
return_trace (true);
|
2009-05-18 04:11:30 +02:00
|
|
|
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (false);
|
2009-05-18 04:11:30 +02:00
|
|
|
}
|
2009-05-18 02:48:27 +02:00
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool sanitize (hb_sanitize_context_t *c) const
|
2015-02-17 15:27:44 +01:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_SANITIZE (this);
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (rule.sanitize (c, this));
|
2009-08-04 06:58:28 +02:00
|
|
|
}
|
|
|
|
|
2012-07-24 21:40:37 +02:00
|
|
|
protected:
|
2009-05-18 04:11:30 +02:00
|
|
|
OffsetArrayOf<ChainRule>
|
|
|
|
rule; /* Array of ChainRule tables
|
|
|
|
* ordered by preference */
|
2010-05-10 22:57:29 +02:00
|
|
|
public:
|
2010-05-11 01:01:17 +02:00
|
|
|
DEFINE_SIZE_ARRAY (2, rule);
|
2009-05-18 02:48:27 +02:00
|
|
|
};
|
|
|
|
|
2009-05-20 05:58:54 +02:00
|
|
|
struct ChainContextFormat1
|
|
|
|
{
|
2018-12-16 20:08:10 +01:00
|
|
|
bool intersects (const hb_set_t *glyphs) const
|
2018-09-03 04:47:50 +02:00
|
|
|
{
|
|
|
|
struct ChainContextClosureLookupContext lookup_context = {
|
|
|
|
{intersects_glyph},
|
|
|
|
{nullptr, nullptr, nullptr}
|
|
|
|
};
|
2019-01-10 06:00:13 +01:00
|
|
|
for (auto it = hb_zip (this+coverage, ruleSet)
|
|
|
|
| hb_filter (*glyphs, hb_first)
|
|
|
|
| hb_map (hb_second); it; ++it)
|
|
|
|
if ((this+*it).intersects (glyphs, lookup_context))
|
|
|
|
return true;
|
2018-09-03 04:47:50 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
void closure (hb_closure_context_t *c) const
|
2012-04-23 19:04:38 +02:00
|
|
|
{
|
2012-04-23 22:54:58 +02:00
|
|
|
struct ChainContextClosureLookupContext lookup_context = {
|
2012-11-22 05:33:13 +01:00
|
|
|
{intersects_glyph},
|
2017-10-15 12:11:08 +02:00
|
|
|
{nullptr, nullptr, nullptr}
|
2012-04-23 22:54:58 +02:00
|
|
|
};
|
2019-01-10 06:00:13 +01:00
|
|
|
for (auto it = hb_zip (this+coverage, ruleSet)
|
|
|
|
| hb_filter (*c->glyphs, hb_first)
|
|
|
|
| hb_map (hb_second); it; ++it)
|
|
|
|
(this+*it).closure (c, lookup_context);
|
2012-04-23 19:04:38 +02:00
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
void collect_glyphs (hb_collect_glyphs_context_t *c) const
|
2012-11-24 00:13:48 +01:00
|
|
|
{
|
2012-12-04 23:08:41 +01:00
|
|
|
(this+coverage).add_coverage (c->input);
|
2012-11-24 07:55:34 +01:00
|
|
|
|
|
|
|
struct ChainContextCollectGlyphsLookupContext lookup_context = {
|
|
|
|
{collect_glyph},
|
2017-10-15 12:11:08 +02:00
|
|
|
{nullptr, nullptr, nullptr}
|
2012-11-24 07:55:34 +01:00
|
|
|
};
|
|
|
|
|
2019-02-15 00:43:20 +01:00
|
|
|
for (auto it = hb_iter (ruleSet); it; ++it)
|
|
|
|
(this+*it).collect_glyphs (c, lookup_context);
|
2012-11-24 00:13:48 +01:00
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool would_apply (hb_would_apply_context_t *c) const
|
2012-07-19 20:35:23 +02:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_WOULD_APPLY (this);
|
2012-07-19 20:35:23 +02:00
|
|
|
|
2012-11-25 01:13:55 +01:00
|
|
|
const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
|
2012-07-19 20:35:23 +02:00
|
|
|
struct ChainContextApplyLookupContext lookup_context = {
|
2012-11-22 22:05:59 +01:00
|
|
|
{match_glyph},
|
2017-10-15 12:11:08 +02:00
|
|
|
{nullptr, nullptr, nullptr}
|
2012-07-19 20:35:23 +02:00
|
|
|
};
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (rule_set.would_apply (c, lookup_context));
|
2012-07-19 20:35:23 +02:00
|
|
|
}
|
|
|
|
|
2018-12-17 19:01:01 +01:00
|
|
|
const Coverage &get_coverage () const { return this+coverage; }
|
2012-11-22 05:33:13 +01:00
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool apply (hb_ot_apply_context_t *c) const
|
2009-05-20 05:58:54 +02:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_APPLY (this);
|
2012-11-25 01:13:55 +01:00
|
|
|
unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
|
2015-09-29 15:57:02 +02:00
|
|
|
if (likely (index == NOT_COVERED)) return_trace (false);
|
2009-05-18 02:48:27 +02:00
|
|
|
|
2009-05-18 05:17:56 +02:00
|
|
|
const ChainRuleSet &rule_set = this+ruleSet[index];
|
2012-04-23 22:54:58 +02:00
|
|
|
struct ChainContextApplyLookupContext lookup_context = {
|
2012-11-22 22:05:59 +01:00
|
|
|
{match_glyph},
|
2017-10-15 12:11:08 +02:00
|
|
|
{nullptr, nullptr, nullptr}
|
2009-05-18 05:17:56 +02:00
|
|
|
};
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (rule_set.apply (c, lookup_context));
|
2009-05-18 05:17:56 +02:00
|
|
|
}
|
2009-08-04 06:58:28 +02:00
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool subset (hb_subset_context_t *c) const
|
2018-09-04 02:33:34 +02:00
|
|
|
{
|
|
|
|
TRACE_SUBSET (this);
|
|
|
|
// TODO(subset)
|
|
|
|
return_trace (false);
|
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool sanitize (hb_sanitize_context_t *c) const
|
2015-02-17 15:27:44 +01:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_SANITIZE (this);
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
|
2009-08-04 06:58:28 +02:00
|
|
|
}
|
|
|
|
|
2012-07-24 21:40:37 +02:00
|
|
|
protected:
|
2018-01-10 03:07:30 +01:00
|
|
|
HBUINT16 format; /* Format identifier--format = 1 */
|
2009-05-18 04:11:30 +02:00
|
|
|
OffsetTo<Coverage>
|
|
|
|
coverage; /* Offset to Coverage table--from
|
2009-05-18 02:48:27 +02:00
|
|
|
* beginning of table */
|
2009-05-18 05:17:56 +02:00
|
|
|
OffsetArrayOf<ChainRuleSet>
|
|
|
|
ruleSet; /* Array of ChainRuleSet tables
|
|
|
|
* ordered by Coverage Index */
|
2010-05-10 22:57:29 +02:00
|
|
|
public:
|
2010-05-11 01:01:17 +02:00
|
|
|
DEFINE_SIZE_ARRAY (6, ruleSet);
|
2009-05-18 02:48:27 +02:00
|
|
|
};
|
|
|
|
|
2009-05-20 05:58:54 +02:00
|
|
|
struct ChainContextFormat2
|
|
|
|
{
|
2018-12-16 20:08:10 +01:00
|
|
|
bool intersects (const hb_set_t *glyphs) const
|
2018-09-03 04:47:50 +02:00
|
|
|
{
|
|
|
|
if (!(this+coverage).intersects (glyphs))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
const ClassDef &backtrack_class_def = this+backtrackClassDef;
|
|
|
|
const ClassDef &input_class_def = this+inputClassDef;
|
|
|
|
const ClassDef &lookahead_class_def = this+lookaheadClassDef;
|
|
|
|
|
|
|
|
struct ChainContextClosureLookupContext lookup_context = {
|
|
|
|
{intersects_class},
|
|
|
|
{&backtrack_class_def,
|
|
|
|
&input_class_def,
|
|
|
|
&lookahead_class_def}
|
|
|
|
};
|
|
|
|
|
2019-02-16 01:05:36 +01:00
|
|
|
for (auto it = hb_enumerate (ruleSet); it; ++it)
|
|
|
|
if (input_class_def.intersects_class (glyphs, (*it).first) &&
|
|
|
|
(this+(*it).second).intersects (glyphs, lookup_context))
|
2018-11-15 20:40:56 +01:00
|
|
|
return true;
|
2018-09-03 04:47:50 +02:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2018-12-16 20:08:10 +01:00
|
|
|
void closure (hb_closure_context_t *c) const
|
2012-04-23 19:04:38 +02:00
|
|
|
{
|
2012-04-23 22:54:58 +02:00
|
|
|
if (!(this+coverage).intersects (c->glyphs))
|
2012-04-24 05:03:12 +02:00
|
|
|
return;
|
2012-04-23 22:54:58 +02:00
|
|
|
|
|
|
|
const ClassDef &backtrack_class_def = this+backtrackClassDef;
|
|
|
|
const ClassDef &input_class_def = this+inputClassDef;
|
|
|
|
const ClassDef &lookahead_class_def = this+lookaheadClassDef;
|
|
|
|
|
|
|
|
struct ChainContextClosureLookupContext lookup_context = {
|
2012-11-22 05:33:13 +01:00
|
|
|
{intersects_class},
|
2012-04-23 22:54:58 +02:00
|
|
|
{&backtrack_class_def,
|
|
|
|
&input_class_def,
|
|
|
|
&lookahead_class_def}
|
|
|
|
};
|
|
|
|
|
2019-02-16 01:05:36 +01:00
|
|
|
for (auto it = hb_enumerate (ruleSet); it; ++it)
|
|
|
|
if (input_class_def.intersects_class (c->glyphs, (*it).first))
|
|
|
|
(this+(*it).second).closure (c, lookup_context);
|
2012-04-23 19:04:38 +02:00
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
void collect_glyphs (hb_collect_glyphs_context_t *c) const
|
2012-11-24 00:13:48 +01:00
|
|
|
{
|
2012-12-04 23:08:41 +01:00
|
|
|
(this+coverage).add_coverage (c->input);
|
2012-11-24 07:55:34 +01:00
|
|
|
|
2013-01-03 06:36:37 +01:00
|
|
|
const ClassDef &backtrack_class_def = this+backtrackClassDef;
|
|
|
|
const ClassDef &input_class_def = this+inputClassDef;
|
|
|
|
const ClassDef &lookahead_class_def = this+lookaheadClassDef;
|
|
|
|
|
2012-11-24 07:55:34 +01:00
|
|
|
struct ChainContextCollectGlyphsLookupContext lookup_context = {
|
|
|
|
{collect_class},
|
2013-01-03 06:36:37 +01:00
|
|
|
{&backtrack_class_def,
|
|
|
|
&input_class_def,
|
|
|
|
&lookahead_class_def}
|
2012-11-24 07:55:34 +01:00
|
|
|
};
|
|
|
|
|
2019-02-15 02:10:04 +01:00
|
|
|
for (auto it = hb_iter (ruleSet); it; ++it)
|
|
|
|
(this+*it).collect_glyphs (c, lookup_context);
|
2012-11-24 00:13:48 +01:00
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool would_apply (hb_would_apply_context_t *c) const
|
2012-07-19 20:35:23 +02:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_WOULD_APPLY (this);
|
2012-07-19 20:35:23 +02:00
|
|
|
|
2013-01-03 06:36:37 +01:00
|
|
|
const ClassDef &backtrack_class_def = this+backtrackClassDef;
|
2012-07-19 20:35:23 +02:00
|
|
|
const ClassDef &input_class_def = this+inputClassDef;
|
2013-01-03 06:36:37 +01:00
|
|
|
const ClassDef &lookahead_class_def = this+lookaheadClassDef;
|
2012-07-19 20:35:23 +02:00
|
|
|
|
2012-11-25 01:16:34 +01:00
|
|
|
unsigned int index = input_class_def.get_class (c->glyphs[0]);
|
2012-07-19 20:35:23 +02:00
|
|
|
const ChainRuleSet &rule_set = this+ruleSet[index];
|
|
|
|
struct ChainContextApplyLookupContext lookup_context = {
|
2012-11-22 22:05:59 +01:00
|
|
|
{match_class},
|
2013-01-03 06:36:37 +01:00
|
|
|
{&backtrack_class_def,
|
|
|
|
&input_class_def,
|
|
|
|
&lookahead_class_def}
|
2012-07-19 20:35:23 +02:00
|
|
|
};
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (rule_set.would_apply (c, lookup_context));
|
2012-07-19 20:35:23 +02:00
|
|
|
}
|
|
|
|
|
2018-12-17 19:01:01 +01:00
|
|
|
const Coverage &get_coverage () const { return this+coverage; }
|
2012-11-22 05:33:13 +01:00
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool apply (hb_ot_apply_context_t *c) const
|
2009-05-20 05:58:54 +02:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_APPLY (this);
|
2012-11-25 01:13:55 +01:00
|
|
|
unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
|
2015-09-29 15:57:02 +02:00
|
|
|
if (likely (index == NOT_COVERED)) return_trace (false);
|
2009-05-18 05:17:56 +02:00
|
|
|
|
|
|
|
const ClassDef &backtrack_class_def = this+backtrackClassDef;
|
|
|
|
const ClassDef &input_class_def = this+inputClassDef;
|
|
|
|
const ClassDef &lookahead_class_def = this+lookaheadClassDef;
|
|
|
|
|
2012-11-25 01:16:34 +01:00
|
|
|
index = input_class_def.get_class (c->buffer->cur().codepoint);
|
2009-05-18 05:17:56 +02:00
|
|
|
const ChainRuleSet &rule_set = this+ruleSet[index];
|
2012-04-23 22:54:58 +02:00
|
|
|
struct ChainContextApplyLookupContext lookup_context = {
|
2012-11-22 22:05:59 +01:00
|
|
|
{match_class},
|
2010-05-10 23:47:22 +02:00
|
|
|
{&backtrack_class_def,
|
|
|
|
&input_class_def,
|
|
|
|
&lookahead_class_def}
|
2009-05-18 05:17:56 +02:00
|
|
|
};
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (rule_set.apply (c, lookup_context));
|
2009-05-18 02:48:27 +02:00
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool subset (hb_subset_context_t *c) const
|
2018-09-04 02:33:34 +02:00
|
|
|
{
|
|
|
|
TRACE_SUBSET (this);
|
|
|
|
// TODO(subset)
|
|
|
|
return_trace (false);
|
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool sanitize (hb_sanitize_context_t *c) const
|
2015-02-17 15:27:44 +01:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_SANITIZE (this);
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (coverage.sanitize (c, this) &&
|
|
|
|
backtrackClassDef.sanitize (c, this) &&
|
|
|
|
inputClassDef.sanitize (c, this) &&
|
|
|
|
lookaheadClassDef.sanitize (c, this) &&
|
|
|
|
ruleSet.sanitize (c, this));
|
2009-08-04 06:58:28 +02:00
|
|
|
}
|
|
|
|
|
2012-07-24 21:40:37 +02:00
|
|
|
protected:
|
2018-01-10 03:07:30 +01:00
|
|
|
HBUINT16 format; /* Format identifier--format = 2 */
|
2009-05-18 05:17:56 +02:00
|
|
|
OffsetTo<Coverage>
|
|
|
|
coverage; /* Offset to Coverage table--from
|
2009-05-18 02:48:27 +02:00
|
|
|
* beginning of table */
|
2009-05-18 05:17:56 +02:00
|
|
|
OffsetTo<ClassDef>
|
|
|
|
backtrackClassDef; /* Offset to glyph ClassDef table
|
2009-05-18 02:48:27 +02:00
|
|
|
* containing backtrack sequence
|
|
|
|
* data--from beginning of table */
|
2009-05-18 05:17:56 +02:00
|
|
|
OffsetTo<ClassDef>
|
|
|
|
inputClassDef; /* Offset to glyph ClassDef
|
2009-05-18 02:48:27 +02:00
|
|
|
* table containing input sequence
|
|
|
|
* data--from beginning of table */
|
2009-05-18 05:17:56 +02:00
|
|
|
OffsetTo<ClassDef>
|
|
|
|
lookaheadClassDef; /* Offset to glyph ClassDef table
|
2009-05-18 02:48:27 +02:00
|
|
|
* containing lookahead sequence
|
|
|
|
* data--from beginning of table */
|
2009-05-18 05:17:56 +02:00
|
|
|
OffsetArrayOf<ChainRuleSet>
|
|
|
|
ruleSet; /* Array of ChainRuleSet tables
|
|
|
|
* ordered by class */
|
2010-05-10 22:57:29 +02:00
|
|
|
public:
|
2010-05-11 01:01:17 +02:00
|
|
|
DEFINE_SIZE_ARRAY (12, ruleSet);
|
2009-05-18 02:48:27 +02:00
|
|
|
};
|
|
|
|
|
2009-05-20 05:58:54 +02:00
|
|
|
struct ChainContextFormat3
|
|
|
|
{
|
2018-12-16 20:08:10 +01:00
|
|
|
bool intersects (const hb_set_t *glyphs) const
|
2018-09-03 04:47:50 +02:00
|
|
|
{
|
|
|
|
const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
|
|
|
|
|
|
|
|
if (!(this+input[0]).intersects (glyphs))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
|
|
|
|
struct ChainContextClosureLookupContext lookup_context = {
|
|
|
|
{intersects_coverage},
|
|
|
|
{this, this, this}
|
|
|
|
};
|
|
|
|
return chain_context_intersects (glyphs,
|
|
|
|
backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
|
|
|
|
input.len, (const HBUINT16 *) input.arrayZ + 1,
|
|
|
|
lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
|
|
|
|
lookup_context);
|
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
void closure (hb_closure_context_t *c) const
|
2012-04-23 19:04:38 +02:00
|
|
|
{
|
2012-04-24 05:03:12 +02:00
|
|
|
const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
|
|
|
|
|
|
|
|
if (!(this+input[0]).intersects (c->glyphs))
|
|
|
|
return;
|
|
|
|
|
|
|
|
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
|
|
|
|
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
|
|
|
|
struct ChainContextClosureLookupContext lookup_context = {
|
2012-11-22 05:33:13 +01:00
|
|
|
{intersects_coverage},
|
2012-04-24 05:03:12 +02:00
|
|
|
{this, this, this}
|
|
|
|
};
|
|
|
|
chain_context_closure_lookup (c,
|
2018-05-09 01:56:11 +02:00
|
|
|
backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
|
|
|
|
input.len, (const HBUINT16 *) input.arrayZ + 1,
|
|
|
|
lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
|
|
|
|
lookup.len, lookup.arrayZ,
|
2012-04-24 05:03:12 +02:00
|
|
|
lookup_context);
|
2012-04-23 19:04:38 +02:00
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
void collect_glyphs (hb_collect_glyphs_context_t *c) const
|
2012-11-24 00:13:48 +01:00
|
|
|
{
|
2012-11-24 07:55:34 +01:00
|
|
|
const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
|
|
|
|
|
2012-12-04 23:08:41 +01:00
|
|
|
(this+input[0]).add_coverage (c->input);
|
2012-11-24 07:55:34 +01:00
|
|
|
|
|
|
|
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
|
|
|
|
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
|
|
|
|
struct ChainContextCollectGlyphsLookupContext lookup_context = {
|
|
|
|
{collect_coverage},
|
|
|
|
{this, this, this}
|
|
|
|
};
|
|
|
|
chain_context_collect_glyphs_lookup (c,
|
2018-05-09 01:56:11 +02:00
|
|
|
backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
|
|
|
|
input.len, (const HBUINT16 *) input.arrayZ + 1,
|
|
|
|
lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
|
|
|
|
lookup.len, lookup.arrayZ,
|
2012-11-24 07:55:34 +01:00
|
|
|
lookup_context);
|
2012-11-24 00:13:48 +01:00
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool would_apply (hb_would_apply_context_t *c) const
|
2012-07-19 20:35:23 +02:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_WOULD_APPLY (this);
|
2012-07-19 20:35:23 +02:00
|
|
|
|
2012-07-29 00:34:58 +02:00
|
|
|
const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
|
2012-07-19 20:35:23 +02:00
|
|
|
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
|
|
|
|
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
|
|
|
|
struct ChainContextApplyLookupContext lookup_context = {
|
2012-11-22 22:05:59 +01:00
|
|
|
{match_coverage},
|
2012-07-19 20:35:23 +02:00
|
|
|
{this, this, this}
|
|
|
|
};
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (chain_context_would_apply_lookup (c,
|
2018-05-09 01:56:11 +02:00
|
|
|
backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
|
|
|
|
input.len, (const HBUINT16 *) input.arrayZ + 1,
|
|
|
|
lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
|
|
|
|
lookup.len, lookup.arrayZ, lookup_context));
|
2012-07-19 20:35:23 +02:00
|
|
|
}
|
|
|
|
|
2018-12-17 19:01:01 +01:00
|
|
|
const Coverage &get_coverage () const
|
2012-11-22 05:33:13 +01:00
|
|
|
{
|
|
|
|
const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
|
|
|
|
return this+input[0];
|
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool apply (hb_ot_apply_context_t *c) const
|
2009-05-20 05:58:54 +02:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_APPLY (this);
|
2010-04-21 21:56:11 +02:00
|
|
|
const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
|
2009-05-18 08:47:57 +02:00
|
|
|
|
2012-11-25 01:13:55 +01:00
|
|
|
unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint);
|
2015-09-29 15:57:02 +02:00
|
|
|
if (likely (index == NOT_COVERED)) return_trace (false);
|
2009-05-18 08:47:57 +02:00
|
|
|
|
2010-04-21 21:56:11 +02:00
|
|
|
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
|
|
|
|
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
|
2012-04-23 22:54:58 +02:00
|
|
|
struct ChainContextApplyLookupContext lookup_context = {
|
2012-11-22 22:05:59 +01:00
|
|
|
{match_coverage},
|
2010-05-10 23:47:22 +02:00
|
|
|
{this, this, this}
|
2009-05-18 05:17:56 +02:00
|
|
|
};
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (chain_context_apply_lookup (c,
|
2018-05-09 01:56:11 +02:00
|
|
|
backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
|
|
|
|
input.len, (const HBUINT16 *) input.arrayZ + 1,
|
|
|
|
lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
|
|
|
|
lookup.len, lookup.arrayZ, lookup_context));
|
2009-05-18 05:17:56 +02:00
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool subset (hb_subset_context_t *c) const
|
2018-09-04 02:33:34 +02:00
|
|
|
{
|
|
|
|
TRACE_SUBSET (this);
|
|
|
|
// TODO(subset)
|
|
|
|
return_trace (false);
|
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool sanitize (hb_sanitize_context_t *c) const
|
2015-02-17 15:27:44 +01:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_SANITIZE (this);
|
2015-09-29 15:57:02 +02:00
|
|
|
if (!backtrack.sanitize (c, this)) return_trace (false);
|
2015-02-17 15:27:44 +01:00
|
|
|
const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
|
2015-09-29 15:57:02 +02:00
|
|
|
if (!input.sanitize (c, this)) return_trace (false);
|
|
|
|
if (!input.len) return_trace (false); /* To be consistent with Context. */
|
2015-02-17 15:27:44 +01:00
|
|
|
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
|
2015-09-29 15:57:02 +02:00
|
|
|
if (!lookahead.sanitize (c, this)) return_trace (false);
|
2015-02-17 15:27:44 +01:00
|
|
|
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (lookup.sanitize (c));
|
2009-08-04 06:58:28 +02:00
|
|
|
}
|
|
|
|
|
2012-07-24 21:40:37 +02:00
|
|
|
protected:
|
2018-01-10 03:07:30 +01:00
|
|
|
HBUINT16 format; /* Format identifier--format = 3 */
|
2009-05-18 07:49:57 +02:00
|
|
|
OffsetArrayOf<Coverage>
|
2009-05-18 08:14:37 +02:00
|
|
|
backtrack; /* Array of coverage tables
|
2009-05-18 02:48:27 +02:00
|
|
|
* in backtracking sequence, in glyph
|
|
|
|
* sequence order */
|
2009-05-18 07:49:57 +02:00
|
|
|
OffsetArrayOf<Coverage>
|
2009-05-18 08:14:37 +02:00
|
|
|
inputX ; /* Array of coverage
|
2009-05-18 02:48:27 +02:00
|
|
|
* tables in input sequence, in glyph
|
|
|
|
* sequence order */
|
2009-05-18 07:49:57 +02:00
|
|
|
OffsetArrayOf<Coverage>
|
2009-05-18 08:14:37 +02:00
|
|
|
lookaheadX; /* Array of coverage tables
|
2009-05-18 02:48:27 +02:00
|
|
|
* in lookahead sequence, in glyph
|
|
|
|
* sequence order */
|
2009-05-18 07:49:57 +02:00
|
|
|
ArrayOf<LookupRecord>
|
2009-05-18 08:47:57 +02:00
|
|
|
lookupX; /* Array of LookupRecords--in
|
2009-05-18 07:49:57 +02:00
|
|
|
* design order) */
|
2010-05-10 22:57:29 +02:00
|
|
|
public:
|
2010-05-10 23:28:16 +02:00
|
|
|
DEFINE_SIZE_MIN (10);
|
2009-05-18 02:48:27 +02:00
|
|
|
};
|
|
|
|
|
2009-05-20 05:58:54 +02:00
|
|
|
struct ChainContext
|
|
|
|
{
|
2012-11-22 05:33:13 +01:00
|
|
|
template <typename context_t>
|
2018-12-16 20:08:10 +01:00
|
|
|
typename context_t::return_t dispatch (context_t *c) const
|
2012-11-17 04:07:06 +01:00
|
|
|
{
|
2014-12-13 05:36:49 +01:00
|
|
|
TRACE_DISPATCH (this, u.format);
|
2015-10-09 18:25:55 +02:00
|
|
|
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
|
2012-11-17 04:07:06 +01:00
|
|
|
switch (u.format) {
|
2015-09-29 15:57:02 +02:00
|
|
|
case 1: return_trace (c->dispatch (u.format1));
|
|
|
|
case 2: return_trace (c->dispatch (u.format2));
|
|
|
|
case 3: return_trace (c->dispatch (u.format3));
|
|
|
|
default:return_trace (c->default_return_value ());
|
2012-07-19 20:35:23 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-24 21:40:37 +02:00
|
|
|
protected:
|
2009-05-18 02:48:27 +02:00
|
|
|
union {
|
2018-01-10 03:07:30 +01:00
|
|
|
HBUINT16 format; /* Format identifier */
|
2010-05-11 01:45:41 +02:00
|
|
|
ChainContextFormat1 format1;
|
|
|
|
ChainContextFormat2 format2;
|
|
|
|
ChainContextFormat3 format3;
|
2009-05-18 02:48:27 +02:00
|
|
|
} u;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2015-02-19 08:29:41 +01:00
|
|
|
template <typename T>
|
2009-05-22 04:31:33 +02:00
|
|
|
struct ExtensionFormat1
|
|
|
|
{
|
2018-12-17 19:01:01 +01:00
|
|
|
unsigned int get_type () const { return extensionLookupType; }
|
2009-05-22 04:31:33 +02:00
|
|
|
|
2015-02-19 08:29:41 +01:00
|
|
|
template <typename X>
|
2018-12-17 19:01:01 +01:00
|
|
|
const X& get_subtable () const
|
2015-02-19 08:29:41 +01:00
|
|
|
{
|
|
|
|
unsigned int offset = extensionOffset;
|
2018-09-04 01:53:03 +02:00
|
|
|
if (unlikely (!offset)) return Null(typename T::SubTable);
|
|
|
|
return StructAtOffset<typename T::SubTable> (this, offset);
|
2015-02-19 08:29:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename context_t>
|
2018-12-16 20:08:10 +01:00
|
|
|
typename context_t::return_t dispatch (context_t *c) const
|
2015-02-19 08:29:41 +01:00
|
|
|
{
|
|
|
|
TRACE_DISPATCH (this, format);
|
2015-10-09 18:25:55 +02:00
|
|
|
if (unlikely (!c->may_dispatch (this, this))) return_trace (c->no_dispatch_return_value ());
|
2018-09-04 01:53:03 +02:00
|
|
|
return_trace (get_subtable<typename T::SubTable> ().dispatch (c, get_type ()));
|
2015-02-19 08:29:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* This is called from may_dispatch() above with hb_sanitize_context_t. */
|
2018-12-16 20:08:10 +01:00
|
|
|
bool sanitize (hb_sanitize_context_t *c) const
|
2015-02-17 15:27:44 +01:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_SANITIZE (this);
|
2018-01-16 02:44:10 +01:00
|
|
|
return_trace (c->check_struct (this) &&
|
|
|
|
extensionOffset != 0 &&
|
2018-09-04 01:53:03 +02:00
|
|
|
extensionLookupType != T::SubTable::Extension);
|
2009-08-04 06:58:28 +02:00
|
|
|
}
|
|
|
|
|
2012-07-24 21:40:37 +02:00
|
|
|
protected:
|
2018-01-10 03:07:30 +01:00
|
|
|
HBUINT16 format; /* Format identifier. Set to 1. */
|
|
|
|
HBUINT16 extensionLookupType; /* Lookup type of subtable referenced
|
2009-05-22 04:31:33 +02:00
|
|
|
* by ExtensionOffset (i.e. the
|
|
|
|
* extension subtable). */
|
2018-01-16 02:34:05 +01:00
|
|
|
HBUINT32 extensionOffset; /* Offset to the extension subtable,
|
2010-04-22 06:58:49 +02:00
|
|
|
* of lookup type subtable. */
|
2010-05-10 22:57:29 +02:00
|
|
|
public:
|
|
|
|
DEFINE_SIZE_STATIC (8);
|
2009-05-22 04:31:33 +02:00
|
|
|
};
|
|
|
|
|
2012-11-23 22:57:36 +01:00
|
|
|
template <typename T>
|
2009-05-22 04:31:33 +02:00
|
|
|
struct Extension
|
|
|
|
{
|
2018-12-17 19:01:01 +01:00
|
|
|
unsigned int get_type () const
|
2009-05-22 04:31:33 +02:00
|
|
|
{
|
|
|
|
switch (u.format) {
|
2010-05-11 01:45:41 +02:00
|
|
|
case 1: return u.format1.get_type ();
|
2009-05-22 04:31:33 +02:00
|
|
|
default:return 0;
|
|
|
|
}
|
|
|
|
}
|
2012-11-23 23:04:55 +01:00
|
|
|
template <typename X>
|
2018-12-17 19:01:01 +01:00
|
|
|
const X& get_subtable () const
|
2012-11-23 23:04:55 +01:00
|
|
|
{
|
2015-02-19 08:29:41 +01:00
|
|
|
switch (u.format) {
|
2018-09-04 01:53:03 +02:00
|
|
|
case 1: return u.format1.template get_subtable<typename T::SubTable> ();
|
|
|
|
default:return Null(typename T::SubTable);
|
2015-02-19 08:29:41 +01:00
|
|
|
}
|
2012-11-23 23:04:55 +01:00
|
|
|
}
|
|
|
|
|
2012-11-23 22:57:36 +01:00
|
|
|
template <typename context_t>
|
2018-12-16 20:08:10 +01:00
|
|
|
typename context_t::return_t dispatch (context_t *c) const
|
2012-11-23 22:57:36 +01:00
|
|
|
{
|
2015-02-19 08:29:41 +01:00
|
|
|
TRACE_DISPATCH (this, u.format);
|
2015-10-09 18:25:55 +02:00
|
|
|
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
|
2009-08-04 06:58:28 +02:00
|
|
|
switch (u.format) {
|
2015-09-29 15:57:02 +02:00
|
|
|
case 1: return_trace (u.format1.dispatch (c));
|
|
|
|
default:return_trace (c->default_return_value ());
|
2009-08-04 06:58:28 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-24 21:40:37 +02:00
|
|
|
protected:
|
2009-05-22 04:31:33 +02:00
|
|
|
union {
|
2018-01-10 03:07:30 +01:00
|
|
|
HBUINT16 format; /* Format identifier */
|
2015-02-19 08:29:41 +01:00
|
|
|
ExtensionFormat1<T> format1;
|
2009-05-22 04:31:33 +02:00
|
|
|
} u;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2009-05-18 02:13:02 +02:00
|
|
|
/*
|
|
|
|
* GSUB/GPOS Common
|
|
|
|
*/
|
|
|
|
|
2018-10-10 17:41:05 +02:00
|
|
|
struct hb_ot_layout_lookup_accelerator_t
|
|
|
|
{
|
|
|
|
template <typename TLookup>
|
2018-12-16 20:08:10 +01:00
|
|
|
void init (const TLookup &lookup)
|
2018-10-10 17:41:05 +02:00
|
|
|
{
|
|
|
|
digest.init ();
|
|
|
|
lookup.add_coverage (&digest);
|
2018-10-10 17:50:46 +02:00
|
|
|
|
|
|
|
subtables.init ();
|
|
|
|
OT::hb_get_subtables_context_t c_get_subtables (subtables);
|
|
|
|
lookup.dispatch (&c_get_subtables);
|
|
|
|
}
|
2018-12-17 19:01:01 +01:00
|
|
|
void fini () { subtables.fini (); }
|
2018-10-10 17:41:05 +02:00
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool may_have (hb_codepoint_t g) const
|
2018-10-10 17:41:05 +02:00
|
|
|
{ return digest.may_have (g); }
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool apply (hb_ot_apply_context_t *c) const
|
2018-10-10 17:54:48 +02:00
|
|
|
{
|
2018-12-22 00:46:51 +01:00
|
|
|
for (unsigned int i = 0; i < subtables.length; i++)
|
2018-11-15 20:40:56 +01:00
|
|
|
if (subtables[i].apply (c))
|
|
|
|
return true;
|
|
|
|
return false;
|
2018-10-10 17:54:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2018-10-10 17:41:05 +02:00
|
|
|
hb_set_digest_t digest;
|
2018-10-10 17:50:46 +02:00
|
|
|
hb_get_subtables_context_t::array_t subtables;
|
2018-10-10 17:41:05 +02:00
|
|
|
};
|
|
|
|
|
2009-05-20 05:58:54 +02:00
|
|
|
struct GSUBGPOS
|
|
|
|
{
|
2018-12-17 19:01:01 +01:00
|
|
|
bool has_data () const { return version.to_int (); }
|
|
|
|
unsigned int get_script_count () const
|
2009-08-08 01:46:30 +02:00
|
|
|
{ return (this+scriptList).len; }
|
2018-12-16 20:08:10 +01:00
|
|
|
const Tag& get_script_tag (unsigned int i) const
|
2009-08-08 01:46:30 +02:00
|
|
|
{ return (this+scriptList).get_tag (i); }
|
2018-12-16 20:08:10 +01:00
|
|
|
unsigned int get_script_tags (unsigned int start_offset,
|
|
|
|
unsigned int *script_count /* IN/OUT */,
|
|
|
|
hb_tag_t *script_tags /* OUT */) const
|
2009-11-04 22:36:14 +01:00
|
|
|
{ return (this+scriptList).get_tags (start_offset, script_count, script_tags); }
|
2018-12-16 20:08:10 +01:00
|
|
|
const Script& get_script (unsigned int i) const
|
2009-08-08 01:46:30 +02:00
|
|
|
{ return (this+scriptList)[i]; }
|
2018-12-16 20:08:10 +01:00
|
|
|
bool find_script_index (hb_tag_t tag, unsigned int *index) const
|
2009-08-08 01:46:30 +02:00
|
|
|
{ return (this+scriptList).find_index (tag, index); }
|
|
|
|
|
2018-12-17 19:01:01 +01:00
|
|
|
unsigned int get_feature_count () const
|
2009-08-08 01:46:30 +02:00
|
|
|
{ return (this+featureList).len; }
|
2018-12-16 20:08:10 +01:00
|
|
|
hb_tag_t get_feature_tag (unsigned int i) const
|
2014-04-27 15:05:24 +02:00
|
|
|
{ return i == Index::NOT_FOUND_INDEX ? HB_TAG_NONE : (this+featureList).get_tag (i); }
|
2018-12-16 20:08:10 +01:00
|
|
|
unsigned int get_feature_tags (unsigned int start_offset,
|
|
|
|
unsigned int *feature_count /* IN/OUT */,
|
|
|
|
hb_tag_t *feature_tags /* OUT */) const
|
2009-11-04 22:36:14 +01:00
|
|
|
{ return (this+featureList).get_tags (start_offset, feature_count, feature_tags); }
|
2018-12-16 20:08:10 +01:00
|
|
|
const Feature& get_feature (unsigned int i) const
|
2009-08-08 01:46:30 +02:00
|
|
|
{ return (this+featureList)[i]; }
|
2018-12-16 20:08:10 +01:00
|
|
|
bool find_feature_index (hb_tag_t tag, unsigned int *index) const
|
2009-08-08 01:46:30 +02:00
|
|
|
{ return (this+featureList).find_index (tag, index); }
|
|
|
|
|
2018-12-17 19:01:01 +01:00
|
|
|
unsigned int get_lookup_count () const
|
2009-08-08 01:46:30 +02:00
|
|
|
{ return (this+lookupList).len; }
|
2018-12-16 20:08:10 +01:00
|
|
|
const Lookup& get_lookup (unsigned int i) const
|
2009-08-08 01:46:30 +02:00
|
|
|
{ return (this+lookupList)[i]; }
|
2009-05-18 02:13:02 +02:00
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool find_variations_index (const int *coords, unsigned int num_coords,
|
|
|
|
unsigned int *index) const
|
2016-09-10 10:24:28 +02:00
|
|
|
{ return (version.to_int () >= 0x00010001u ? this+featureVars : Null(FeatureVariations))
|
2016-09-10 12:32:39 +02:00
|
|
|
.find_index (coords, num_coords, index); }
|
2018-12-16 20:08:10 +01:00
|
|
|
const Feature& get_feature_variation (unsigned int feature_index,
|
2019-01-22 12:02:06 +01:00
|
|
|
unsigned int variations_index) const
|
2016-09-10 12:53:11 +02:00
|
|
|
{
|
|
|
|
if (FeatureVariations::NOT_FOUND_INDEX != variations_index &&
|
|
|
|
version.to_int () >= 0x00010001u)
|
|
|
|
{
|
2016-09-10 13:52:34 +02:00
|
|
|
const Feature *feature = (this+featureVars).find_substitute (variations_index,
|
|
|
|
feature_index);
|
2016-09-10 12:53:11 +02:00
|
|
|
if (feature)
|
2018-11-15 20:40:56 +01:00
|
|
|
return *feature;
|
2016-09-10 12:53:11 +02:00
|
|
|
}
|
|
|
|
return get_feature (feature_index);
|
|
|
|
}
|
2016-09-10 10:24:28 +02:00
|
|
|
|
2018-09-04 01:53:03 +02:00
|
|
|
template <typename TLookup>
|
2018-12-16 20:08:10 +01:00
|
|
|
bool subset (hb_subset_context_t *c) const
|
2018-09-02 03:34:50 +02:00
|
|
|
{
|
|
|
|
TRACE_SUBSET (this);
|
|
|
|
struct GSUBGPOS *out = c->serializer->embed (*this);
|
|
|
|
if (unlikely (!out)) return_trace (false);
|
2018-12-14 00:10:48 +01:00
|
|
|
|
2018-09-04 01:37:17 +02:00
|
|
|
out->scriptList.serialize_subset (c, this+scriptList, out);
|
|
|
|
out->featureList.serialize_subset (c, this+featureList, out);
|
2018-09-04 01:53:03 +02:00
|
|
|
|
|
|
|
typedef OffsetListOf<TLookup> TLookupList;
|
|
|
|
/* TODO Use intersects() to count how many subtables survive? */
|
|
|
|
CastR<OffsetTo<TLookupList> > (out->lookupList)
|
|
|
|
.serialize_subset (c,
|
|
|
|
this+CastR<const OffsetTo<TLookupList> > (lookupList),
|
|
|
|
out);
|
|
|
|
|
2018-09-02 03:34:50 +02:00
|
|
|
if (version.to_int () >= 0x00010001u)
|
2018-09-04 01:37:17 +02:00
|
|
|
out->featureVars.serialize_subset (c, this+featureVars, out);
|
2018-12-14 00:10:48 +01:00
|
|
|
|
2018-09-02 03:34:50 +02:00
|
|
|
return_trace (true);
|
|
|
|
}
|
|
|
|
|
2018-12-17 19:01:01 +01:00
|
|
|
unsigned int get_size () const
|
2018-09-02 03:34:50 +02:00
|
|
|
{
|
|
|
|
return min_size +
|
|
|
|
(version.to_int () >= 0x00010001u ? featureVars.static_size : 0);
|
|
|
|
}
|
|
|
|
|
2018-09-04 01:41:28 +02:00
|
|
|
template <typename TLookup>
|
2018-12-16 20:08:10 +01:00
|
|
|
bool sanitize (hb_sanitize_context_t *c) const
|
2015-02-17 15:27:44 +01:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_SANITIZE (this);
|
2018-09-04 01:41:28 +02:00
|
|
|
typedef OffsetListOf<TLookup> TLookupList;
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (version.sanitize (c) &&
|
|
|
|
likely (version.major == 1) &&
|
|
|
|
scriptList.sanitize (c, this) &&
|
|
|
|
featureList.sanitize (c, this) &&
|
2018-09-04 01:41:28 +02:00
|
|
|
CastR<OffsetTo<TLookupList> > (lookupList).sanitize (c, this) &&
|
2016-09-10 10:24:28 +02:00
|
|
|
(version.to_int () < 0x00010001u || featureVars.sanitize (c, this)));
|
2009-08-04 08:09:34 +02:00
|
|
|
}
|
|
|
|
|
2018-08-26 09:47:55 +02:00
|
|
|
template <typename T>
|
|
|
|
struct accelerator_t
|
|
|
|
{
|
2018-12-16 20:08:10 +01:00
|
|
|
void init (hb_face_t *face)
|
2018-08-26 09:47:55 +02:00
|
|
|
{
|
2018-11-11 05:52:15 +01:00
|
|
|
this->table = hb_sanitize_context_t().reference_table<T> (face);
|
2018-11-25 22:51:22 +01:00
|
|
|
if (unlikely (this->table->is_blacklisted (this->table.get_blob (), face)))
|
|
|
|
{
|
|
|
|
hb_blob_destroy (this->table.get_blob ());
|
|
|
|
this->table = hb_blob_get_empty ();
|
|
|
|
}
|
2018-08-26 09:47:55 +02:00
|
|
|
|
2018-08-26 10:15:47 +02:00
|
|
|
this->lookup_count = table->get_lookup_count ();
|
2018-08-26 09:47:55 +02:00
|
|
|
|
|
|
|
this->accels = (hb_ot_layout_lookup_accelerator_t *) calloc (this->lookup_count, sizeof (hb_ot_layout_lookup_accelerator_t));
|
|
|
|
if (unlikely (!this->accels))
|
2018-11-15 20:40:56 +01:00
|
|
|
this->lookup_count = 0;
|
2018-08-26 09:47:55 +02:00
|
|
|
|
|
|
|
for (unsigned int i = 0; i < this->lookup_count; i++)
|
2018-08-26 10:15:47 +02:00
|
|
|
this->accels[i].init (table->get_lookup (i));
|
2018-08-26 09:47:55 +02:00
|
|
|
}
|
|
|
|
|
2018-12-17 19:01:01 +01:00
|
|
|
void fini ()
|
2018-08-26 09:47:55 +02:00
|
|
|
{
|
2018-08-26 10:15:47 +02:00
|
|
|
for (unsigned int i = 0; i < this->lookup_count; i++)
|
|
|
|
this->accels[i].fini ();
|
|
|
|
free (this->accels);
|
2018-11-11 17:40:57 +01:00
|
|
|
this->table.destroy ();
|
2018-08-26 09:47:55 +02:00
|
|
|
}
|
|
|
|
|
2018-11-11 05:52:15 +01:00
|
|
|
hb_blob_ptr_t<T> table;
|
2018-08-26 10:15:47 +02:00
|
|
|
unsigned int lookup_count;
|
|
|
|
hb_ot_layout_lookup_accelerator_t *accels;
|
2018-08-26 09:47:55 +02:00
|
|
|
};
|
|
|
|
|
2009-05-24 06:50:27 +02:00
|
|
|
protected:
|
2016-02-22 03:44:45 +01:00
|
|
|
FixedVersion<>version; /* Version of the GSUB/GPOS table--initially set
|
2014-07-11 20:54:42 +02:00
|
|
|
* to 0x00010000u */
|
2009-05-18 02:13:02 +02:00
|
|
|
OffsetTo<ScriptList>
|
|
|
|
scriptList; /* ScriptList table */
|
|
|
|
OffsetTo<FeatureList>
|
|
|
|
featureList; /* FeatureList table */
|
|
|
|
OffsetTo<LookupList>
|
|
|
|
lookupList; /* LookupList table */
|
2017-01-23 05:28:56 +01:00
|
|
|
LOffsetTo<FeatureVariations>
|
2016-09-10 10:24:28 +02:00
|
|
|
featureVars; /* Offset to Feature Variations
|
|
|
|
table--from beginning of table
|
|
|
|
* (may be NULL). Introduced
|
|
|
|
* in version 0x00010001. */
|
2010-05-10 22:57:29 +02:00
|
|
|
public:
|
2016-09-10 10:24:28 +02:00
|
|
|
DEFINE_SIZE_MIN (10);
|
2009-05-18 02:13:02 +02:00
|
|
|
};
|
2009-05-17 14:28:42 +02:00
|
|
|
|
2009-05-18 02:28:01 +02:00
|
|
|
|
2012-11-17 03:49:54 +01:00
|
|
|
} /* namespace OT */
|
2012-08-28 23:57:49 +02:00
|
|
|
|
2010-07-23 21:11:18 +02:00
|
|
|
|
2018-08-26 07:36:36 +02:00
|
|
|
#endif /* HB_OT_LAYOUT_GSUBGPOS_HH */
|