2008-01-23 23:01:55 +01:00
|
|
|
/*
|
2011-04-21 23:14:28 +02:00
|
|
|
* Copyright © 2007,2008,2009,2010 Red Hat, Inc.
|
2013-04-24 22:42:05 +02:00
|
|
|
* Copyright © 2010,2012,2013 Google, Inc.
|
2008-01-23 23:01:55 +01:00
|
|
|
*
|
2010-04-22 06:11:43 +02:00
|
|
|
* This is part of HarfBuzz, a text shaping library.
|
2008-01-23 23:01:55 +01: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
|
2008-01-23 23:01:55 +01:00
|
|
|
*/
|
|
|
|
|
2011-08-17 14:19:59 +02:00
|
|
|
#ifndef HB_OT_LAYOUT_GSUB_TABLE_HH
|
|
|
|
#define HB_OT_LAYOUT_GSUB_TABLE_HH
|
2008-01-23 23:01:55 +01:00
|
|
|
|
2018-08-26 07:36:36 +02:00
|
|
|
#include "hb-ot-layout-gsubgpos.hh"
|
2008-01-23 23:01:55 +01:00
|
|
|
|
2010-07-23 21:11:18 +02:00
|
|
|
|
2012-08-28 23:57:49 +02:00
|
|
|
namespace OT {
|
|
|
|
|
2019-05-09 22:04:11 +02:00
|
|
|
typedef hb_pair_t<hb_codepoint_t, hb_codepoint_t> hb_codepoint_pair_t;
|
2009-05-18 02:28:01 +02:00
|
|
|
|
2019-05-16 04:07:39 +02:00
|
|
|
template<typename Iterator>
|
2018-09-04 05:50:11 +02:00
|
|
|
static inline void SingleSubst_serialize (hb_serialize_context_t *c,
|
2019-05-09 22:04:11 +02:00
|
|
|
Iterator it);
|
|
|
|
|
2018-09-04 05:50:11 +02:00
|
|
|
|
2009-05-20 05:42:30 +02:00
|
|
|
struct SingleSubstFormat1
|
|
|
|
{
|
2018-12-16 20:08:10 +01:00
|
|
|
bool intersects (const hb_set_t *glyphs) const
|
2018-09-03 04:47:50 +02:00
|
|
|
{ return (this+coverage).intersects (glyphs); }
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
void closure (hb_closure_context_t *c) const
|
2012-04-23 19:04:38 +02:00
|
|
|
{
|
2019-05-16 03:15:05 +02:00
|
|
|
unsigned d = deltaGlyphID;
|
2019-03-30 05:16:30 +01:00
|
|
|
+ hb_iter (this+coverage)
|
|
|
|
| hb_filter (*c->glyphs)
|
2019-05-16 03:15:05 +02:00
|
|
|
| hb_map ([d] (hb_codepoint_t g) { return (g + d) & 0xFFFFu; })
|
2019-03-30 05:16:30 +01:00
|
|
|
| hb_sink (c->output)
|
|
|
|
;
|
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-17 04:07:06 +01:00
|
|
|
{
|
2017-12-16 15:12:06 +01:00
|
|
|
if (unlikely (!(this+coverage).add_coverage (c->input))) return;
|
2019-05-16 03:15:05 +02:00
|
|
|
unsigned d = deltaGlyphID;
|
2019-03-30 05:16:30 +01:00
|
|
|
+ hb_iter (this+coverage)
|
2019-05-16 03:15:05 +02:00
|
|
|
| hb_map ([d] (hb_codepoint_t g) { return (g + d) & 0xFFFFu; })
|
2019-03-30 05:16:30 +01:00
|
|
|
| hb_sink (c->output)
|
|
|
|
;
|
2012-11-17 04:07:06 +01:00
|
|
|
}
|
|
|
|
|
2018-12-17 19:01:01 +01:00
|
|
|
const Coverage &get_coverage () const { return this+coverage; }
|
2012-07-28 23:31:01 +02:00
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool would_apply (hb_would_apply_context_t *c) const
|
2019-03-30 06:12:42 +01:00
|
|
|
{ return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
|
2012-11-22 20:38:10 +01:00
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool apply (hb_ot_apply_context_t *c) const
|
2009-05-20 05:42:30 +02:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_APPLY (this);
|
2012-05-13 15:45:18 +02:00
|
|
|
hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
|
2012-11-25 01:13:55 +01:00
|
|
|
unsigned int index = (this+coverage).get_coverage (glyph_id);
|
2015-09-29 15:57:02 +02:00
|
|
|
if (likely (index == NOT_COVERED)) return_trace (false);
|
2009-04-16 04:56:15 +02:00
|
|
|
|
2011-09-27 18:38:16 +02:00
|
|
|
/* According to the Adobe Annotated OpenType Suite, result is always
|
|
|
|
* limited to 16bit. */
|
2014-07-11 20:54:42 +02:00
|
|
|
glyph_id = (glyph_id + deltaGlyphID) & 0xFFFFu;
|
2010-10-27 23:39:01 +02:00
|
|
|
c->replace_glyph (glyph_id);
|
2009-04-16 04:56:15 +02:00
|
|
|
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (true);
|
2009-04-16 10:45:30 +02:00
|
|
|
}
|
2009-04-16 04:56:15 +02:00
|
|
|
|
2019-05-09 22:04:11 +02:00
|
|
|
template<typename Iterator,
|
2019-06-01 00:38:11 +02:00
|
|
|
hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
|
2018-12-16 20:08:10 +01:00
|
|
|
bool serialize (hb_serialize_context_t *c,
|
2019-05-09 22:04:11 +02:00
|
|
|
Iterator glyphs,
|
2019-04-24 16:24:33 +02:00
|
|
|
unsigned delta)
|
2012-09-02 02:48:22 +02:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_SERIALIZE (this);
|
2015-09-29 15:57:02 +02:00
|
|
|
if (unlikely (!c->extend_min (*this))) return_trace (false);
|
2018-12-18 22:49:08 +01:00
|
|
|
if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs))) return_trace (false);
|
2019-04-24 16:07:19 +02:00
|
|
|
c->check_assign (deltaGlyphID, delta);
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (true);
|
2012-09-02 02:48:22 +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);
|
2019-05-21 00:04:20 +02:00
|
|
|
const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
|
2018-12-12 04:53:58 +01:00
|
|
|
const hb_map_t &glyph_map = *c->plan->glyph_map;
|
2019-03-30 05:46:13 +01:00
|
|
|
|
2018-09-04 03:23:23 +02:00
|
|
|
hb_codepoint_t delta = deltaGlyphID;
|
2019-03-30 05:46:13 +01:00
|
|
|
|
2019-05-09 22:04:11 +02:00
|
|
|
auto it =
|
2019-03-30 05:46:13 +01:00
|
|
|
+ hb_iter (this+coverage)
|
|
|
|
| hb_filter (glyphset)
|
2019-05-09 22:04:11 +02:00
|
|
|
| hb_map_retains_sorting ([&] (hb_codepoint_t g) {
|
2019-08-29 22:40:46 +02:00
|
|
|
return hb_codepoint_pair_t (g,
|
|
|
|
(g + delta) & 0xFFFF); })
|
|
|
|
| hb_filter (glyphset, hb_second)
|
|
|
|
| hb_map_retains_sorting ([&] (hb_codepoint_pair_t p) -> hb_codepoint_pair_t
|
|
|
|
{ return hb_pair (glyph_map[p.first], glyph_map[p.second]); })
|
2019-05-09 22:04:11 +02:00
|
|
|
;
|
2019-03-30 05:46:13 +01:00
|
|
|
|
2019-05-16 22:05:58 +02:00
|
|
|
bool ret = bool (it);
|
2019-05-09 22:04:11 +02:00
|
|
|
SingleSubst_serialize (c->serializer, it);
|
2019-05-16 22:05:58 +02:00
|
|
|
return_trace (ret);
|
2018-09-04 02:33:34 +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 (coverage.sanitize (c, this) && deltaGlyphID.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 = 1 */
|
2009-05-17 06:22:37 +02:00
|
|
|
OffsetTo<Coverage>
|
|
|
|
coverage; /* Offset to Coverage table--from
|
2008-01-23 23:01:55 +01:00
|
|
|
* beginning of Substitution table */
|
2019-04-24 16:24:33 +02:00
|
|
|
HBUINT16 deltaGlyphID; /* Add to original GlyphID to get
|
|
|
|
* substitute GlyphID, modulo 0x10000 */
|
2010-05-10 22:57:29 +02:00
|
|
|
public:
|
|
|
|
DEFINE_SIZE_STATIC (6);
|
2008-01-23 23:01:55 +01:00
|
|
|
};
|
|
|
|
|
2009-05-20 05:42:30 +02:00
|
|
|
struct SingleSubstFormat2
|
|
|
|
{
|
2018-12-16 20:08:10 +01:00
|
|
|
bool intersects (const hb_set_t *glyphs) const
|
2018-09-03 04:47:50 +02:00
|
|
|
{ return (this+coverage).intersects (glyphs); }
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
void closure (hb_closure_context_t *c) const
|
2012-04-23 19:04:38 +02:00
|
|
|
{
|
2019-02-14 19:40:05 +01:00
|
|
|
+ hb_zip (this+coverage, substitute)
|
|
|
|
| hb_filter (*c->glyphs, hb_first)
|
|
|
|
| hb_map (hb_second)
|
2019-02-14 20:03:29 +01:00
|
|
|
| hb_sink (c->output)
|
2019-02-14 19:51:47 +01:00
|
|
|
;
|
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-17 04:07:06 +01:00
|
|
|
{
|
2017-12-16 15:12:06 +01:00
|
|
|
if (unlikely (!(this+coverage).add_coverage (c->input))) return;
|
2019-02-14 19:40:05 +01:00
|
|
|
+ hb_zip (this+coverage, substitute)
|
|
|
|
| hb_map (hb_second)
|
2019-02-14 20:03:29 +01:00
|
|
|
| hb_sink (c->output)
|
2019-02-14 19:51:47 +01:00
|
|
|
;
|
2012-11-17 04:07:06 +01:00
|
|
|
}
|
|
|
|
|
2018-12-17 19:01:01 +01:00
|
|
|
const Coverage &get_coverage () const { return this+coverage; }
|
2012-07-28 23:31:01 +02:00
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool would_apply (hb_would_apply_context_t *c) const
|
2019-03-30 06:12:42 +01:00
|
|
|
{ return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
|
2012-11-22 20:38:10 +01:00
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool apply (hb_ot_apply_context_t *c) const
|
2009-05-20 05:42:30 +02:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_APPLY (this);
|
2018-09-03 04:47:50 +02: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-04-16 10:45:30 +02:00
|
|
|
|
2015-09-29 15:57:02 +02:00
|
|
|
if (unlikely (index >= substitute.len)) return_trace (false);
|
2009-04-16 10:45:30 +02:00
|
|
|
|
2018-09-03 04:47:50 +02:00
|
|
|
c->replace_glyph (substitute[index]);
|
2009-05-20 05:42:30 +02:00
|
|
|
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (true);
|
2009-04-16 10:45:30 +02:00
|
|
|
}
|
2008-01-23 23:01:55 +01:00
|
|
|
|
2019-05-09 22:04:11 +02:00
|
|
|
template<typename Iterator,
|
2019-05-16 03:52:57 +02:00
|
|
|
hb_requires (hb_is_sorted_source_of (Iterator,
|
2019-06-01 00:48:54 +02:00
|
|
|
hb_codepoint_pair_t))>
|
2018-12-16 20:08:10 +01:00
|
|
|
bool serialize (hb_serialize_context_t *c,
|
2019-05-09 22:04:11 +02:00
|
|
|
Iterator it)
|
2012-09-02 03:43:38 +02:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_SERIALIZE (this);
|
2019-05-09 22:04:11 +02:00
|
|
|
auto substitutes =
|
|
|
|
+ it
|
|
|
|
| hb_map (hb_second)
|
|
|
|
;
|
|
|
|
auto glyphs =
|
|
|
|
+ it
|
|
|
|
| hb_map_retains_sorting (hb_first)
|
|
|
|
;
|
2015-09-29 15:57:02 +02:00
|
|
|
if (unlikely (!c->extend_min (*this))) return_trace (false);
|
2018-12-18 22:49:08 +01:00
|
|
|
if (unlikely (!substitute.serialize (c, substitutes))) return_trace (false);
|
|
|
|
if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs))) return_trace (false);
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (true);
|
2012-09-02 03:43:38 +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);
|
2019-05-21 00:04:20 +02:00
|
|
|
const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
|
2018-12-12 04:53:58 +01:00
|
|
|
const hb_map_t &glyph_map = *c->plan->glyph_map;
|
2019-03-30 05:46:13 +01:00
|
|
|
|
2019-05-09 22:04:11 +02:00
|
|
|
auto it =
|
2019-03-30 05:46:13 +01:00
|
|
|
+ hb_zip (this+coverage, substitute)
|
|
|
|
| hb_filter (glyphset, hb_first)
|
2019-08-29 22:40:46 +02:00
|
|
|
| hb_filter (glyphset, hb_second)
|
2019-09-14 08:06:29 +02:00
|
|
|
| hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, const HBGlyphID &> p) -> hb_codepoint_pair_t
|
2019-05-16 22:22:09 +02:00
|
|
|
{ return hb_pair (glyph_map[p.first], glyph_map[p.second]); })
|
2019-05-09 22:04:11 +02:00
|
|
|
;
|
2019-03-30 05:46:13 +01:00
|
|
|
|
2019-05-16 22:05:58 +02:00
|
|
|
bool ret = bool (it);
|
2019-05-09 22:04:11 +02:00
|
|
|
SingleSubst_serialize (c->serializer, it);
|
2019-05-16 22:05:58 +02:00
|
|
|
return_trace (ret);
|
2018-09-04 02:33:34 +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 (coverage.sanitize (c, this) && substitute.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 = 2 */
|
2009-05-17 06:22:37 +02:00
|
|
|
OffsetTo<Coverage>
|
|
|
|
coverage; /* Offset to Coverage table--from
|
2008-01-23 23:01:55 +01:00
|
|
|
* beginning of Substitution table */
|
2019-09-14 08:06:29 +02:00
|
|
|
ArrayOf<HBGlyphID>
|
2009-05-17 07:22:51 +02:00
|
|
|
substitute; /* Array of substitute
|
|
|
|
* GlyphIDs--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, substitute);
|
2008-01-23 23:01:55 +01:00
|
|
|
};
|
|
|
|
|
2009-05-20 05:42:30 +02:00
|
|
|
struct SingleSubst
|
|
|
|
{
|
2019-05-09 22:04:11 +02:00
|
|
|
|
|
|
|
template<typename Iterator,
|
2019-05-16 03:52:57 +02:00
|
|
|
hb_requires (hb_is_sorted_source_of (Iterator,
|
|
|
|
const hb_codepoint_pair_t))>
|
2018-12-16 20:08:10 +01:00
|
|
|
bool serialize (hb_serialize_context_t *c,
|
2019-05-09 22:04:11 +02:00
|
|
|
Iterator glyphs)
|
2012-09-02 03:43:38 +02:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_SERIALIZE (this);
|
2015-09-29 15:57:02 +02:00
|
|
|
if (unlikely (!c->extend_min (u.format))) return_trace (false);
|
2019-04-24 16:01:30 +02:00
|
|
|
unsigned format = 2;
|
|
|
|
unsigned delta = 0;
|
2019-07-26 23:34:26 +02:00
|
|
|
if (glyphs)
|
2018-12-18 22:49:08 +01:00
|
|
|
{
|
2012-09-02 03:43:38 +02:00
|
|
|
format = 1;
|
2019-05-09 22:04:11 +02:00
|
|
|
auto get_delta = [=] (hb_codepoint_pair_t _) {
|
|
|
|
return (unsigned) (_.second - _.first) & 0xFFFF;
|
|
|
|
};
|
|
|
|
delta = get_delta (*glyphs);
|
|
|
|
if (!hb_all (++(+glyphs), delta, get_delta)) format = 2;
|
2012-09-02 03:43:38 +02:00
|
|
|
}
|
2019-03-30 04:17:46 +01:00
|
|
|
u.format = format;
|
2012-09-02 03:43:38 +02:00
|
|
|
switch (u.format) {
|
2019-05-09 22:04:11 +02:00
|
|
|
case 1: return_trace (u.format1.serialize (c,
|
2019-05-16 22:22:09 +02:00
|
|
|
+ glyphs
|
|
|
|
| hb_map_retains_sorting (hb_first),
|
|
|
|
delta));
|
2019-05-09 22:04:11 +02:00
|
|
|
case 2: return_trace (u.format2.serialize (c, glyphs));
|
2015-09-29 15:57:02 +02:00
|
|
|
default:return_trace (false);
|
2012-09-02 03:43:38 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-05 19:14:17 +02:00
|
|
|
template <typename context_t, typename ...Ts>
|
2019-05-08 05:58:43 +02:00
|
|
|
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
|
2013-03-09 07:59:30 +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 ());
|
2013-03-09 07:59:30 +01:00
|
|
|
switch (u.format) {
|
2019-05-05 19:14:17 +02:00
|
|
|
case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
|
|
|
|
case 2: return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
|
2015-09-29 15:57:02 +02:00
|
|
|
default:return_trace (c->default_return_value ());
|
2013-03-09 07:59:30 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-24 21:40:37 +02:00
|
|
|
protected:
|
2009-04-16 10:45:30 +02:00
|
|
|
union {
|
2018-01-10 03:07:30 +01:00
|
|
|
HBUINT16 format; /* Format identifier */
|
2010-05-11 01:45:41 +02:00
|
|
|
SingleSubstFormat1 format1;
|
|
|
|
SingleSubstFormat2 format2;
|
2009-04-16 10:45:30 +02:00
|
|
|
} u;
|
2008-01-23 23:01:55 +01:00
|
|
|
};
|
2009-04-16 10:45:30 +02:00
|
|
|
|
2019-05-16 03:54:07 +02:00
|
|
|
template<typename Iterator>
|
2018-09-04 05:50:11 +02:00
|
|
|
static inline void
|
|
|
|
SingleSubst_serialize (hb_serialize_context_t *c,
|
2019-05-09 22:04:11 +02:00
|
|
|
Iterator it)
|
|
|
|
{ c->start_embed<SingleSubst> ()->serialize (c, it); }
|
2008-01-23 23:01:55 +01:00
|
|
|
|
2009-05-20 05:42:30 +02:00
|
|
|
struct Sequence
|
|
|
|
{
|
2019-08-29 00:30:37 +02:00
|
|
|
bool intersects (const hb_set_t *glyphs) const
|
|
|
|
{ return hb_all (substitute, glyphs); }
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
void closure (hb_closure_context_t *c) const
|
2019-08-29 00:30:37 +02:00
|
|
|
{ c->output->add_array (substitute.arrayZ, substitute.len); }
|
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
|
2019-01-18 20:59:18 +01:00
|
|
|
{ c->output->add_array (substitute.arrayZ, substitute.len); }
|
2012-11-17 04:07:06 +01:00
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool apply (hb_ot_apply_context_t *c) const
|
2009-05-20 05:42:30 +02:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_APPLY (this);
|
2014-06-06 00:54:44 +02:00
|
|
|
unsigned int count = substitute.len;
|
2014-06-05 23:12:54 +02:00
|
|
|
|
2014-06-06 00:54:44 +02:00
|
|
|
/* Special-case to make it in-place and not consider this
|
|
|
|
* as a "multiplied" substitution. */
|
|
|
|
if (unlikely (count == 1))
|
2013-05-02 20:44:45 +02:00
|
|
|
{
|
2018-05-09 01:56:11 +02:00
|
|
|
c->replace_glyph (substitute.arrayZ[0]);
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (true);
|
2013-05-02 20:44:45 +02:00
|
|
|
}
|
2016-05-06 17:19:19 +02:00
|
|
|
/* Spec disallows this, but Uniscribe allows it.
|
2017-11-20 20:49:22 +01:00
|
|
|
* https://github.com/harfbuzz/harfbuzz/issues/253 */
|
2016-05-06 17:19:19 +02:00
|
|
|
else if (unlikely (count == 0))
|
|
|
|
{
|
|
|
|
c->buffer->delete_glyph ();
|
|
|
|
return_trace (true);
|
|
|
|
}
|
2014-06-06 00:54:44 +02:00
|
|
|
|
|
|
|
unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ?
|
|
|
|
HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0;
|
|
|
|
|
|
|
|
for (unsigned int i = 0; i < count; i++) {
|
|
|
|
_hb_glyph_info_set_lig_props_for_component (&c->buffer->cur(), i);
|
2018-05-09 01:56:11 +02:00
|
|
|
c->output_glyph_for_component (substitute.arrayZ[i], klass);
|
2012-06-09 03:47:23 +02:00
|
|
|
}
|
2014-06-06 00:54:44 +02:00
|
|
|
c->buffer->skip_glyph ();
|
2009-05-05 22:22:02 +02:00
|
|
|
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (true);
|
2009-05-05 22:22:02 +02:00
|
|
|
}
|
|
|
|
|
2019-06-01 00:38:11 +02:00
|
|
|
template <typename Iterator,
|
|
|
|
hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))>
|
2018-12-16 20:08:10 +01:00
|
|
|
bool serialize (hb_serialize_context_t *c,
|
2019-06-01 00:38:11 +02:00
|
|
|
Iterator subst)
|
2012-09-04 05:28:34 +02:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_SERIALIZE (this);
|
2019-01-08 00:33:04 +01:00
|
|
|
return_trace (substitute.serialize (c, subst));
|
2012-09-04 05:28:34 +02:00
|
|
|
}
|
|
|
|
|
2019-08-29 00:25:55 +02:00
|
|
|
bool subset (hb_subset_context_t *c) const
|
|
|
|
{
|
|
|
|
TRACE_SUBSET (this);
|
|
|
|
const hb_set_t &glyphset = *c->plan->glyphset ();
|
|
|
|
const hb_map_t &glyph_map = *c->plan->glyph_map;
|
|
|
|
|
2019-08-29 00:30:37 +02:00
|
|
|
if (!intersects (&glyphset)) return_trace (false);
|
2019-08-29 00:25:55 +02:00
|
|
|
|
|
|
|
auto it =
|
|
|
|
+ hb_iter (substitute)
|
|
|
|
| hb_map (glyph_map)
|
|
|
|
;
|
|
|
|
|
|
|
|
auto *out = c->serializer->start_embed (*this);
|
2019-08-29 00:38:46 +02:00
|
|
|
return_trace (out->serialize (c->serializer, it));
|
2019-08-29 00:25:55 +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 (substitute.sanitize (c));
|
2009-08-04 06:58:28 +02:00
|
|
|
}
|
|
|
|
|
2012-07-24 21:40:37 +02:00
|
|
|
protected:
|
2019-09-14 08:06:29 +02:00
|
|
|
ArrayOf<HBGlyphID>
|
2009-05-17 07:22:51 +02:00
|
|
|
substitute; /* String of GlyphIDs to substitute */
|
2010-05-10 22:57:29 +02:00
|
|
|
public:
|
2010-05-11 01:01:17 +02:00
|
|
|
DEFINE_SIZE_ARRAY (2, substitute);
|
2008-01-23 23:01:55 +01:00
|
|
|
};
|
|
|
|
|
2009-05-20 05:42:30 +02:00
|
|
|
struct MultipleSubstFormat1
|
|
|
|
{
|
2018-12-16 20:08:10 +01:00
|
|
|
bool intersects (const hb_set_t *glyphs) const
|
2018-09-03 04:47:50 +02:00
|
|
|
{ return (this+coverage).intersects (glyphs); }
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
void closure (hb_closure_context_t *c) const
|
2012-04-23 19:04:38 +02:00
|
|
|
{
|
2019-02-14 22:16:33 +01:00
|
|
|
+ hb_zip (this+coverage, sequence)
|
|
|
|
| hb_filter (*c->glyphs, hb_first)
|
|
|
|
| hb_map (hb_second)
|
2019-05-16 06:57:26 +02:00
|
|
|
| hb_map (hb_add (this))
|
|
|
|
| hb_apply ([c] (const Sequence &_) { _.closure (c); })
|
2019-02-14 22:16:33 +01:00
|
|
|
;
|
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-17 04:07:06 +01:00
|
|
|
{
|
2017-12-16 15:12:06 +01:00
|
|
|
if (unlikely (!(this+coverage).add_coverage (c->input))) return;
|
2019-02-14 22:16:33 +01:00
|
|
|
+ hb_zip (this+coverage, sequence)
|
|
|
|
| hb_map (hb_second)
|
2019-05-16 06:57:26 +02:00
|
|
|
| hb_map (hb_add (this))
|
|
|
|
| hb_apply ([c] (const Sequence &_) { _.collect_glyphs (c); })
|
2019-02-14 22:16:33 +01:00
|
|
|
;
|
2012-11-17 04:07:06 +01:00
|
|
|
}
|
|
|
|
|
2018-12-17 19:01:01 +01:00
|
|
|
const Coverage &get_coverage () const { return this+coverage; }
|
2012-07-28 23:31:01 +02:00
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool would_apply (hb_would_apply_context_t *c) const
|
2019-03-30 06:12:42 +01:00
|
|
|
{ return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
|
2012-11-22 20:38:10 +01:00
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool apply (hb_ot_apply_context_t *c) const
|
2009-05-20 05:42:30 +02:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_APPLY (this);
|
2009-04-16 10:45:30 +02:00
|
|
|
|
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
|
|
|
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace ((this+sequence[index]).apply (c));
|
2009-04-16 10:45:30 +02:00
|
|
|
}
|
2008-01-23 23:01:55 +01:00
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool serialize (hb_serialize_context_t *c,
|
2019-09-14 08:06:29 +02:00
|
|
|
hb_sorted_array_t<const HBGlyphID> glyphs,
|
2018-12-18 22:49:08 +01:00
|
|
|
hb_array_t<const unsigned int> substitute_len_list,
|
2019-09-14 08:06:29 +02:00
|
|
|
hb_array_t<const HBGlyphID> substitute_glyphs_list)
|
2012-09-04 05:28:34 +02:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_SERIALIZE (this);
|
2015-09-29 15:57:02 +02:00
|
|
|
if (unlikely (!c->extend_min (*this))) return_trace (false);
|
2018-12-22 00:46:51 +01:00
|
|
|
if (unlikely (!sequence.serialize (c, glyphs.length))) return_trace (false);
|
|
|
|
for (unsigned int i = 0; i < glyphs.length; i++)
|
2018-12-18 22:49:08 +01:00
|
|
|
{
|
|
|
|
unsigned int substitute_len = substitute_len_list[i];
|
|
|
|
if (unlikely (!sequence[i].serialize (c, this)
|
|
|
|
.serialize (c, substitute_glyphs_list.sub_array (0, substitute_len))))
|
|
|
|
return_trace (false);
|
|
|
|
substitute_glyphs_list += substitute_len;
|
|
|
|
}
|
|
|
|
return_trace (coverage.serialize (c, this).serialize (c, glyphs));
|
2012-09-04 05:28:34 +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);
|
2019-08-29 00:25:55 +02:00
|
|
|
const hb_set_t &glyphset = *c->plan->glyphset ();
|
|
|
|
const hb_map_t &glyph_map = *c->plan->glyph_map;
|
|
|
|
|
|
|
|
auto *out = c->serializer->start_embed (*this);
|
|
|
|
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
|
|
|
|
out->format = format;
|
|
|
|
|
|
|
|
hb_sorted_vector_t<hb_codepoint_t> new_coverage;
|
|
|
|
+ hb_zip (this+coverage, sequence)
|
|
|
|
| hb_filter (glyphset, hb_first)
|
2019-10-09 20:45:42 +02:00
|
|
|
| hb_filter (subset_offset_array (c, out->sequence, this, out), hb_second)
|
2019-08-29 00:25:55 +02:00
|
|
|
| hb_map (hb_first)
|
|
|
|
| hb_map (glyph_map)
|
2019-08-29 12:39:39 +02:00
|
|
|
| hb_sink (new_coverage)
|
2019-08-29 00:25:55 +02:00
|
|
|
;
|
|
|
|
out->coverage.serialize (c->serializer, out)
|
|
|
|
.serialize (c->serializer, new_coverage.iter ());
|
|
|
|
return_trace (bool (new_coverage));
|
2018-09-04 02:33:34 +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 (coverage.sanitize (c, this) && sequence.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 06:22:37 +02:00
|
|
|
OffsetTo<Coverage>
|
|
|
|
coverage; /* Offset to Coverage table--from
|
2008-01-23 23:01:55 +01:00
|
|
|
* beginning of Substitution table */
|
2009-05-17 07:22:51 +02:00
|
|
|
OffsetArrayOf<Sequence>
|
|
|
|
sequence; /* Array of Sequence 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, sequence);
|
2008-01-23 23:01:55 +01:00
|
|
|
};
|
2009-04-16 10:45:30 +02:00
|
|
|
|
2009-05-20 05:42:30 +02:00
|
|
|
struct MultipleSubst
|
|
|
|
{
|
2018-12-16 20:08:10 +01:00
|
|
|
bool serialize (hb_serialize_context_t *c,
|
2019-09-14 08:06:29 +02:00
|
|
|
hb_sorted_array_t<const HBGlyphID> glyphs,
|
2018-12-18 22:49:08 +01:00
|
|
|
hb_array_t<const unsigned int> substitute_len_list,
|
2019-09-14 08:06:29 +02:00
|
|
|
hb_array_t<const HBGlyphID> substitute_glyphs_list)
|
2012-09-04 05:28:34 +02:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_SERIALIZE (this);
|
2015-09-29 15:57:02 +02:00
|
|
|
if (unlikely (!c->extend_min (u.format))) return_trace (false);
|
2012-09-04 05:28:34 +02:00
|
|
|
unsigned int format = 1;
|
2019-03-30 04:17:46 +01:00
|
|
|
u.format = format;
|
2012-09-04 05:28:34 +02:00
|
|
|
switch (u.format) {
|
2018-12-18 22:49:08 +01:00
|
|
|
case 1: return_trace (u.format1.serialize (c, glyphs, substitute_len_list, substitute_glyphs_list));
|
2015-09-29 15:57:02 +02:00
|
|
|
default:return_trace (false);
|
2012-09-04 05:28:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-05 19:14:17 +02:00
|
|
|
template <typename context_t, typename ...Ts>
|
2019-05-08 05:58:43 +02:00
|
|
|
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
|
2013-03-09 07:59:30 +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 ());
|
2013-03-09 07:59:30 +01:00
|
|
|
switch (u.format) {
|
2019-05-05 19:14:17 +02:00
|
|
|
case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
|
2015-09-29 15:57:02 +02:00
|
|
|
default:return_trace (c->default_return_value ());
|
2013-03-09 07:59:30 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-24 21:40:37 +02:00
|
|
|
protected:
|
2009-04-16 10:45:30 +02:00
|
|
|
union {
|
2018-01-10 03:07:30 +01:00
|
|
|
HBUINT16 format; /* Format identifier */
|
2010-05-11 01:45:41 +02:00
|
|
|
MultipleSubstFormat1 format1;
|
2009-04-16 10:45:30 +02:00
|
|
|
} u;
|
|
|
|
};
|
|
|
|
|
2018-09-03 04:47:50 +02:00
|
|
|
struct AlternateSet
|
|
|
|
{
|
2019-08-29 00:38:46 +02:00
|
|
|
bool intersects (const hb_set_t *glyphs) const
|
|
|
|
{ return hb_any (alternates, glyphs); }
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
void closure (hb_closure_context_t *c) const
|
2019-08-29 00:30:37 +02:00
|
|
|
{ c->output->add_array (alternates.arrayZ, alternates.len); }
|
2018-09-03 04:47:50 +02:00
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
void collect_glyphs (hb_collect_glyphs_context_t *c) const
|
2019-01-18 20:59:18 +01:00
|
|
|
{ c->output->add_array (alternates.arrayZ, alternates.len); }
|
2018-09-03 04:47:50 +02:00
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool apply (hb_ot_apply_context_t *c) const
|
2018-09-03 04:47:50 +02:00
|
|
|
{
|
|
|
|
TRACE_APPLY (this);
|
|
|
|
unsigned int count = alternates.len;
|
|
|
|
|
|
|
|
if (unlikely (!count)) return_trace (false);
|
|
|
|
|
2018-09-10 16:36:05 +02:00
|
|
|
hb_mask_t glyph_mask = c->buffer->cur().mask;
|
|
|
|
hb_mask_t lookup_mask = c->lookup_mask;
|
2018-09-03 04:47:50 +02:00
|
|
|
|
2018-09-10 16:36:05 +02:00
|
|
|
/* Note: This breaks badly if two features enabled this lookup together. */
|
|
|
|
unsigned int shift = hb_ctz (lookup_mask);
|
|
|
|
unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift);
|
2018-09-03 04:47:50 +02:00
|
|
|
|
2019-05-08 05:54:31 +02:00
|
|
|
/* If alt_index is MAX_VALUE, randomize feature if it is the rand feature. */
|
2018-09-10 22:37:19 +02:00
|
|
|
if (alt_index == HB_OT_MAP_MAX_VALUE && c->random)
|
2018-09-11 10:51:19 +02:00
|
|
|
alt_index = c->random_number () % count + 1;
|
2008-01-23 23:01:55 +01:00
|
|
|
|
2018-09-10 22:37:19 +02:00
|
|
|
if (unlikely (alt_index > count || alt_index == 0)) return_trace (false);
|
|
|
|
|
2018-09-10 16:36:05 +02:00
|
|
|
c->replace_glyph (alternates[alt_index - 1]);
|
|
|
|
|
2018-09-03 04:47:50 +02:00
|
|
|
return_trace (true);
|
|
|
|
}
|
|
|
|
|
2019-06-01 00:38:11 +02:00
|
|
|
template <typename Iterator,
|
|
|
|
hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))>
|
2018-12-16 20:08:10 +01:00
|
|
|
bool serialize (hb_serialize_context_t *c,
|
2019-06-01 00:38:11 +02:00
|
|
|
Iterator alts)
|
2018-09-03 04:47:50 +02:00
|
|
|
{
|
|
|
|
TRACE_SERIALIZE (this);
|
2019-01-08 00:33:04 +01:00
|
|
|
return_trace (alternates.serialize (c, alts));
|
2018-09-03 04:47:50 +02:00
|
|
|
}
|
|
|
|
|
2019-08-29 00:38:46 +02:00
|
|
|
bool subset (hb_subset_context_t *c) const
|
|
|
|
{
|
|
|
|
TRACE_SUBSET (this);
|
|
|
|
const hb_set_t &glyphset = *c->plan->glyphset ();
|
|
|
|
const hb_map_t &glyph_map = *c->plan->glyph_map;
|
|
|
|
|
|
|
|
auto it =
|
|
|
|
+ hb_iter (alternates)
|
|
|
|
| hb_filter (glyphset)
|
|
|
|
| hb_map (glyph_map)
|
|
|
|
;
|
|
|
|
|
|
|
|
auto *out = c->serializer->start_embed (*this);
|
|
|
|
return_trace (out->serialize (c->serializer, it) &&
|
|
|
|
out->alternates);
|
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool sanitize (hb_sanitize_context_t *c) const
|
2018-09-03 04:47:50 +02:00
|
|
|
{
|
|
|
|
TRACE_SANITIZE (this);
|
|
|
|
return_trace (alternates.sanitize (c));
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
2019-09-14 08:06:29 +02:00
|
|
|
ArrayOf<HBGlyphID>
|
2018-09-03 04:47:50 +02:00
|
|
|
alternates; /* Array of alternate GlyphIDs--in
|
2008-01-23 23:01:55 +01:00
|
|
|
* arbitrary order */
|
2018-09-03 04:47:50 +02:00
|
|
|
public:
|
|
|
|
DEFINE_SIZE_ARRAY (2, alternates);
|
|
|
|
};
|
2008-01-23 23:01:55 +01:00
|
|
|
|
2009-05-20 05:42:30 +02:00
|
|
|
struct AlternateSubstFormat1
|
|
|
|
{
|
2018-12-16 20:08:10 +01:00
|
|
|
bool intersects (const hb_set_t *glyphs) const
|
2018-09-03 04:47:50 +02:00
|
|
|
{ return (this+coverage).intersects (glyphs); }
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
void closure (hb_closure_context_t *c) const
|
2012-04-23 19:04:38 +02:00
|
|
|
{
|
2019-02-14 22:16:33 +01:00
|
|
|
+ hb_zip (this+coverage, alternateSet)
|
|
|
|
| hb_map (hb_second)
|
2019-05-16 06:57:26 +02:00
|
|
|
| hb_map (hb_add (this))
|
|
|
|
| hb_apply ([c] (const AlternateSet &_) { _.closure (c); })
|
2019-02-14 22:16:33 +01:00
|
|
|
;
|
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-17 04:07:06 +01:00
|
|
|
{
|
2017-12-16 15:12:06 +01:00
|
|
|
if (unlikely (!(this+coverage).add_coverage (c->input))) return;
|
2019-02-14 22:16:33 +01:00
|
|
|
+ hb_zip (this+coverage, alternateSet)
|
|
|
|
| hb_map (hb_second)
|
2019-05-16 06:57:26 +02:00
|
|
|
| hb_map (hb_add (this))
|
|
|
|
| hb_apply ([c] (const AlternateSet &_) { _.collect_glyphs (c); })
|
2019-02-14 22:16:33 +01:00
|
|
|
;
|
2012-11-17 04:07:06 +01:00
|
|
|
}
|
|
|
|
|
2018-12-17 19:01:01 +01:00
|
|
|
const Coverage &get_coverage () const { return this+coverage; }
|
2012-07-28 23:31:01 +02:00
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool would_apply (hb_would_apply_context_t *c) const
|
2019-03-30 06:12:42 +01:00
|
|
|
{ return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
|
2012-11-22 20:38:10 +01:00
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool apply (hb_ot_apply_context_t *c) const
|
2009-05-20 05:42:30 +02:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_APPLY (this);
|
2009-04-16 20:19:42 +02:00
|
|
|
|
2018-09-03 04:47:50 +02: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
|
|
|
|
2018-09-03 04:47:50 +02:00
|
|
|
return_trace ((this+alternateSet[index]).apply (c));
|
2009-04-16 20:19:42 +02:00
|
|
|
}
|
2008-01-23 23:01:55 +01:00
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool serialize (hb_serialize_context_t *c,
|
2019-09-14 08:06:29 +02:00
|
|
|
hb_sorted_array_t<const HBGlyphID> glyphs,
|
2018-12-18 22:49:08 +01:00
|
|
|
hb_array_t<const unsigned int> alternate_len_list,
|
2019-09-14 08:06:29 +02:00
|
|
|
hb_array_t<const HBGlyphID> alternate_glyphs_list)
|
2012-09-04 05:31:14 +02:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_SERIALIZE (this);
|
2015-09-29 15:57:02 +02:00
|
|
|
if (unlikely (!c->extend_min (*this))) return_trace (false);
|
2018-12-22 00:46:51 +01:00
|
|
|
if (unlikely (!alternateSet.serialize (c, glyphs.length))) return_trace (false);
|
|
|
|
for (unsigned int i = 0; i < glyphs.length; i++)
|
2018-12-18 22:49:08 +01:00
|
|
|
{
|
|
|
|
unsigned int alternate_len = alternate_len_list[i];
|
|
|
|
if (unlikely (!alternateSet[i].serialize (c, this)
|
|
|
|
.serialize (c, alternate_glyphs_list.sub_array (0, alternate_len))))
|
|
|
|
return_trace (false);
|
|
|
|
alternate_glyphs_list += alternate_len;
|
|
|
|
}
|
|
|
|
return_trace (coverage.serialize (c, this).serialize (c, glyphs));
|
2012-09-04 05:31:14 +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);
|
2019-08-29 00:38:46 +02:00
|
|
|
const hb_set_t &glyphset = *c->plan->glyphset ();
|
|
|
|
const hb_map_t &glyph_map = *c->plan->glyph_map;
|
|
|
|
|
|
|
|
auto *out = c->serializer->start_embed (*this);
|
|
|
|
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
|
|
|
|
out->format = format;
|
|
|
|
|
|
|
|
hb_sorted_vector_t<hb_codepoint_t> new_coverage;
|
|
|
|
+ hb_zip (this+coverage, alternateSet)
|
|
|
|
| hb_filter (glyphset, hb_first)
|
2019-10-09 20:45:42 +02:00
|
|
|
| hb_filter (subset_offset_array (c, out->alternateSet, this, out), hb_second)
|
2019-08-29 00:38:46 +02:00
|
|
|
| hb_map (hb_first)
|
|
|
|
| hb_map (glyph_map)
|
2019-08-29 12:39:39 +02:00
|
|
|
| hb_sink (new_coverage)
|
2019-08-29 00:38:46 +02:00
|
|
|
;
|
|
|
|
out->coverage.serialize (c->serializer, out)
|
|
|
|
.serialize (c->serializer, new_coverage.iter ());
|
|
|
|
return_trace (bool (new_coverage));
|
2018-09-04 02:33:34 +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 (coverage.sanitize (c, this) && alternateSet.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 06:22:37 +02:00
|
|
|
OffsetTo<Coverage>
|
|
|
|
coverage; /* Offset to Coverage table--from
|
2008-01-23 23:01:55 +01:00
|
|
|
* beginning of Substitution table */
|
2009-05-17 07:22:51 +02:00
|
|
|
OffsetArrayOf<AlternateSet>
|
|
|
|
alternateSet; /* Array of AlternateSet 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, alternateSet);
|
2008-01-23 23:01:55 +01:00
|
|
|
};
|
2009-04-16 10:45:30 +02:00
|
|
|
|
2009-05-20 05:42:30 +02:00
|
|
|
struct AlternateSubst
|
|
|
|
{
|
2018-12-16 20:08:10 +01:00
|
|
|
bool serialize (hb_serialize_context_t *c,
|
2019-09-14 08:06:29 +02:00
|
|
|
hb_sorted_array_t<const HBGlyphID> glyphs,
|
2018-12-18 22:49:08 +01:00
|
|
|
hb_array_t<const unsigned int> alternate_len_list,
|
2019-09-14 08:06:29 +02:00
|
|
|
hb_array_t<const HBGlyphID> alternate_glyphs_list)
|
2012-09-04 05:31:14 +02:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_SERIALIZE (this);
|
2015-09-29 15:57:02 +02:00
|
|
|
if (unlikely (!c->extend_min (u.format))) return_trace (false);
|
2012-09-04 05:31:14 +02:00
|
|
|
unsigned int format = 1;
|
2019-03-30 04:17:46 +01:00
|
|
|
u.format = format;
|
2012-09-04 05:31:14 +02:00
|
|
|
switch (u.format) {
|
2018-12-18 22:49:08 +01:00
|
|
|
case 1: return_trace (u.format1.serialize (c, glyphs, alternate_len_list, alternate_glyphs_list));
|
2015-09-29 15:57:02 +02:00
|
|
|
default:return_trace (false);
|
2012-09-04 05:31:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-05 19:14:17 +02:00
|
|
|
template <typename context_t, typename ...Ts>
|
2019-05-08 05:58:43 +02:00
|
|
|
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
|
2013-03-09 07:59:30 +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 ());
|
2013-03-09 07:59:30 +01:00
|
|
|
switch (u.format) {
|
2019-05-05 19:14:17 +02:00
|
|
|
case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
|
2015-09-29 15:57:02 +02:00
|
|
|
default:return_trace (c->default_return_value ());
|
2013-03-09 07:59:30 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-24 21:40:37 +02:00
|
|
|
protected:
|
2009-04-16 20:19:42 +02:00
|
|
|
union {
|
2018-01-10 03:07:30 +01:00
|
|
|
HBUINT16 format; /* Format identifier */
|
2010-05-11 01:45:41 +02:00
|
|
|
AlternateSubstFormat1 format1;
|
2009-04-16 20:19:42 +02:00
|
|
|
} u;
|
|
|
|
};
|
|
|
|
|
2009-04-16 10:45:30 +02:00
|
|
|
|
2009-05-20 05:42:30 +02:00
|
|
|
struct Ligature
|
|
|
|
{
|
2018-12-16 20:08:10 +01:00
|
|
|
bool intersects (const hb_set_t *glyphs) const
|
2019-08-29 00:30:37 +02:00
|
|
|
{ return hb_all (component, glyphs); }
|
2018-09-03 04:47:50 +02:00
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
void closure (hb_closure_context_t *c) const
|
2012-04-23 19:04:38 +02:00
|
|
|
{
|
2019-03-30 05:57:26 +01:00
|
|
|
if (!intersects (c->glyphs)) return;
|
2019-01-09 19:45:53 +01:00
|
|
|
c->output->add (ligGlyph);
|
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-17 04:07:06 +01:00
|
|
|
{
|
2019-08-29 00:06:45 +02:00
|
|
|
c->input->add_array (component.arrayZ, component.get_length ());
|
2012-12-04 23:08:41 +01:00
|
|
|
c->output->add (ligGlyph);
|
2012-11-17 04:07:06 +01:00
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool would_apply (hb_would_apply_context_t *c) const
|
2012-04-20 04:21:38 +02:00
|
|
|
{
|
2018-09-13 20:21:54 +02:00
|
|
|
if (c->len != component.lenP1)
|
2019-03-30 06:12:42 +01:00
|
|
|
return false;
|
2012-08-08 04:25:24 +02:00
|
|
|
|
|
|
|
for (unsigned int i = 1; i < c->len; i++)
|
|
|
|
if (likely (c->glyphs[i] != component[i]))
|
2019-03-30 06:12:42 +01:00
|
|
|
return false;
|
2012-08-08 04:25:24 +02:00
|
|
|
|
2019-03-30 06:12:42 +01:00
|
|
|
return true;
|
2012-04-20 04:21:38 +02:00
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool apply (hb_ot_apply_context_t *c) const
|
2009-05-20 05:42:30 +02:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_APPLY (this);
|
2018-09-13 20:21:54 +02:00
|
|
|
unsigned int count = component.lenP1;
|
2014-06-06 00:54:44 +02:00
|
|
|
|
2015-09-29 15:57:02 +02:00
|
|
|
if (unlikely (!count)) return_trace (false);
|
2012-01-17 04:05:08 +01:00
|
|
|
|
2014-06-06 01:00:22 +02:00
|
|
|
/* Special-case to make it in-place and not consider this
|
|
|
|
* as a "ligated" substitution. */
|
|
|
|
if (unlikely (count == 1))
|
|
|
|
{
|
|
|
|
c->replace_glyph (ligGlyph);
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (true);
|
2014-06-06 01:00:22 +02:00
|
|
|
}
|
|
|
|
|
2012-11-23 20:07:24 +01:00
|
|
|
unsigned int total_component_count = 0;
|
2012-08-29 04:58:55 +02:00
|
|
|
|
2013-10-17 13:49:51 +02:00
|
|
|
unsigned int match_length = 0;
|
2015-11-03 00:43:08 +01:00
|
|
|
unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
|
2013-10-17 13:49:51 +02:00
|
|
|
|
2012-08-29 04:58:55 +02:00
|
|
|
if (likely (!match_input (c, count,
|
|
|
|
&component[1],
|
|
|
|
match_glyph,
|
2017-10-15 12:11:08 +02:00
|
|
|
nullptr,
|
2013-10-17 13:49:51 +02:00
|
|
|
&match_length,
|
|
|
|
match_positions,
|
2012-08-29 04:58:55 +02:00
|
|
|
&total_component_count)))
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (false);
|
[GSUB] Don't set new lig_id on mark ligatures
If two marks form a ligature, retain their previous lig_id, such that
the mark ligature can attach to ligature components...
Fixes https://bugzilla.gnome.org/show_bug.cgi?id=676343
In fact, I noticed that we should not let ligatures form between glyphs
coming from different components of a previous ligature. For example,
if the sequence is: LAM,SHADDA,LAM,FATHA,HEH, the LAM,LAM,HEH form a
ligature, putting SHADDA and FATHA next to eachother. However, it would
be wrong to ligate them. Uniscribe has this bug also.
2012-07-30 02:37:38 +02:00
|
|
|
|
2012-08-29 05:18:22 +02:00
|
|
|
ligate_input (c,
|
|
|
|
count,
|
2013-10-17 13:49:51 +02:00
|
|
|
match_positions,
|
|
|
|
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
|
|
|
ligGlyph,
|
2012-08-29 05:18:22 +02:00
|
|
|
total_component_count);
|
2009-05-05 19:25:13 +02:00
|
|
|
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (true);
|
2009-05-05 19:25:13 +02:00
|
|
|
}
|
2009-04-16 10:45:30 +02:00
|
|
|
|
2019-06-01 00:38:11 +02:00
|
|
|
template <typename Iterator,
|
|
|
|
hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))>
|
2018-12-16 20:08:10 +01:00
|
|
|
bool serialize (hb_serialize_context_t *c,
|
2019-08-28 23:51:28 +02:00
|
|
|
hb_codepoint_t ligature,
|
2019-06-01 00:38:11 +02:00
|
|
|
Iterator components /* Starting from second */)
|
2012-09-05 00:17:57 +02:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_SERIALIZE (this);
|
2015-09-29 15:57:02 +02:00
|
|
|
if (unlikely (!c->extend_min (*this))) return_trace (false);
|
2012-09-06 04:19:28 +02:00
|
|
|
ligGlyph = ligature;
|
2018-12-18 22:49:08 +01:00
|
|
|
if (unlikely (!component.serialize (c, components))) return_trace (false);
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (true);
|
2012-09-05 00:17:57 +02:00
|
|
|
}
|
|
|
|
|
2019-08-28 23:51:28 +02:00
|
|
|
bool subset (hb_subset_context_t *c) const
|
|
|
|
{
|
|
|
|
TRACE_SUBSET (this);
|
|
|
|
const hb_set_t &glyphset = *c->plan->glyphset ();
|
|
|
|
const hb_map_t &glyph_map = *c->plan->glyph_map;
|
|
|
|
|
2019-08-29 00:30:37 +02:00
|
|
|
if (!intersects (&glyphset) || !glyphset.has (ligGlyph)) return_trace (false);
|
2019-08-28 23:51:28 +02:00
|
|
|
|
|
|
|
auto it =
|
|
|
|
+ hb_iter (component)
|
|
|
|
| hb_map (glyph_map)
|
|
|
|
;
|
|
|
|
|
|
|
|
auto *out = c->serializer->start_embed (*this);
|
2019-08-29 00:38:46 +02:00
|
|
|
return_trace (out->serialize (c->serializer,
|
|
|
|
glyph_map[ligGlyph],
|
|
|
|
it));
|
2019-08-28 23:51:28 +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);
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (ligGlyph.sanitize (c) && component.sanitize (c));
|
2009-08-04 06:58:28 +02:00
|
|
|
}
|
|
|
|
|
2012-07-24 21:40:37 +02:00
|
|
|
protected:
|
2019-09-14 08:06:29 +02:00
|
|
|
HBGlyphID ligGlyph; /* GlyphID of ligature to substitute */
|
|
|
|
HeadlessArrayOf<HBGlyphID>
|
2009-05-18 08:03:58 +02:00
|
|
|
component; /* Array of component GlyphIDs--start
|
2009-04-16 10:45:30 +02:00
|
|
|
* with the second component--ordered
|
|
|
|
* in writing direction */
|
2010-05-10 22:57:29 +02:00
|
|
|
public:
|
2010-05-11 01:01:17 +02:00
|
|
|
DEFINE_SIZE_ARRAY (4, component);
|
2009-04-16 10:45:30 +02:00
|
|
|
};
|
2008-01-23 23:01:55 +01:00
|
|
|
|
2009-05-20 05:42:30 +02:00
|
|
|
struct LigatureSet
|
|
|
|
{
|
2018-12-16 20:08:10 +01:00
|
|
|
bool intersects (const hb_set_t *glyphs) const
|
2018-09-03 04:47:50 +02:00
|
|
|
{
|
2019-03-30 06:04:15 +01:00
|
|
|
return
|
|
|
|
+ hb_iter (ligature)
|
2019-05-16 06:57:26 +02:00
|
|
|
| hb_map (hb_add (this))
|
|
|
|
| hb_map ([glyphs] (const Ligature &_) { return _.intersects (glyphs); })
|
2019-03-30 06:04:15 +01:00
|
|
|
| hb_any
|
|
|
|
;
|
2018-09-03 04:47:50 +02:00
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
void closure (hb_closure_context_t *c) const
|
2012-04-23 19:04:38 +02:00
|
|
|
{
|
2019-03-30 06:04:15 +01:00
|
|
|
+ hb_iter (ligature)
|
2019-05-16 06:57:26 +02:00
|
|
|
| hb_map (hb_add (this))
|
|
|
|
| hb_apply ([c] (const Ligature &_) { _.closure (c); })
|
2019-03-30 06:04:15 +01:00
|
|
|
;
|
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-17 04:07:06 +01:00
|
|
|
{
|
2019-03-30 06:04:15 +01:00
|
|
|
+ hb_iter (ligature)
|
2019-05-16 06:57:26 +02:00
|
|
|
| hb_map (hb_add (this))
|
|
|
|
| hb_apply ([c] (const Ligature &_) { _.collect_glyphs (c); })
|
2019-03-30 06:04:15 +01:00
|
|
|
;
|
2012-11-17 04:07:06 +01:00
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool would_apply (hb_would_apply_context_t *c) const
|
2012-04-20 04:21:38 +02:00
|
|
|
{
|
2019-03-30 06:17:31 +01:00
|
|
|
return
|
|
|
|
+ hb_iter (ligature)
|
2019-05-16 06:57:26 +02:00
|
|
|
| hb_map (hb_add (this))
|
|
|
|
| hb_map ([c] (const Ligature &_) { return _.would_apply (c); })
|
2019-03-30 06:17:31 +01:00
|
|
|
| hb_any
|
|
|
|
;
|
2012-04-20 04:21:38 +02:00
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool apply (hb_ot_apply_context_t *c) const
|
2009-05-20 05:42:30 +02:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_APPLY (this);
|
2009-05-17 07:22:51 +02:00
|
|
|
unsigned int num_ligs = ligature.len;
|
2009-05-20 05:42:30 +02:00
|
|
|
for (unsigned int i = 0; i < num_ligs; i++)
|
|
|
|
{
|
2009-05-17 07:22:51 +02:00
|
|
|
const Ligature &lig = this+ligature[i];
|
2015-09-29 15:57:02 +02:00
|
|
|
if (lig.apply (c)) return_trace (true);
|
2009-05-05 19:25:13 +02:00
|
|
|
}
|
|
|
|
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (false);
|
2009-05-05 19:25:13 +02:00
|
|
|
}
|
2008-01-23 23:01:55 +01:00
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool serialize (hb_serialize_context_t *c,
|
2019-09-14 08:06:29 +02:00
|
|
|
hb_array_t<const HBGlyphID> ligatures,
|
2018-12-18 22:49:08 +01:00
|
|
|
hb_array_t<const unsigned int> component_count_list,
|
2019-09-14 08:06:29 +02:00
|
|
|
hb_array_t<const HBGlyphID> &component_list /* Starting from second for each ligature */)
|
2012-09-05 00:17:57 +02:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_SERIALIZE (this);
|
2015-09-29 15:57:02 +02:00
|
|
|
if (unlikely (!c->extend_min (*this))) return_trace (false);
|
2018-12-22 00:46:51 +01:00
|
|
|
if (unlikely (!ligature.serialize (c, ligatures.length))) return_trace (false);
|
|
|
|
for (unsigned int i = 0; i < ligatures.length; i++)
|
2018-12-18 22:49:08 +01:00
|
|
|
{
|
2019-05-08 05:54:31 +02:00
|
|
|
unsigned int component_count = (unsigned) hb_max ((int) component_count_list[i] - 1, 0);
|
2018-12-18 22:49:08 +01:00
|
|
|
if (unlikely (!ligature[i].serialize (c, this)
|
|
|
|
.serialize (c,
|
|
|
|
ligatures[i],
|
|
|
|
component_list.sub_array (0, component_count))))
|
|
|
|
return_trace (false);
|
|
|
|
component_list += component_count;
|
|
|
|
}
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (true);
|
2012-09-05 00:17:57 +02:00
|
|
|
}
|
|
|
|
|
2019-08-28 23:51:28 +02:00
|
|
|
bool subset (hb_subset_context_t *c) const
|
|
|
|
{
|
|
|
|
TRACE_SUBSET (this);
|
|
|
|
auto *out = c->serializer->start_embed (*this);
|
|
|
|
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
|
|
|
|
|
|
|
|
+ hb_iter (ligature)
|
2019-10-09 20:45:42 +02:00
|
|
|
| hb_filter (subset_offset_array (c, out->ligature, this, out))
|
2019-08-29 12:39:39 +02:00
|
|
|
| hb_drain
|
2019-08-28 23:51:28 +02:00
|
|
|
;
|
|
|
|
return_trace (bool (out->ligature));
|
|
|
|
}
|
|
|
|
|
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 (ligature.sanitize (c, this));
|
2009-08-04 06:58:28 +02:00
|
|
|
}
|
|
|
|
|
2012-07-24 21:40:37 +02:00
|
|
|
protected:
|
2009-05-17 07:22:51 +02:00
|
|
|
OffsetArrayOf<Ligature>
|
|
|
|
ligature; /* Array LigatureSet 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, ligature);
|
2008-01-23 23:01:55 +01:00
|
|
|
};
|
|
|
|
|
2009-05-20 05:42:30 +02:00
|
|
|
struct LigatureSubstFormat1
|
|
|
|
{
|
2018-12-16 20:08:10 +01:00
|
|
|
bool intersects (const hb_set_t *glyphs) const
|
2018-09-03 04:47:50 +02:00
|
|
|
{
|
2019-03-30 05:49:18 +01:00
|
|
|
return
|
|
|
|
+ hb_zip (this+coverage, ligatureSet)
|
|
|
|
| hb_filter (*glyphs, hb_first)
|
|
|
|
| hb_map (hb_second)
|
2019-05-16 03:15:05 +02:00
|
|
|
| hb_map ([this, glyphs] (const OffsetTo<LigatureSet> &_)
|
2019-03-30 05:49:18 +01:00
|
|
|
{ return (this+_).intersects (glyphs); })
|
|
|
|
| hb_any
|
|
|
|
;
|
2018-09-03 04:47:50 +02:00
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
void closure (hb_closure_context_t *c) const
|
2012-04-23 19:04:38 +02:00
|
|
|
{
|
2019-02-14 22:45:52 +01:00
|
|
|
+ hb_zip (this+coverage, ligatureSet)
|
|
|
|
| hb_filter (*c->glyphs, hb_first)
|
|
|
|
| hb_map (hb_second)
|
2019-05-16 06:57:26 +02:00
|
|
|
| hb_map (hb_add (this))
|
|
|
|
| hb_apply ([c] (const LigatureSet &_) { _.closure (c); })
|
2019-02-14 22:45:52 +01:00
|
|
|
;
|
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-17 04:07:06 +01:00
|
|
|
{
|
2017-12-16 15:12:06 +01:00
|
|
|
if (unlikely (!(this+coverage).add_coverage (c->input))) return;
|
2019-03-30 05:17:08 +01:00
|
|
|
|
2019-02-14 22:45:52 +01:00
|
|
|
+ hb_zip (this+coverage, ligatureSet)
|
|
|
|
| hb_map (hb_second)
|
2019-05-16 06:57:26 +02:00
|
|
|
| hb_map (hb_add (this))
|
|
|
|
| hb_apply ([c] (const LigatureSet &_) { _.collect_glyphs (c); })
|
2019-02-14 22:45:52 +01:00
|
|
|
;
|
2012-11-17 04:07:06 +01:00
|
|
|
}
|
|
|
|
|
2018-12-17 19:01:01 +01:00
|
|
|
const Coverage &get_coverage () const { return this+coverage; }
|
2012-07-28 23:31:01 +02:00
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool would_apply (hb_would_apply_context_t *c) const
|
2012-04-20 04:21:38 +02:00
|
|
|
{
|
2012-11-25 01:13:55 +01:00
|
|
|
unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
|
2019-03-30 06:12:42 +01:00
|
|
|
if (likely (index == NOT_COVERED)) return false;
|
2012-11-22 20:38:10 +01:00
|
|
|
|
|
|
|
const LigatureSet &lig_set = this+ligatureSet[index];
|
2019-03-30 06:12:42 +01:00
|
|
|
return lig_set.would_apply (c);
|
2012-04-20 04:21:38 +02:00
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool apply (hb_ot_apply_context_t *c) const
|
2009-05-20 05:42:30 +02:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_APPLY (this);
|
2009-04-16 22:53:40 +02:00
|
|
|
|
2018-09-03 04:47:50 +02: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
|
|
|
|
2009-05-17 07:22:51 +02:00
|
|
|
const LigatureSet &lig_set = this+ligatureSet[index];
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (lig_set.apply (c));
|
2009-04-16 22:53:40 +02:00
|
|
|
}
|
2008-01-23 23:01:55 +01:00
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool serialize (hb_serialize_context_t *c,
|
2019-09-14 08:06:29 +02:00
|
|
|
hb_sorted_array_t<const HBGlyphID> first_glyphs,
|
2018-12-18 22:49:08 +01:00
|
|
|
hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
|
2019-09-14 08:06:29 +02:00
|
|
|
hb_array_t<const HBGlyphID> ligatures_list,
|
2018-12-18 22:49:08 +01:00
|
|
|
hb_array_t<const unsigned int> component_count_list,
|
2019-09-14 08:06:29 +02:00
|
|
|
hb_array_t<const HBGlyphID> component_list /* Starting from second for each ligature */)
|
2012-09-05 00:17:57 +02:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_SERIALIZE (this);
|
2015-09-29 15:57:02 +02:00
|
|
|
if (unlikely (!c->extend_min (*this))) return_trace (false);
|
2018-12-22 00:46:51 +01:00
|
|
|
if (unlikely (!ligatureSet.serialize (c, first_glyphs.length))) return_trace (false);
|
|
|
|
for (unsigned int i = 0; i < first_glyphs.length; i++)
|
2018-12-18 22:49:08 +01:00
|
|
|
{
|
|
|
|
unsigned int ligature_count = ligature_per_first_glyph_count_list[i];
|
|
|
|
if (unlikely (!ligatureSet[i].serialize (c, this)
|
|
|
|
.serialize (c,
|
|
|
|
ligatures_list.sub_array (0, ligature_count),
|
|
|
|
component_count_list.sub_array (0, ligature_count),
|
|
|
|
component_list))) return_trace (false);
|
|
|
|
ligatures_list += ligature_count;
|
|
|
|
component_count_list += ligature_count;
|
|
|
|
}
|
|
|
|
return_trace (coverage.serialize (c, this).serialize (c, first_glyphs));
|
2012-09-05 00:17:57 +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);
|
2019-08-28 23:51:28 +02:00
|
|
|
const hb_set_t &glyphset = *c->plan->glyphset ();
|
|
|
|
const hb_map_t &glyph_map = *c->plan->glyph_map;
|
|
|
|
|
|
|
|
auto *out = c->serializer->start_embed (*this);
|
|
|
|
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
|
|
|
|
out->format = format;
|
|
|
|
|
|
|
|
hb_sorted_vector_t<hb_codepoint_t> new_coverage;
|
|
|
|
+ hb_zip (this+coverage, ligatureSet)
|
|
|
|
| hb_filter (glyphset, hb_first)
|
2019-10-07 23:02:31 +02:00
|
|
|
| hb_filter (subset_offset_array (c, out->ligatureSet, this, out), hb_second)
|
2019-08-28 23:51:28 +02:00
|
|
|
| hb_map (hb_first)
|
|
|
|
| hb_map (glyph_map)
|
2019-08-29 12:39:39 +02:00
|
|
|
| hb_sink (new_coverage)
|
2019-08-28 23:51:28 +02:00
|
|
|
;
|
|
|
|
out->coverage.serialize (c->serializer, out)
|
|
|
|
.serialize (c->serializer, new_coverage.iter ());
|
|
|
|
return_trace (bool (new_coverage));
|
2018-09-04 02:33:34 +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 (coverage.sanitize (c, this) && ligatureSet.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 06:22:37 +02:00
|
|
|
OffsetTo<Coverage>
|
|
|
|
coverage; /* Offset to Coverage table--from
|
2009-04-16 10:45:30 +02:00
|
|
|
* beginning of Substitution table */
|
2009-05-18 19:50:15 +02:00
|
|
|
OffsetArrayOf<LigatureSet>
|
2009-05-17 07:22:51 +02:00
|
|
|
ligatureSet; /* Array LigatureSet 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, ligatureSet);
|
2008-01-23 23:01:55 +01:00
|
|
|
};
|
2009-04-16 10:45:30 +02:00
|
|
|
|
2009-05-20 05:42:30 +02:00
|
|
|
struct LigatureSubst
|
|
|
|
{
|
2018-12-16 20:08:10 +01:00
|
|
|
bool serialize (hb_serialize_context_t *c,
|
2019-09-14 08:06:29 +02:00
|
|
|
hb_sorted_array_t<const HBGlyphID> first_glyphs,
|
2018-12-18 22:49:08 +01:00
|
|
|
hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
|
2019-09-14 08:06:29 +02:00
|
|
|
hb_array_t<const HBGlyphID> ligatures_list,
|
2018-12-18 22:49:08 +01:00
|
|
|
hb_array_t<const unsigned int> component_count_list,
|
2019-09-14 08:06:29 +02:00
|
|
|
hb_array_t<const HBGlyphID> component_list /* Starting from second for each ligature */)
|
2012-09-05 00:17:57 +02:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_SERIALIZE (this);
|
2015-09-29 15:57:02 +02:00
|
|
|
if (unlikely (!c->extend_min (u.format))) return_trace (false);
|
2012-09-05 00:17:57 +02:00
|
|
|
unsigned int format = 1;
|
2019-03-30 04:17:46 +01:00
|
|
|
u.format = format;
|
2012-09-05 00:17:57 +02:00
|
|
|
switch (u.format) {
|
2015-09-29 15:57:02 +02:00
|
|
|
case 1: return_trace (u.format1.serialize (c,
|
|
|
|
first_glyphs,
|
|
|
|
ligature_per_first_glyph_count_list,
|
|
|
|
ligatures_list,
|
|
|
|
component_count_list,
|
|
|
|
component_list));
|
|
|
|
default:return_trace (false);
|
2012-09-05 00:17:57 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-05 19:14:17 +02:00
|
|
|
template <typename context_t, typename ...Ts>
|
2019-05-08 05:58:43 +02:00
|
|
|
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
|
2013-03-09 07:59:30 +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 ());
|
2013-03-09 07:59:30 +01:00
|
|
|
switch (u.format) {
|
2019-05-05 19:14:17 +02:00
|
|
|
case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
|
2015-09-29 15:57:02 +02:00
|
|
|
default:return_trace (c->default_return_value ());
|
2013-03-09 07:59:30 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-24 21:40:37 +02:00
|
|
|
protected:
|
2009-04-16 22:53:40 +02:00
|
|
|
union {
|
2018-01-10 03:07:30 +01:00
|
|
|
HBUINT16 format; /* Format identifier */
|
2010-05-11 01:45:41 +02:00
|
|
|
LigatureSubstFormat1 format1;
|
2009-04-16 22:53:40 +02:00
|
|
|
} u;
|
|
|
|
};
|
|
|
|
|
2008-01-23 23:01:55 +01:00
|
|
|
|
2012-11-23 22:51:43 +01:00
|
|
|
struct ContextSubst : Context {};
|
2009-05-17 01:59:15 +02:00
|
|
|
|
2012-11-23 22:51:43 +01:00
|
|
|
struct ChainContextSubst : ChainContext {};
|
2009-04-16 19:40:13 +02:00
|
|
|
|
2012-11-23 22:57:36 +01:00
|
|
|
struct ExtensionSubst : Extension<ExtensionSubst>
|
2009-05-20 05:42:30 +02:00
|
|
|
{
|
2018-09-04 01:53:03 +02:00
|
|
|
typedef struct SubstLookupSubTable SubTable;
|
2009-08-04 06:58:28 +02:00
|
|
|
|
2018-12-17 19:01:01 +01:00
|
|
|
bool is_reverse () const;
|
2009-04-16 19:40:13 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2009-05-20 05:42:30 +02:00
|
|
|
struct ReverseChainSingleSubstFormat1
|
|
|
|
{
|
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;
|
|
|
|
|
2019-04-30 22:05:10 +02:00
|
|
|
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
|
2018-09-03 04:47:50 +02:00
|
|
|
|
|
|
|
unsigned int count;
|
|
|
|
|
|
|
|
count = backtrack.len;
|
|
|
|
for (unsigned int i = 0; i < count; i++)
|
|
|
|
if (!(this+backtrack[i]).intersects (glyphs))
|
2019-05-16 22:22:09 +02:00
|
|
|
return false;
|
2018-09-03 04:47:50 +02:00
|
|
|
|
|
|
|
count = lookahead.len;
|
|
|
|
for (unsigned int i = 0; i < count; i++)
|
|
|
|
if (!(this+lookahead[i]).intersects (glyphs))
|
2019-05-16 22:22:09 +02:00
|
|
|
return false;
|
2018-09-03 04:47:50 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
void closure (hb_closure_context_t *c) const
|
2012-04-23 19:04:38 +02:00
|
|
|
{
|
2019-03-30 05:57:26 +01:00
|
|
|
if (!intersects (c->glyphs)) return;
|
2012-04-23 21:28:35 +02:00
|
|
|
|
2019-04-30 22:05:10 +02:00
|
|
|
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
|
2019-09-14 08:06:29 +02:00
|
|
|
const ArrayOf<HBGlyphID> &substitute = StructAfter<ArrayOf<HBGlyphID>> (lookahead);
|
2019-03-30 05:17:08 +01:00
|
|
|
|
2019-02-14 19:40:05 +01:00
|
|
|
+ hb_zip (this+coverage, substitute)
|
|
|
|
| hb_filter (*c->glyphs, hb_first)
|
|
|
|
| hb_map (hb_second)
|
2019-02-14 20:03:29 +01:00
|
|
|
| hb_sink (c->output)
|
2019-02-14 19:51:47 +01:00
|
|
|
;
|
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-17 04:07:06 +01:00
|
|
|
{
|
2017-12-16 15:12:06 +01:00
|
|
|
if (unlikely (!(this+coverage).add_coverage (c->input))) return;
|
2012-11-17 04:07:06 +01:00
|
|
|
|
|
|
|
unsigned int count;
|
|
|
|
|
|
|
|
count = backtrack.len;
|
|
|
|
for (unsigned int i = 0; i < count; i++)
|
2017-12-16 15:12:06 +01:00
|
|
|
if (unlikely (!(this+backtrack[i]).add_coverage (c->before))) return;
|
2012-11-17 04:07:06 +01:00
|
|
|
|
2019-04-30 22:05:10 +02:00
|
|
|
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
|
2012-11-17 04:07:06 +01:00
|
|
|
count = lookahead.len;
|
|
|
|
for (unsigned int i = 0; i < count; i++)
|
2017-12-16 15:12:06 +01:00
|
|
|
if (unlikely (!(this+lookahead[i]).add_coverage (c->after))) return;
|
2012-11-17 04:07:06 +01:00
|
|
|
|
2019-09-14 08:06:29 +02:00
|
|
|
const ArrayOf<HBGlyphID> &substitute = StructAfter<ArrayOf<HBGlyphID>> (lookahead);
|
2012-11-17 04:07:06 +01:00
|
|
|
count = substitute.len;
|
2018-05-09 01:56:11 +02:00
|
|
|
c->output->add_array (substitute.arrayZ, substitute.len);
|
2012-11-17 04:07:06 +01:00
|
|
|
}
|
|
|
|
|
2018-12-17 19:01:01 +01:00
|
|
|
const Coverage &get_coverage () const { return this+coverage; }
|
2012-07-28 23:31:01 +02:00
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool would_apply (hb_would_apply_context_t *c) const
|
2019-03-30 06:12:42 +01:00
|
|
|
{ return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
|
2012-11-22 20:38:10 +01:00
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool apply (hb_ot_apply_context_t *c) const
|
2009-05-20 05:42:30 +02:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_APPLY (this);
|
2015-11-03 00:43:08 +01:00
|
|
|
if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL))
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (false); /* No chaining to this type */
|
2009-05-18 11:47:47 +02:00
|
|
|
|
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 11:47:47 +02:00
|
|
|
|
2019-04-30 22:05:10 +02:00
|
|
|
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
|
2019-09-14 08:06:29 +02:00
|
|
|
const ArrayOf<HBGlyphID> &substitute = StructAfter<ArrayOf<HBGlyphID>> (lookahead);
|
2009-05-18 11:47:47 +02:00
|
|
|
|
2016-05-02 14:47:45 +02:00
|
|
|
unsigned int start_index = 0, end_index = 0;
|
2010-05-13 20:18:49 +02:00
|
|
|
if (match_backtrack (c,
|
2018-05-09 01:56:11 +02:00
|
|
|
backtrack.len, (HBUINT16 *) backtrack.arrayZ,
|
2016-05-02 14:47:45 +02:00
|
|
|
match_coverage, this,
|
|
|
|
&start_index) &&
|
2019-05-16 22:22:09 +02:00
|
|
|
match_lookahead (c,
|
2018-05-09 01:56:11 +02:00
|
|
|
lookahead.len, (HBUINT16 *) lookahead.arrayZ,
|
2010-05-10 23:47:22 +02:00
|
|
|
match_coverage, this,
|
2016-05-02 14:47:45 +02:00
|
|
|
1, &end_index))
|
2009-05-18 11:47:47 +02:00
|
|
|
{
|
2016-05-02 14:47:45 +02:00
|
|
|
c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index);
|
2012-07-31 00:36:42 +02:00
|
|
|
c->replace_glyph_inplace (substitute[index]);
|
2013-10-17 19:48:51 +02:00
|
|
|
/* Note: We DON'T decrease buffer->idx. The main loop does it
|
|
|
|
* for us. This is useful for preventing surprises if someone
|
|
|
|
* calls us through a Context lookup. */
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (true);
|
2009-05-18 11:47:47 +02:00
|
|
|
}
|
|
|
|
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (false);
|
2009-05-18 02:48:27 +02:00
|
|
|
}
|
2008-01-23 23:01:55 +01: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);
|
2012-05-11 01:25:34 +02:00
|
|
|
if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (false);
|
2019-04-30 22:05:10 +02:00
|
|
|
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
|
2010-05-13 20:18:49 +02:00
|
|
|
if (!lookahead.sanitize (c, this))
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (false);
|
2019-09-14 08:06:29 +02:00
|
|
|
const ArrayOf<HBGlyphID> &substitute = StructAfter<ArrayOf<HBGlyphID>> (lookahead);
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (substitute.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 = 1 */
|
2009-05-18 11:47:47 +02:00
|
|
|
OffsetTo<Coverage>
|
|
|
|
coverage; /* Offset to Coverage table--from
|
|
|
|
* beginning of table */
|
|
|
|
OffsetArrayOf<Coverage>
|
|
|
|
backtrack; /* Array of coverage tables
|
2018-09-03 04:47:50 +02:00
|
|
|
* in backtracking sequence, in glyph
|
2008-01-23 23:01:55 +01:00
|
|
|
* sequence order */
|
2009-05-18 11:47:47 +02:00
|
|
|
OffsetArrayOf<Coverage>
|
|
|
|
lookaheadX; /* Array of coverage tables
|
|
|
|
* in lookahead sequence, in glyph
|
2008-01-23 23:01:55 +01:00
|
|
|
* sequence order */
|
2019-09-14 08:06:29 +02:00
|
|
|
ArrayOf<HBGlyphID>
|
2009-05-18 11:47:47 +02:00
|
|
|
substituteX; /* Array of substitute
|
|
|
|
* GlyphIDs--ordered by Coverage Index */
|
2010-05-10 22:57:29 +02:00
|
|
|
public:
|
2010-05-10 23:28:16 +02:00
|
|
|
DEFINE_SIZE_MIN (10);
|
2008-01-23 23:01:55 +01:00
|
|
|
};
|
|
|
|
|
2009-05-20 05:42:30 +02:00
|
|
|
struct ReverseChainSingleSubst
|
|
|
|
{
|
2019-05-05 19:14:17 +02:00
|
|
|
template <typename context_t, typename ...Ts>
|
2019-05-08 05:58:43 +02:00
|
|
|
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) 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) {
|
2019-05-05 19:14:17 +02:00
|
|
|
case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
|
2015-09-29 15:57:02 +02:00
|
|
|
default:return_trace (c->default_return_value ());
|
2012-07-28 23:31:01 +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
|
|
|
ReverseChainSingleSubstFormat1 format1;
|
2009-05-18 02:48:27 +02:00
|
|
|
} u;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
2009-04-16 01:50:16 +02:00
|
|
|
/*
|
|
|
|
* SubstLookup
|
|
|
|
*/
|
|
|
|
|
2009-05-20 05:42:30 +02:00
|
|
|
struct SubstLookupSubTable
|
|
|
|
{
|
2018-09-04 02:16:09 +02:00
|
|
|
friend struct Lookup;
|
2009-04-16 01:50:16 +02:00
|
|
|
friend struct SubstLookup;
|
|
|
|
|
2012-04-12 19:23:59 +02:00
|
|
|
enum Type {
|
2009-05-20 09:53:00 +02:00
|
|
|
Single = 1,
|
|
|
|
Multiple = 2,
|
|
|
|
Alternate = 3,
|
|
|
|
Ligature = 4,
|
|
|
|
Context = 5,
|
|
|
|
ChainContext = 6,
|
|
|
|
Extension = 7,
|
2009-08-18 22:41:59 +02:00
|
|
|
ReverseChainSingle = 8
|
2009-05-20 09:53:00 +02:00
|
|
|
};
|
|
|
|
|
2019-05-05 19:14:17 +02:00
|
|
|
template <typename context_t, typename ...Ts>
|
2019-05-08 05:58:43 +02:00
|
|
|
typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type, Ts&&... ds) const
|
2012-04-23 19:04:38 +02:00
|
|
|
{
|
2014-12-13 05:36:49 +01:00
|
|
|
TRACE_DISPATCH (this, lookup_type);
|
2012-04-23 19:04:38 +02:00
|
|
|
switch (lookup_type) {
|
2019-05-05 19:14:17 +02:00
|
|
|
case Single: return_trace (u.single.dispatch (c, hb_forward<Ts> (ds)...));
|
|
|
|
case Multiple: return_trace (u.multiple.dispatch (c, hb_forward<Ts> (ds)...));
|
|
|
|
case Alternate: return_trace (u.alternate.dispatch (c, hb_forward<Ts> (ds)...));
|
|
|
|
case Ligature: return_trace (u.ligature.dispatch (c, hb_forward<Ts> (ds)...));
|
|
|
|
case Context: return_trace (u.context.dispatch (c, hb_forward<Ts> (ds)...));
|
|
|
|
case ChainContext: return_trace (u.chainContext.dispatch (c, hb_forward<Ts> (ds)...));
|
|
|
|
case Extension: return_trace (u.extension.dispatch (c, hb_forward<Ts> (ds)...));
|
|
|
|
case ReverseChainSingle: return_trace (u.reverseChainContextSingle.dispatch (c, hb_forward<Ts> (ds)...));
|
2015-09-29 15:57:02 +02:00
|
|
|
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-04-16 01:50:16 +02:00
|
|
|
union {
|
2010-05-11 01:45:41 +02:00
|
|
|
SingleSubst single;
|
|
|
|
MultipleSubst multiple;
|
|
|
|
AlternateSubst alternate;
|
|
|
|
LigatureSubst ligature;
|
2012-07-19 20:35:23 +02:00
|
|
|
ContextSubst context;
|
2010-05-11 01:45:41 +02:00
|
|
|
ChainContextSubst chainContext;
|
|
|
|
ExtensionSubst extension;
|
|
|
|
ReverseChainSingleSubst reverseChainContextSingle;
|
2009-04-16 01:50:16 +02:00
|
|
|
} u;
|
2010-05-11 00:08:46 +02:00
|
|
|
public:
|
2018-12-12 16:07:38 +01:00
|
|
|
DEFINE_SIZE_MIN (0);
|
2009-04-16 01:50:16 +02:00
|
|
|
};
|
|
|
|
|
2009-04-16 19:40:13 +02:00
|
|
|
|
2009-05-20 05:42:30 +02:00
|
|
|
struct SubstLookup : Lookup
|
|
|
|
{
|
2018-09-04 01:53:03 +02:00
|
|
|
typedef SubstLookupSubTable SubTable;
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
const SubTable& get_subtable (unsigned int i) const
|
2018-09-04 01:53:03 +02:00
|
|
|
{ return Lookup::get_subtable<SubTable> (i); }
|
2009-04-16 01:50:16 +02:00
|
|
|
|
2019-04-12 23:50:03 +02:00
|
|
|
HB_INTERNAL static bool lookup_type_is_reverse (unsigned int lookup_type)
|
2018-09-04 01:53:03 +02:00
|
|
|
{ return lookup_type == SubTable::ReverseChainSingle; }
|
2010-04-23 02:15:11 +02:00
|
|
|
|
2018-12-17 19:01:01 +01:00
|
|
|
bool is_reverse () const
|
2009-05-20 05:42:30 +02:00
|
|
|
{
|
2009-04-16 01:50:16 +02:00
|
|
|
unsigned int type = get_type ();
|
2018-09-04 01:53:03 +02:00
|
|
|
if (unlikely (type == SubTable::Extension))
|
2010-04-23 22:35:01 +02:00
|
|
|
return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
|
2010-04-23 02:15:11 +02:00
|
|
|
return lookup_type_is_reverse (type);
|
2009-04-16 01:50:16 +02:00
|
|
|
}
|
2013-04-24 22:42:05 +02:00
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool apply (hb_ot_apply_context_t *c) const
|
2015-02-19 08:47:18 +01:00
|
|
|
{
|
|
|
|
TRACE_APPLY (this);
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (dispatch (c));
|
2015-02-19 08:47:18 +01:00
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool intersects (const hb_set_t *glyphs) const
|
2018-09-03 04:47:50 +02:00
|
|
|
{
|
|
|
|
hb_intersects_context_t c (glyphs);
|
|
|
|
return dispatch (&c);
|
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
hb_closure_context_t::return_t closure (hb_closure_context_t *c, unsigned int this_index) const
|
2012-11-23 23:55:40 +01:00
|
|
|
{
|
2018-06-12 05:24:41 +02:00
|
|
|
if (!c->should_visit_lookup (this_index))
|
2019-01-18 18:53:06 +01:00
|
|
|
return hb_closure_context_t::default_return_value ();
|
2018-06-06 02:14:42 +02:00
|
|
|
|
|
|
|
c->set_recurse_func (dispatch_closure_recurse_func);
|
2018-07-24 18:43:27 +02:00
|
|
|
|
|
|
|
hb_closure_context_t::return_t ret = dispatch (c);
|
|
|
|
|
|
|
|
c->flush ();
|
|
|
|
|
2019-01-18 18:53:06 +01:00
|
|
|
return ret;
|
2012-11-24 00:13:48 +01:00
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
|
2012-11-24 00:13:48 +01:00
|
|
|
{
|
2013-03-09 07:55:04 +01:00
|
|
|
c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
|
2019-01-18 20:59:18 +01:00
|
|
|
return dispatch (c);
|
2012-11-23 23:55:40 +01:00
|
|
|
}
|
|
|
|
|
2012-08-02 03:18:54 +02:00
|
|
|
template <typename set_t>
|
2018-12-16 20:08:10 +01:00
|
|
|
void add_coverage (set_t *glyphs) const
|
2012-08-02 03:18:54 +02:00
|
|
|
{
|
2015-02-17 17:15:34 +01:00
|
|
|
hb_add_coverage_context_t<set_t> c (glyphs);
|
|
|
|
dispatch (&c);
|
2012-08-02 03:18:54 +02:00
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool would_apply (hb_would_apply_context_t *c,
|
|
|
|
const hb_ot_layout_lookup_accelerator_t *accel) const
|
2012-04-20 04:21:38 +02:00
|
|
|
{
|
2019-03-30 06:12:42 +01:00
|
|
|
if (unlikely (!c->len)) return false;
|
|
|
|
if (!accel->may_have (c->glyphs[0])) return false;
|
|
|
|
return dispatch (c);
|
2012-04-20 04:21:38 +02:00
|
|
|
}
|
|
|
|
|
2019-04-12 23:50:03 +02:00
|
|
|
HB_INTERNAL static bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index);
|
2009-08-04 08:27:37 +02:00
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
SubTable& serialize_subtable (hb_serialize_context_t *c,
|
2019-06-01 00:48:54 +02:00
|
|
|
unsigned int i)
|
2018-09-04 01:53:03 +02:00
|
|
|
{ return get_subtables<SubTable> ()[i].serialize (c, this); }
|
2012-09-05 03:13:17 +02:00
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool serialize_single (hb_serialize_context_t *c,
|
|
|
|
uint32_t lookup_props,
|
2019-09-14 08:06:29 +02:00
|
|
|
hb_sorted_array_t<const HBGlyphID> glyphs,
|
|
|
|
hb_array_t<const HBGlyphID> substitutes)
|
2012-09-05 03:13:17 +02:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_SERIALIZE (this);
|
2018-09-04 01:53:03 +02:00
|
|
|
if (unlikely (!Lookup::serialize (c, SubTable::Single, lookup_props, 1))) return_trace (false);
|
2019-06-01 00:48:54 +02:00
|
|
|
return_trace (serialize_subtable (c, 0).u.single.
|
|
|
|
serialize (c, hb_zip (glyphs, substitutes)));
|
2012-09-05 03:13:17 +02:00
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool serialize_multiple (hb_serialize_context_t *c,
|
|
|
|
uint32_t lookup_props,
|
2019-09-14 08:06:29 +02:00
|
|
|
hb_sorted_array_t<const HBGlyphID> glyphs,
|
2018-12-18 22:49:08 +01:00
|
|
|
hb_array_t<const unsigned int> substitute_len_list,
|
2019-09-14 08:06:29 +02:00
|
|
|
hb_array_t<const HBGlyphID> substitute_glyphs_list)
|
2012-09-05 03:13:17 +02:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_SERIALIZE (this);
|
2018-09-04 01:53:03 +02:00
|
|
|
if (unlikely (!Lookup::serialize (c, SubTable::Multiple, lookup_props, 1))) return_trace (false);
|
2019-06-01 00:48:54 +02:00
|
|
|
return_trace (serialize_subtable (c, 0).u.multiple.
|
|
|
|
serialize (c,
|
|
|
|
glyphs,
|
|
|
|
substitute_len_list,
|
|
|
|
substitute_glyphs_list));
|
2012-09-05 03:13:17 +02:00
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool serialize_alternate (hb_serialize_context_t *c,
|
|
|
|
uint32_t lookup_props,
|
2019-09-14 08:06:29 +02:00
|
|
|
hb_sorted_array_t<const HBGlyphID> glyphs,
|
2018-12-18 22:49:08 +01:00
|
|
|
hb_array_t<const unsigned int> alternate_len_list,
|
2019-09-14 08:06:29 +02:00
|
|
|
hb_array_t<const HBGlyphID> alternate_glyphs_list)
|
2012-09-05 03:13:17 +02:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_SERIALIZE (this);
|
2018-09-04 01:53:03 +02:00
|
|
|
if (unlikely (!Lookup::serialize (c, SubTable::Alternate, lookup_props, 1))) return_trace (false);
|
2019-06-01 00:48:54 +02:00
|
|
|
return_trace (serialize_subtable (c, 0).u.alternate.
|
|
|
|
serialize (c,
|
|
|
|
glyphs,
|
|
|
|
alternate_len_list,
|
|
|
|
alternate_glyphs_list));
|
2012-09-05 03:13:17 +02:00
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool serialize_ligature (hb_serialize_context_t *c,
|
|
|
|
uint32_t lookup_props,
|
2019-09-14 08:06:29 +02:00
|
|
|
hb_sorted_array_t<const HBGlyphID> first_glyphs,
|
2018-12-18 22:49:08 +01:00
|
|
|
hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
|
2019-09-14 08:06:29 +02:00
|
|
|
hb_array_t<const HBGlyphID> ligatures_list,
|
2018-12-18 22:49:08 +01:00
|
|
|
hb_array_t<const unsigned int> component_count_list,
|
2019-09-14 08:06:29 +02:00
|
|
|
hb_array_t<const HBGlyphID> component_list /* Starting from second for each ligature */)
|
2012-09-05 03:13:17 +02:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_SERIALIZE (this);
|
2018-09-04 01:53:03 +02:00
|
|
|
if (unlikely (!Lookup::serialize (c, SubTable::Ligature, lookup_props, 1))) return_trace (false);
|
2019-06-01 00:48:54 +02:00
|
|
|
return_trace (serialize_subtable (c, 0).u.ligature.
|
|
|
|
serialize (c,
|
|
|
|
first_glyphs,
|
|
|
|
ligature_per_first_glyph_count_list,
|
|
|
|
ligatures_list,
|
|
|
|
component_count_list,
|
|
|
|
component_list));
|
2012-09-05 03:13:17 +02:00
|
|
|
}
|
|
|
|
|
2013-03-09 07:59:30 +01:00
|
|
|
template <typename context_t>
|
2019-04-12 23:50:03 +02:00
|
|
|
HB_INTERNAL static typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
|
2013-03-09 07:59:30 +01:00
|
|
|
|
2019-04-12 23:50:03 +02:00
|
|
|
HB_INTERNAL static hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_context_t *c, unsigned int lookup_index)
|
2018-06-06 02:14:42 +02:00
|
|
|
{
|
2018-06-12 05:24:41 +02:00
|
|
|
if (!c->should_visit_lookup (lookup_index))
|
2019-05-11 05:43:26 +02:00
|
|
|
return hb_empty_t ();
|
2018-07-24 18:43:27 +02:00
|
|
|
|
|
|
|
hb_closure_context_t::return_t ret = dispatch_recurse_func (c, lookup_index);
|
|
|
|
|
2018-11-23 03:30:04 +01:00
|
|
|
/* While in theory we should flush here, it will cause timeouts because a recursive
|
|
|
|
* lookup can keep growing the glyph set. Skip, and outer loop will retry up to
|
|
|
|
* HB_CLOSURE_MAX_STAGES time, which should be enough for every realistic font. */
|
|
|
|
//c->flush ();
|
2018-07-24 18:43:27 +02:00
|
|
|
|
|
|
|
return ret;
|
2018-06-06 02:14:42 +02:00
|
|
|
}
|
|
|
|
|
2019-05-05 19:14:17 +02:00
|
|
|
template <typename context_t, typename ...Ts>
|
2019-05-08 05:58:43 +02:00
|
|
|
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
|
2019-05-05 19:14:17 +02:00
|
|
|
{ return Lookup::dispatch<SubTable> (c, hb_forward<Ts> (ds)...); }
|
2018-09-04 01:53:03 +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
|
|
|
{ return Lookup::subset<SubTable> (c); }
|
2013-03-09 07:59:30 +01:00
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool sanitize (hb_sanitize_context_t *c) const
|
2018-09-04 02:16:09 +02:00
|
|
|
{ return Lookup::sanitize<SubTable> (c); }
|
2009-04-16 01:50:16 +02:00
|
|
|
};
|
|
|
|
|
2008-01-24 00:02:28 +01:00
|
|
|
/*
|
2018-04-12 11:08:19 +02:00
|
|
|
* GSUB -- Glyph Substitution
|
|
|
|
* https://docs.microsoft.com/en-us/typography/opentype/spec/gsub
|
2008-01-24 00:02:28 +01:00
|
|
|
*/
|
|
|
|
|
2009-05-20 05:42:30 +02:00
|
|
|
struct GSUB : GSUBGPOS
|
|
|
|
{
|
2019-01-22 12:08:57 +01:00
|
|
|
static constexpr hb_tag_t tableTag = HB_OT_TAG_GSUB;
|
2008-01-24 00:02:28 +01:00
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
const SubstLookup& get_lookup (unsigned int i) const
|
2010-04-23 22:35:01 +02:00
|
|
|
{ return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); }
|
2009-04-16 01:50:16 +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
|
|
|
{ return GSUBGPOS::subset<SubstLookup> (c); }
|
2018-09-01 01:31:00 +02:00
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool sanitize (hb_sanitize_context_t *c) const
|
2018-09-04 02:33:34 +02:00
|
|
|
{ return GSUBGPOS::sanitize<SubstLookup> (c); }
|
2018-08-26 09:47:55 +02:00
|
|
|
|
2018-11-25 22:51:22 +01:00
|
|
|
HB_INTERNAL bool is_blacklisted (hb_blob_t *blob,
|
|
|
|
hb_face_t *face) const;
|
|
|
|
|
2018-08-26 09:47:55 +02:00
|
|
|
typedef GSUBGPOS::accelerator_t<GSUB> accelerator_t;
|
2008-01-24 00:02:28 +01:00
|
|
|
};
|
2009-05-16 00:54:53 +02:00
|
|
|
|
|
|
|
|
2018-11-06 05:19:04 +01:00
|
|
|
struct GSUB_accelerator_t : GSUB::accelerator_t {};
|
|
|
|
|
|
|
|
|
2009-05-18 03:06:08 +02:00
|
|
|
/* Out-of-class implementation for methods recursing */
|
2009-05-16 00:54:53 +02:00
|
|
|
|
2019-06-26 22:44:10 +02:00
|
|
|
#ifndef HB_NO_OT_LAYOUT
|
2018-12-17 19:01:01 +01:00
|
|
|
/*static*/ inline bool ExtensionSubst::is_reverse () const
|
2010-04-23 02:15:11 +02:00
|
|
|
{
|
|
|
|
unsigned int type = get_type ();
|
2018-09-04 01:53:03 +02:00
|
|
|
if (unlikely (type == SubTable::Extension))
|
|
|
|
return CastR<ExtensionSubst> (get_subtable<SubTable>()).is_reverse ();
|
2010-04-23 02:15:11 +02:00
|
|
|
return SubstLookup::lookup_type_is_reverse (type);
|
|
|
|
}
|
2012-11-24 00:04:08 +01:00
|
|
|
template <typename context_t>
|
2014-04-28 23:29:39 +02:00
|
|
|
/*static*/ inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
|
2012-11-23 23:55:40 +01:00
|
|
|
{
|
2018-11-06 05:19:04 +01:00
|
|
|
const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index);
|
2013-03-09 07:55:04 +01:00
|
|
|
return l.dispatch (c);
|
2012-11-23 23:55:40 +01:00
|
|
|
}
|
2018-01-18 01:46:51 +01:00
|
|
|
/*static*/ inline bool SubstLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index)
|
2009-05-20 05:42:30 +02:00
|
|
|
{
|
2018-11-06 05:19:04 +01:00
|
|
|
const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index);
|
2012-11-24 07:13:20 +01:00
|
|
|
unsigned int saved_lookup_props = c->lookup_props;
|
2015-08-18 15:36:43 +02:00
|
|
|
unsigned int saved_lookup_index = c->lookup_index;
|
|
|
|
c->set_lookup_index (lookup_index);
|
|
|
|
c->set_lookup_props (l.get_props ());
|
2015-02-19 08:40:23 +01:00
|
|
|
bool ret = l.dispatch (c);
|
2015-08-18 15:36:43 +02:00
|
|
|
c->set_lookup_index (saved_lookup_index);
|
2015-01-29 08:01:12 +01:00
|
|
|
c->set_lookup_props (saved_lookup_props);
|
2012-11-24 07:13:20 +01:00
|
|
|
return ret;
|
2009-05-16 00:54:53 +02:00
|
|
|
}
|
2019-06-26 22:44:10 +02:00
|
|
|
#endif
|
|
|
|
|
2009-05-16 00:54:53 +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
|
|
|
|
2011-08-17 14:19:59 +02:00
|
|
|
#endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */
|