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 {
|
|
|
|
|
2009-05-18 02:28:01 +02:00
|
|
|
|
2018-09-04 05:50:11 +02:00
|
|
|
static inline void SingleSubst_serialize (hb_serialize_context_t *c,
|
2018-12-18 22:49:08 +01:00
|
|
|
hb_array_t<const GlyphID> glyphs,
|
|
|
|
hb_array_t<const GlyphID> substitutes);
|
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
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_CLOSURE (this);
|
2018-10-30 06:30:21 +01:00
|
|
|
for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
|
2016-12-20 22:01:16 +01:00
|
|
|
{
|
|
|
|
/* TODO Switch to range-based API to work around malicious fonts.
|
2017-11-20 20:49:22 +01:00
|
|
|
* https://github.com/harfbuzz/harfbuzz/issues/363 */
|
2012-04-23 21:28:35 +02:00
|
|
|
hb_codepoint_t glyph_id = iter.get_glyph ();
|
|
|
|
if (c->glyphs->has (glyph_id))
|
2018-07-24 18:43:27 +02:00
|
|
|
c->out->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
|
2012-04-23 21:28:35 +02: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
|
|
|
{
|
2012-11-24 00:13:48 +01:00
|
|
|
TRACE_COLLECT_GLYPHS (this);
|
2017-12-16 15:12:06 +01:00
|
|
|
if (unlikely (!(this+coverage).add_coverage (c->input))) return;
|
2018-10-30 06:30:21 +01:00
|
|
|
for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
|
2016-12-20 22:01:16 +01:00
|
|
|
{
|
|
|
|
/* TODO Switch to range-based API to work around malicious fonts.
|
2017-11-20 20:49:22 +01:00
|
|
|
* https://github.com/harfbuzz/harfbuzz/issues/363 */
|
2012-11-17 04:07:06 +01:00
|
|
|
hb_codepoint_t glyph_id = iter.get_glyph ();
|
2014-07-11 20:54:42 +02:00
|
|
|
c->output->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
|
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-11-22 20:38:10 +01:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_WOULD_APPLY (this);
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (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
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool serialize (hb_serialize_context_t *c,
|
2018-12-18 22:49:08 +01:00
|
|
|
hb_array_t<const GlyphID> glyphs,
|
2018-12-16 20:08:10 +01:00
|
|
|
int 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);
|
2018-10-19 17:49:21 +02:00
|
|
|
deltaGlyphID.set (delta); /* TODO(serialize) overflow? */
|
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);
|
2018-12-13 23:48:42 +01:00
|
|
|
const hb_set_t &glyphset = *c->plan->glyphset;
|
2018-12-12 04:53:58 +01:00
|
|
|
const hb_map_t &glyph_map = *c->plan->glyph_map;
|
2018-10-30 02:05:25 +01:00
|
|
|
hb_vector_t<GlyphID> from;
|
|
|
|
hb_vector_t<GlyphID> to;
|
2018-09-04 03:23:23 +02:00
|
|
|
hb_codepoint_t delta = deltaGlyphID;
|
2018-10-30 06:30:21 +01:00
|
|
|
for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
|
2018-09-04 03:23:23 +02:00
|
|
|
{
|
2018-12-13 23:48:42 +01:00
|
|
|
if (!glyphset.has (iter.get_glyph ())) continue;
|
2018-12-12 04:53:58 +01:00
|
|
|
from.push ()->set (glyph_map[iter.get_glyph ()]);
|
|
|
|
to.push ()->set (glyph_map[(iter.get_glyph () + delta) & 0xFFFF]);
|
2018-09-04 03:23:23 +02:00
|
|
|
}
|
2018-12-18 19:22:17 +01:00
|
|
|
c->serializer->propagate_error (from, to);
|
2018-12-18 22:49:08 +01:00
|
|
|
SingleSubst_serialize (c->serializer, from, to);
|
2018-09-04 05:50:11 +02:00
|
|
|
return_trace (from.len);
|
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 */
|
2018-02-27 21:45:26 +01:00
|
|
|
HBINT16 deltaGlyphID; /* Add to original GlyphID to get
|
2008-01-23 23:01:55 +01:00
|
|
|
* substitute GlyphID */
|
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
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_CLOSURE (this);
|
2016-12-20 22:01:16 +01:00
|
|
|
unsigned int count = substitute.len;
|
2018-10-30 06:30:21 +01:00
|
|
|
for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
|
2016-12-20 22:01:16 +01:00
|
|
|
{
|
|
|
|
if (unlikely (iter.get_coverage () >= count))
|
2017-11-20 20:49:22 +01:00
|
|
|
break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
|
2012-04-23 21:28:35 +02:00
|
|
|
if (c->glyphs->has (iter.get_glyph ()))
|
2018-07-24 18:43:27 +02:00
|
|
|
c->out->add (substitute[iter.get_coverage ()]);
|
2012-04-23 21:28:35 +02: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
|
|
|
{
|
2012-11-24 00:13:48 +01:00
|
|
|
TRACE_COLLECT_GLYPHS (this);
|
2017-12-16 15:12:06 +01:00
|
|
|
if (unlikely (!(this+coverage).add_coverage (c->input))) return;
|
2016-12-20 22:01:16 +01:00
|
|
|
unsigned int count = substitute.len;
|
2018-10-30 06:30:21 +01:00
|
|
|
for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
|
2016-12-20 22:01:16 +01:00
|
|
|
{
|
|
|
|
if (unlikely (iter.get_coverage () >= count))
|
2017-11-20 20:49:22 +01:00
|
|
|
break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
|
2012-12-04 23:08:41 +01:00
|
|
|
c->output->add (substitute[iter.get_coverage ()]);
|
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-11-22 20:38:10 +01:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_WOULD_APPLY (this);
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (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
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool serialize (hb_serialize_context_t *c,
|
2018-12-18 22:49:08 +01:00
|
|
|
hb_array_t<const GlyphID> glyphs,
|
|
|
|
hb_array_t<const GlyphID> substitutes)
|
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 (*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);
|
2018-12-13 23:48:42 +01:00
|
|
|
const hb_set_t &glyphset = *c->plan->glyphset;
|
2018-12-12 04:53:58 +01:00
|
|
|
const hb_map_t &glyph_map = *c->plan->glyph_map;
|
2018-10-30 02:05:25 +01:00
|
|
|
hb_vector_t<GlyphID> from;
|
|
|
|
hb_vector_t<GlyphID> to;
|
2018-10-30 06:30:21 +01:00
|
|
|
for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
|
2018-09-04 05:50:11 +02:00
|
|
|
{
|
2018-12-13 23:48:42 +01:00
|
|
|
if (!glyphset.has (iter.get_glyph ())) continue;
|
2018-12-12 04:53:58 +01:00
|
|
|
from.push ()->set (glyph_map[iter.get_glyph ()]);
|
|
|
|
to.push ()->set (glyph_map[substitute[iter.get_coverage ()]]);
|
2018-09-04 05:50:11 +02:00
|
|
|
}
|
2018-12-18 19:22:17 +01:00
|
|
|
c->serializer->propagate_error (from, to);
|
2018-12-18 22:49:08 +01:00
|
|
|
SingleSubst_serialize (c->serializer, from, to);
|
2018-09-04 05:50:11 +02:00
|
|
|
return_trace (from.len);
|
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 */
|
2009-05-17 07:22:51 +02:00
|
|
|
ArrayOf<GlyphID>
|
|
|
|
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
|
|
|
|
{
|
2018-12-16 20:08:10 +01:00
|
|
|
bool serialize (hb_serialize_context_t *c,
|
2018-12-18 22:49:08 +01:00
|
|
|
hb_array_t<const GlyphID> glyphs,
|
|
|
|
hb_array_t<const GlyphID> substitutes)
|
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);
|
2012-09-02 03:43:38 +02:00
|
|
|
unsigned int format = 2;
|
2014-10-15 05:07:31 +02:00
|
|
|
int delta = 0;
|
2018-12-18 22:49:08 +01:00
|
|
|
if (glyphs.len)
|
|
|
|
{
|
2012-09-02 03:43:38 +02:00
|
|
|
format = 1;
|
2012-09-04 02:58:03 +02:00
|
|
|
/* TODO(serialize) check for wrap-around */
|
2012-09-02 03:43:38 +02:00
|
|
|
delta = substitutes[0] - glyphs[0];
|
2018-12-18 22:49:08 +01:00
|
|
|
for (unsigned int i = 1; i < glyphs.len; i++)
|
2018-12-01 06:04:29 +01:00
|
|
|
if (delta != (int) (substitutes[i] - glyphs[i])) {
|
2012-09-02 03:43:38 +02:00
|
|
|
format = 2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
u.format.set (format);
|
|
|
|
switch (u.format) {
|
2018-12-18 22:49:08 +01:00
|
|
|
case 1: return_trace (u.format1.serialize (c, glyphs, delta));
|
|
|
|
case 2: return_trace (u.format2.serialize (c, glyphs, substitutes));
|
2015-09-29 15:57:02 +02:00
|
|
|
default:return_trace (false);
|
2012-09-02 03:43:38 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-09 07:59:30 +01:00
|
|
|
template <typename context_t>
|
2018-12-16 20:08:10 +01:00
|
|
|
typename context_t::return_t dispatch (context_t *c) 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) {
|
2015-09-29 15:57:02 +02:00
|
|
|
case 1: return_trace (c->dispatch (u.format1));
|
|
|
|
case 2: return_trace (c->dispatch (u.format2));
|
|
|
|
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
|
|
|
|
2018-09-04 05:50:11 +02:00
|
|
|
static inline void
|
|
|
|
SingleSubst_serialize (hb_serialize_context_t *c,
|
2018-12-18 22:49:08 +01:00
|
|
|
hb_array_t<const GlyphID> glyphs,
|
|
|
|
hb_array_t<const GlyphID> substitutes)
|
|
|
|
{ c->start_embed<SingleSubst> ()->serialize (c, glyphs, substitutes); }
|
2008-01-23 23:01:55 +01:00
|
|
|
|
2009-05-20 05:42:30 +02:00
|
|
|
struct Sequence
|
|
|
|
{
|
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-11-23 21:32:14 +01:00
|
|
|
TRACE_CLOSURE (this);
|
2012-04-23 21:28:35 +02:00
|
|
|
unsigned int count = substitute.len;
|
|
|
|
for (unsigned int i = 0; i < count; i++)
|
2018-07-24 18:43:27 +02:00
|
|
|
c->out->add (substitute[i]);
|
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
|
|
|
{
|
2012-11-24 00:13:48 +01:00
|
|
|
TRACE_COLLECT_GLYPHS (this);
|
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-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
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool serialize (hb_serialize_context_t *c,
|
2018-12-18 22:49:08 +01:00
|
|
|
hb_array_t<const GlyphID> glyphs)
|
2012-09-04 05:28:34 +02:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_SERIALIZE (this);
|
2018-12-18 22:49:08 +01:00
|
|
|
return_trace (substitute.serialize (c, glyphs));
|
2012-09-04 05:28: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 (substitute.sanitize (c));
|
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
|
|
|
ArrayOf<GlyphID>
|
|
|
|
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
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_CLOSURE (this);
|
2016-12-20 22:01:16 +01:00
|
|
|
unsigned int count = sequence.len;
|
2018-10-30 06:30:21 +01:00
|
|
|
for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
|
2016-12-20 22:01:16 +01:00
|
|
|
{
|
|
|
|
if (unlikely (iter.get_coverage () >= count))
|
2017-11-20 20:49:22 +01:00
|
|
|
break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
|
2012-04-23 21:28:35 +02:00
|
|
|
if (c->glyphs->has (iter.get_glyph ()))
|
2012-04-24 05:03:12 +02:00
|
|
|
(this+sequence[iter.get_coverage ()]).closure (c);
|
2012-04-23 21:28:35 +02: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
|
|
|
{
|
2012-11-24 00:13:48 +01:00
|
|
|
TRACE_COLLECT_GLYPHS (this);
|
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 = sequence.len;
|
|
|
|
for (unsigned int i = 0; i < count; i++)
|
2018-09-03 04:47:50 +02:00
|
|
|
(this+sequence[i]).collect_glyphs (c);
|
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-11-22 20:38:10 +01:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_WOULD_APPLY (this);
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (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,
|
2018-12-18 22:49:08 +01:00
|
|
|
hb_array_t<const GlyphID> glyphs,
|
|
|
|
hb_array_t<const unsigned int> substitute_len_list,
|
|
|
|
hb_array_t<const GlyphID> 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-18 22:49:08 +01:00
|
|
|
if (unlikely (!sequence.serialize (c, glyphs.len))) return_trace (false);
|
|
|
|
for (unsigned int i = 0; i < glyphs.len; i++)
|
|
|
|
{
|
|
|
|
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);
|
|
|
|
// 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) && 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,
|
2018-12-18 22:49:08 +01:00
|
|
|
hb_array_t<const GlyphID> glyphs,
|
|
|
|
hb_array_t<const unsigned int> substitute_len_list,
|
|
|
|
hb_array_t<const GlyphID> 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;
|
|
|
|
u.format.set (format);
|
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-09 07:59:30 +01:00
|
|
|
template <typename context_t>
|
2018-12-16 20:08:10 +01:00
|
|
|
typename context_t::return_t dispatch (context_t *c) 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) {
|
2015-09-29 15:57:02 +02:00
|
|
|
case 1: return_trace (c->dispatch (u.format1));
|
|
|
|
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
|
|
|
|
{
|
2018-12-16 20:08:10 +01:00
|
|
|
void closure (hb_closure_context_t *c) const
|
2018-09-03 04:47:50 +02:00
|
|
|
{
|
|
|
|
TRACE_CLOSURE (this);
|
|
|
|
unsigned int count = alternates.len;
|
|
|
|
for (unsigned int i = 0; i < count; i++)
|
|
|
|
c->out->add (alternates[i]);
|
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
void collect_glyphs (hb_collect_glyphs_context_t *c) const
|
2018-09-03 04:47:50 +02:00
|
|
|
{
|
|
|
|
TRACE_COLLECT_GLYPHS (this);
|
|
|
|
c->output->add_array (alternates.arrayZ, alternates.len);
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2018-09-10 22:37:19 +02:00
|
|
|
/* If alt_index is MAX, randomize feature if it is the rand feature. */
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool serialize (hb_serialize_context_t *c,
|
2018-12-18 22:49:08 +01:00
|
|
|
hb_array_t<const GlyphID> glyphs)
|
2018-09-03 04:47:50 +02:00
|
|
|
{
|
|
|
|
TRACE_SERIALIZE (this);
|
2018-12-18 22:49:08 +01:00
|
|
|
return_trace (alternates.serialize (c, glyphs));
|
2018-09-03 04:47:50 +02:00
|
|
|
}
|
|
|
|
|
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:
|
|
|
|
ArrayOf<GlyphID>
|
|
|
|
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
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_CLOSURE (this);
|
2016-12-20 22:01:16 +01:00
|
|
|
unsigned int count = alternateSet.len;
|
2018-10-30 06:30:21 +01:00
|
|
|
for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
|
2016-12-20 22:01:16 +01:00
|
|
|
{
|
|
|
|
if (unlikely (iter.get_coverage () >= count))
|
2018-11-15 20:40:56 +01:00
|
|
|
break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
|
2018-09-03 04:47:50 +02:00
|
|
|
if (c->glyphs->has (iter.get_glyph ()))
|
|
|
|
(this+alternateSet[iter.get_coverage ()]).closure (c);
|
2012-04-23 21:28:35 +02: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
|
|
|
{
|
2012-11-24 00:13:48 +01:00
|
|
|
TRACE_COLLECT_GLYPHS (this);
|
2017-12-16 15:12:06 +01:00
|
|
|
if (unlikely (!(this+coverage).add_coverage (c->input))) return;
|
2016-12-20 22:01:16 +01:00
|
|
|
unsigned int count = alternateSet.len;
|
2018-10-30 06:30:21 +01:00
|
|
|
for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
|
2016-12-20 22:01:16 +01:00
|
|
|
{
|
|
|
|
if (unlikely (iter.get_coverage () >= count))
|
2018-11-15 20:40:56 +01:00
|
|
|
break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
|
2018-09-03 04:47:50 +02:00
|
|
|
(this+alternateSet[iter.get_coverage ()]).collect_glyphs (c);
|
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-11-22 20:38:10 +01:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_WOULD_APPLY (this);
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (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,
|
2018-12-18 22:49:08 +01:00
|
|
|
hb_array_t<const GlyphID> glyphs,
|
|
|
|
hb_array_t<const unsigned int> alternate_len_list,
|
|
|
|
hb_array_t<const GlyphID> 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-18 22:49:08 +01:00
|
|
|
if (unlikely (!alternateSet.serialize (c, glyphs.len))) return_trace (false);
|
|
|
|
for (unsigned int i = 0; i < glyphs.len; i++)
|
|
|
|
{
|
|
|
|
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);
|
|
|
|
// 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) && 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,
|
2018-12-18 22:49:08 +01:00
|
|
|
hb_array_t<const GlyphID> glyphs,
|
|
|
|
hb_array_t<const unsigned int> alternate_len_list,
|
|
|
|
hb_array_t<const GlyphID> 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;
|
|
|
|
u.format.set (format);
|
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-09 07:59:30 +01:00
|
|
|
template <typename context_t>
|
2018-12-16 20:08:10 +01:00
|
|
|
typename context_t::return_t dispatch (context_t *c) 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) {
|
2015-09-29 15:57:02 +02:00
|
|
|
case 1: return_trace (c->dispatch (u.format1));
|
|
|
|
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
|
2018-09-03 04:47:50 +02:00
|
|
|
{
|
2018-09-13 20:21:54 +02:00
|
|
|
unsigned int count = component.lenP1;
|
2018-09-03 04:47:50 +02:00
|
|
|
for (unsigned int i = 1; i < count; i++)
|
|
|
|
if (!glyphs->has (component[i]))
|
|
|
|
return false;
|
|
|
|
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
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_CLOSURE (this);
|
2018-09-13 20:21:54 +02:00
|
|
|
unsigned int count = component.lenP1;
|
2012-04-23 21:28:35 +02:00
|
|
|
for (unsigned int i = 1; i < count; i++)
|
|
|
|
if (!c->glyphs->has (component[i]))
|
2012-04-24 05:03:12 +02:00
|
|
|
return;
|
2018-07-24 18:43:27 +02:00
|
|
|
c->out->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
|
|
|
{
|
2012-11-24 00:13:48 +01:00
|
|
|
TRACE_COLLECT_GLYPHS (this);
|
2018-09-13 20:21:54 +02:00
|
|
|
c->input->add_array (component.arrayZ, component.lenP1 ? component.lenP1 - 1 : 0);
|
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
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_WOULD_APPLY (this);
|
2018-09-13 20:21:54 +02:00
|
|
|
if (c->len != component.lenP1)
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (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]))
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (false);
|
2012-08-08 04:25:24 +02:00
|
|
|
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (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
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
bool serialize (hb_serialize_context_t *c,
|
|
|
|
GlyphID ligature,
|
2018-12-18 22:49:08 +01:00
|
|
|
hb_array_t<const GlyphID> 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
|
|
|
}
|
|
|
|
|
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:
|
2009-04-16 10:45:30 +02:00
|
|
|
GlyphID ligGlyph; /* GlyphID of ligature to substitute */
|
2009-05-18 08:03:58 +02:00
|
|
|
HeadlessArrayOf<GlyphID>
|
|
|
|
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
|
|
|
{
|
|
|
|
unsigned int num_ligs = ligature.len;
|
|
|
|
for (unsigned int i = 0; i < num_ligs; i++)
|
|
|
|
if ((this+ligature[i]).intersects (glyphs))
|
|
|
|
return true;
|
|
|
|
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-11-23 21:32:14 +01:00
|
|
|
TRACE_CLOSURE (this);
|
2012-04-23 21:28:35 +02:00
|
|
|
unsigned int num_ligs = ligature.len;
|
|
|
|
for (unsigned int i = 0; i < num_ligs; i++)
|
2012-04-24 05:03:12 +02:00
|
|
|
(this+ligature[i]).closure (c);
|
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
|
|
|
{
|
2012-11-24 00:13:48 +01:00
|
|
|
TRACE_COLLECT_GLYPHS (this);
|
2012-11-17 04:07:06 +01:00
|
|
|
unsigned int num_ligs = ligature.len;
|
|
|
|
for (unsigned int i = 0; i < num_ligs; i++)
|
|
|
|
(this+ligature[i]).collect_glyphs (c);
|
|
|
|
}
|
|
|
|
|
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-23 21:32:14 +01:00
|
|
|
TRACE_WOULD_APPLY (this);
|
2012-04-20 04:21:38 +02:00
|
|
|
unsigned int num_ligs = ligature.len;
|
|
|
|
for (unsigned int i = 0; i < num_ligs; i++)
|
|
|
|
{
|
|
|
|
const Ligature &lig = this+ligature[i];
|
2012-07-19 20:35:23 +02:00
|
|
|
if (lig.would_apply (c))
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (true);
|
2012-04-20 04:21:38 +02:00
|
|
|
}
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (false);
|
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,
|
2018-12-18 22:49:08 +01:00
|
|
|
hb_array_t<const GlyphID> ligatures,
|
|
|
|
hb_array_t<const unsigned int> component_count_list,
|
2018-12-21 21:56:01 +01:00
|
|
|
hb_array_t<const GlyphID> &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-18 22:49:08 +01:00
|
|
|
if (unlikely (!ligature.serialize (c, ligatures.len))) return_trace (false);
|
|
|
|
for (unsigned int i = 0; i < ligatures.len; i++)
|
|
|
|
{
|
|
|
|
unsigned int component_count = MAX<int> (component_count_list[i] - 1, 0);
|
|
|
|
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
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
|
|
|
unsigned int count = ligatureSet.len;
|
2018-10-30 06:30:21 +01:00
|
|
|
for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
|
2018-09-03 04:47:50 +02:00
|
|
|
{
|
|
|
|
if (unlikely (iter.get_coverage () >= count))
|
|
|
|
break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
|
|
|
|
if (glyphs->has (iter.get_glyph ()) &&
|
|
|
|
(this+ligatureSet[iter.get_coverage ()]).intersects (glyphs))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
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-11-23 21:32:14 +01:00
|
|
|
TRACE_CLOSURE (this);
|
2016-12-20 22:01:16 +01:00
|
|
|
unsigned int count = ligatureSet.len;
|
2018-10-30 06:30:21 +01:00
|
|
|
for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
|
2016-12-20 22:01:16 +01:00
|
|
|
{
|
|
|
|
if (unlikely (iter.get_coverage () >= count))
|
2017-11-20 20:49:22 +01:00
|
|
|
break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
|
2012-04-23 21:28:35 +02:00
|
|
|
if (c->glyphs->has (iter.get_glyph ()))
|
2012-04-24 05:03:12 +02:00
|
|
|
(this+ligatureSet[iter.get_coverage ()]).closure (c);
|
2012-04-23 21:28:35 +02: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
|
|
|
{
|
2012-11-24 00:13:48 +01:00
|
|
|
TRACE_COLLECT_GLYPHS (this);
|
2017-12-16 15:12:06 +01:00
|
|
|
if (unlikely (!(this+coverage).add_coverage (c->input))) return;
|
2016-12-20 22:01:16 +01:00
|
|
|
unsigned int count = ligatureSet.len;
|
2018-10-30 06:30:21 +01:00
|
|
|
for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
|
2016-12-20 22:01:16 +01:00
|
|
|
{
|
|
|
|
if (unlikely (iter.get_coverage () >= count))
|
2017-11-20 20:49:22 +01:00
|
|
|
break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
|
2012-11-17 04:07:06 +01:00
|
|
|
(this+ligatureSet[iter.get_coverage ()]).collect_glyphs (c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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-23 21:32:14 +01:00
|
|
|
TRACE_WOULD_APPLY (this);
|
2012-11-25 01:13:55 +01:00
|
|
|
unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
|
2015-09-29 15:57:02 +02:00
|
|
|
if (likely (index == NOT_COVERED)) return_trace (false);
|
2012-11-22 20:38:10 +01:00
|
|
|
|
|
|
|
const LigatureSet &lig_set = this+ligatureSet[index];
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (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,
|
2018-12-18 22:49:08 +01:00
|
|
|
hb_array_t<const GlyphID> first_glyphs,
|
|
|
|
hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
|
|
|
|
hb_array_t<const GlyphID> ligatures_list,
|
|
|
|
hb_array_t<const unsigned int> component_count_list,
|
|
|
|
hb_array_t<const GlyphID> 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-18 22:49:08 +01:00
|
|
|
if (unlikely (!ligatureSet.serialize (c, first_glyphs.len))) return_trace (false);
|
|
|
|
for (unsigned int i = 0; i < first_glyphs.len; i++)
|
|
|
|
{
|
|
|
|
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);
|
|
|
|
// 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) && 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,
|
2018-12-18 22:49:08 +01:00
|
|
|
hb_array_t<const GlyphID> first_glyphs,
|
|
|
|
hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
|
|
|
|
hb_array_t<const GlyphID> ligatures_list,
|
|
|
|
hb_array_t<const unsigned int> component_count_list,
|
|
|
|
hb_array_t<const GlyphID> 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;
|
|
|
|
u.format.set (format);
|
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-09 07:59:30 +01:00
|
|
|
template <typename context_t>
|
2018-12-16 20:08:10 +01:00
|
|
|
typename context_t::return_t dispatch (context_t *c) 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) {
|
2015-09-29 15:57:02 +02:00
|
|
|
case 1: return_trace (c->dispatch (u.format1));
|
|
|
|
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;
|
|
|
|
|
|
|
|
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
|
|
|
|
|
|
|
|
unsigned int count;
|
|
|
|
|
|
|
|
count = backtrack.len;
|
|
|
|
for (unsigned int i = 0; i < count; i++)
|
|
|
|
if (!(this+backtrack[i]).intersects (glyphs))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
count = lookahead.len;
|
|
|
|
for (unsigned int i = 0; i < count; i++)
|
|
|
|
if (!(this+lookahead[i]).intersects (glyphs))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
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
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_CLOSURE (this);
|
2012-04-23 21:28:35 +02:00
|
|
|
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
|
|
|
|
|
|
|
|
unsigned int count;
|
|
|
|
|
|
|
|
count = backtrack.len;
|
|
|
|
for (unsigned int i = 0; i < count; i++)
|
|
|
|
if (!(this+backtrack[i]).intersects (c->glyphs))
|
2012-04-24 05:03:12 +02:00
|
|
|
return;
|
2012-04-23 21:28:35 +02:00
|
|
|
|
|
|
|
count = lookahead.len;
|
|
|
|
for (unsigned int i = 0; i < count; i++)
|
|
|
|
if (!(this+lookahead[i]).intersects (c->glyphs))
|
2012-04-24 05:03:12 +02:00
|
|
|
return;
|
2012-04-23 21:28:35 +02:00
|
|
|
|
|
|
|
const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
|
2016-12-20 22:01:16 +01:00
|
|
|
count = substitute.len;
|
2018-10-30 06:30:21 +01:00
|
|
|
for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
|
2016-12-20 22:01:16 +01:00
|
|
|
{
|
|
|
|
if (unlikely (iter.get_coverage () >= count))
|
2017-11-20 20:49:22 +01:00
|
|
|
break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
|
2012-04-23 21:28:35 +02:00
|
|
|
if (c->glyphs->has (iter.get_glyph ()))
|
2018-07-24 18:43:27 +02:00
|
|
|
c->out->add (substitute[iter.get_coverage ()]);
|
2012-04-23 21:28:35 +02: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
|
|
|
{
|
2012-11-24 00:13:48 +01:00
|
|
|
TRACE_COLLECT_GLYPHS (this);
|
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
|
|
|
|
2017-12-16 15:12:06 +01: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
|
|
|
|
|
|
|
const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
|
|
|
|
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
|
2012-11-22 20:38:10 +01:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_WOULD_APPLY (this);
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (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
|
|
|
|
2010-04-21 21:56:11 +02:00
|
|
|
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
|
|
|
|
const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (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) &&
|
2010-05-13 20:18:49 +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);
|
2015-02-17 15:27:44 +01: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);
|
2015-02-17 15:27:44 +01:00
|
|
|
const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (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 */
|
2009-05-18 11:47:47 +02:00
|
|
|
ArrayOf<GlyphID>
|
|
|
|
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
|
|
|
|
{
|
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));
|
|
|
|
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
|
|
|
};
|
|
|
|
|
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, unsigned int lookup_type) 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) {
|
2015-09-29 15:57:02 +02:00
|
|
|
case Single: return_trace (u.single.dispatch (c));
|
|
|
|
case Multiple: return_trace (u.multiple.dispatch (c));
|
|
|
|
case Alternate: return_trace (u.alternate.dispatch (c));
|
|
|
|
case Ligature: return_trace (u.ligature.dispatch (c));
|
|
|
|
case Context: return_trace (u.context.dispatch (c));
|
|
|
|
case ChainContext: return_trace (u.chainContext.dispatch (c));
|
|
|
|
case Extension: return_trace (u.extension.dispatch (c));
|
|
|
|
case ReverseChainSingle: return_trace (u.reverseChainContextSingle.dispatch (c));
|
|
|
|
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
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
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
|
|
|
{
|
2012-11-24 00:13:48 +01:00
|
|
|
TRACE_CLOSURE (this);
|
2018-06-12 05:24:41 +02:00
|
|
|
if (!c->should_visit_lookup (this_index))
|
2018-06-06 02:14:42 +02:00
|
|
|
return_trace (HB_VOID);
|
|
|
|
|
|
|
|
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 ();
|
|
|
|
|
|
|
|
return_trace (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
|
|
|
{
|
|
|
|
TRACE_COLLECT_GLYPHS (this);
|
2013-03-09 07:55:04 +01:00
|
|
|
c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (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
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_WOULD_APPLY (this);
|
2015-09-29 15:57:02 +02:00
|
|
|
if (unlikely (!c->len)) return_trace (false);
|
|
|
|
if (!accel->may_have (c->glyphs[0])) return_trace (false);
|
|
|
|
return_trace (dispatch (c));
|
2012-04-20 04:21:38 +02:00
|
|
|
}
|
|
|
|
|
2018-01-18 01:46:51 +01:00
|
|
|
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,
|
2018-09-04 01:53:03 +02:00
|
|
|
unsigned int i)
|
|
|
|
{ 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,
|
2018-12-18 22:49:08 +01:00
|
|
|
hb_array_t<const GlyphID> glyphs,
|
|
|
|
hb_array_t<const GlyphID> 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);
|
2018-12-18 22:49:08 +01:00
|
|
|
return_trace (serialize_subtable (c, 0).u.single.serialize (c, 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,
|
2018-12-18 22:49:08 +01:00
|
|
|
hb_array_t<const GlyphID> glyphs,
|
|
|
|
hb_array_t<const unsigned int> substitute_len_list,
|
|
|
|
hb_array_t<const GlyphID> 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);
|
2015-09-29 15:57:02 +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,
|
2018-12-18 22:49:08 +01:00
|
|
|
hb_array_t<const GlyphID> glyphs,
|
|
|
|
hb_array_t<const unsigned int> alternate_len_list,
|
|
|
|
hb_array_t<const GlyphID> 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);
|
2015-09-29 15:57:02 +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,
|
2018-12-18 22:49:08 +01:00
|
|
|
hb_array_t<const GlyphID> first_glyphs,
|
|
|
|
hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
|
|
|
|
hb_array_t<const GlyphID> ligatures_list,
|
|
|
|
hb_array_t<const unsigned int> component_count_list,
|
|
|
|
hb_array_t<const GlyphID> 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);
|
2015-09-29 15:57:02 +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>
|
2018-12-16 20:08:10 +01:00
|
|
|
static typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
|
2013-03-09 07:59:30 +01:00
|
|
|
|
2018-12-16 20:08:10 +01:00
|
|
|
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))
|
2018-06-06 02:14:42 +02:00
|
|
|
return HB_VOID;
|
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
|
|
|
}
|
|
|
|
|
2013-03-09 07:59:30 +01:00
|
|
|
template <typename context_t>
|
2018-12-16 20:08:10 +01:00
|
|
|
typename context_t::return_t dispatch (context_t *c) const
|
2018-09-04 01:53:03 +02:00
|
|
|
{ return Lookup::dispatch<SubTable> (c); }
|
|
|
|
|
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
|
|
|
|
{
|
2018-11-29 21:04:34 +01:00
|
|
|
enum { 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
|
|
|
|
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
|
|
|
}
|
|
|
|
|
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 */
|