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,
|
|
|
|
Supplier<GlyphID> &glyphs,
|
|
|
|
Supplier<GlyphID> &substitutes,
|
|
|
|
unsigned int num_glyphs);
|
|
|
|
|
2009-05-20 05:42:30 +02:00
|
|
|
struct SingleSubstFormat1
|
|
|
|
{
|
2018-09-03 04:47:50 +02:00
|
|
|
inline bool intersects (const hb_set_t *glyphs) const
|
|
|
|
{ return (this+coverage).intersects (glyphs); }
|
|
|
|
|
2012-04-24 05:03:12 +02:00
|
|
|
inline 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-08-26 06:15:39 +02:00
|
|
|
for (hb_auto_t<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
|
|
|
}
|
|
|
|
|
2012-11-17 04:07:06 +01:00
|
|
|
inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
|
|
|
|
{
|
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-08-26 06:15:39 +02:00
|
|
|
for (hb_auto_t<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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-28 23:31:01 +02:00
|
|
|
inline const Coverage &get_coverage (void) const
|
2018-09-03 04:47:50 +02:00
|
|
|
{ return this+coverage; }
|
2012-07-28 23:31:01 +02:00
|
|
|
|
2012-11-22 20:38:10 +01:00
|
|
|
inline bool would_apply (hb_would_apply_context_t *c) const
|
|
|
|
{
|
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-01-18 01:46:51 +01:00
|
|
|
inline 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
|
|
|
|
2012-09-02 02:48:22 +02:00
|
|
|
inline bool serialize (hb_serialize_context_t *c,
|
2012-09-05 00:17:57 +02:00
|
|
|
Supplier<GlyphID> &glyphs,
|
2012-09-02 02:48:22 +02:00
|
|
|
unsigned int num_glyphs,
|
2012-09-05 00:17:21 +02: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);
|
|
|
|
if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
|
2012-09-04 02:58:03 +02:00
|
|
|
deltaGlyphID.set (delta); /* TODO(serilaize) overflow? */
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (true);
|
2012-09-02 02:48:22 +02:00
|
|
|
}
|
|
|
|
|
2018-09-04 02:33:34 +02:00
|
|
|
inline bool subset (hb_subset_context_t *c) const
|
|
|
|
{
|
|
|
|
TRACE_SUBSET (this);
|
2018-09-04 05:50:11 +02:00
|
|
|
hb_auto_t<hb_vector_t<GlyphID>> from;
|
|
|
|
hb_auto_t<hb_vector_t<GlyphID>> to;
|
2018-09-04 03:23:23 +02:00
|
|
|
hb_codepoint_t delta = deltaGlyphID;
|
|
|
|
for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
|
|
|
|
{
|
2018-09-04 05:50:11 +02:00
|
|
|
if (!c->plan->glyphset->has (iter.get_glyph ()))
|
|
|
|
continue;
|
|
|
|
from.push ()->set (iter.get_glyph ());
|
|
|
|
to.push ()->set ((iter.get_glyph () + delta) & 0xFFFF);
|
2018-09-04 03:23:23 +02:00
|
|
|
}
|
2018-09-04 05:50:11 +02:00
|
|
|
c->serializer->err (from.in_error () || to.in_error ());
|
|
|
|
|
|
|
|
Supplier<GlyphID> from_supplier (&from);
|
|
|
|
Supplier<GlyphID> to_supplier (&to);
|
|
|
|
SingleSubst_serialize (c->serializer,
|
|
|
|
from_supplier,
|
|
|
|
to_supplier,
|
|
|
|
from.len);
|
|
|
|
return_trace (from.len);
|
2018-09-04 02:33:34 +02:00
|
|
|
}
|
|
|
|
|
2015-02-17 15:27:44 +01:00
|
|
|
inline bool sanitize (hb_sanitize_context_t *c) const
|
|
|
|
{
|
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-09-03 04:47:50 +02:00
|
|
|
inline bool intersects (const hb_set_t *glyphs) const
|
|
|
|
{ return (this+coverage).intersects (glyphs); }
|
|
|
|
|
2012-04-24 05:03:12 +02:00
|
|
|
inline 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-08-26 06:15:39 +02:00
|
|
|
for (hb_auto_t<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
|
|
|
}
|
|
|
|
|
2012-11-17 04:07:06 +01:00
|
|
|
inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
|
|
|
|
{
|
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-08-26 06:15:39 +02:00
|
|
|
for (hb_auto_t<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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-28 23:31:01 +02:00
|
|
|
inline const Coverage &get_coverage (void) const
|
2018-09-03 04:47:50 +02:00
|
|
|
{ return this+coverage; }
|
2012-07-28 23:31:01 +02:00
|
|
|
|
2012-11-22 20:38:10 +01:00
|
|
|
inline bool would_apply (hb_would_apply_context_t *c) const
|
|
|
|
{
|
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-01-18 01:46:51 +01:00
|
|
|
inline 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
|
|
|
|
2012-09-02 03:43:38 +02:00
|
|
|
inline bool serialize (hb_serialize_context_t *c,
|
2012-09-05 00:17:57 +02:00
|
|
|
Supplier<GlyphID> &glyphs,
|
|
|
|
Supplier<GlyphID> &substitutes,
|
2012-09-02 03:43:38 +02:00
|
|
|
unsigned int num_glyphs)
|
|
|
|
{
|
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);
|
|
|
|
if (unlikely (!substitute.serialize (c, substitutes, num_glyphs))) return_trace (false);
|
|
|
|
if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
|
|
|
|
return_trace (true);
|
2012-09-02 03:43:38 +02:00
|
|
|
}
|
|
|
|
|
2018-09-04 02:33:34 +02:00
|
|
|
inline bool subset (hb_subset_context_t *c) const
|
|
|
|
{
|
|
|
|
TRACE_SUBSET (this);
|
2018-09-04 05:50:11 +02:00
|
|
|
hb_auto_t<hb_vector_t<GlyphID>> from;
|
|
|
|
hb_auto_t<hb_vector_t<GlyphID>> to;
|
|
|
|
for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
|
|
|
|
{
|
|
|
|
if (!c->plan->glyphset->has (iter.get_glyph ()))
|
|
|
|
continue;
|
|
|
|
from.push ()->set (iter.get_glyph ());
|
|
|
|
to.push ()->set (substitute[iter.get_coverage ()]);
|
|
|
|
}
|
|
|
|
c->serializer->err (from.in_error () || to.in_error ());
|
|
|
|
|
|
|
|
Supplier<GlyphID> from_supplier (&from);
|
|
|
|
Supplier<GlyphID> to_supplier (&to);
|
|
|
|
SingleSubst_serialize (c->serializer,
|
|
|
|
from_supplier,
|
|
|
|
to_supplier,
|
|
|
|
from.len);
|
|
|
|
return_trace (from.len);
|
2018-09-04 02:33:34 +02:00
|
|
|
}
|
|
|
|
|
2015-02-17 15:27:44 +01:00
|
|
|
inline bool sanitize (hb_sanitize_context_t *c) const
|
|
|
|
{
|
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
|
|
|
|
{
|
2012-09-02 03:43:38 +02:00
|
|
|
inline bool serialize (hb_serialize_context_t *c,
|
2012-09-05 00:17:57 +02:00
|
|
|
Supplier<GlyphID> &glyphs,
|
|
|
|
Supplier<GlyphID> &substitutes,
|
2012-09-02 03:43:38 +02:00
|
|
|
unsigned int num_glyphs)
|
|
|
|
{
|
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;
|
2012-09-02 03:43:38 +02:00
|
|
|
if (num_glyphs) {
|
|
|
|
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];
|
|
|
|
for (unsigned int i = 1; i < num_glyphs; i++)
|
|
|
|
if (delta != substitutes[i] - glyphs[i]) {
|
|
|
|
format = 2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
u.format.set (format);
|
|
|
|
switch (u.format) {
|
2015-09-29 15:57:02 +02:00
|
|
|
case 1: return_trace (u.format1.serialize (c, glyphs, num_glyphs, delta));
|
|
|
|
case 2: return_trace (u.format2.serialize (c, glyphs, substitutes, num_glyphs));
|
|
|
|
default:return_trace (false);
|
2012-09-02 03:43:38 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-09 07:59:30 +01:00
|
|
|
template <typename context_t>
|
|
|
|
inline typename context_t::return_t dispatch (context_t *c) const
|
|
|
|
{
|
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,
|
|
|
|
Supplier<GlyphID> &glyphs,
|
|
|
|
Supplier<GlyphID> &substitutes,
|
|
|
|
unsigned int num_glyphs)
|
|
|
|
{
|
|
|
|
c->start_embed<SingleSubst> ()->serialize (c,
|
|
|
|
glyphs,
|
|
|
|
substitutes,
|
|
|
|
num_glyphs);
|
|
|
|
}
|
2008-01-23 23:01:55 +01:00
|
|
|
|
2009-05-20 05:42:30 +02:00
|
|
|
struct Sequence
|
|
|
|
{
|
2012-04-24 05:03:12 +02:00
|
|
|
inline 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
|
|
|
}
|
|
|
|
|
2012-11-17 04:07:06 +01:00
|
|
|
inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
|
|
|
|
{
|
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-01-18 01:46:51 +01:00
|
|
|
inline 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
|
|
|
}
|
|
|
|
|
2012-09-04 05:28:34 +02:00
|
|
|
inline bool serialize (hb_serialize_context_t *c,
|
2012-09-05 00:17:57 +02:00
|
|
|
Supplier<GlyphID> &glyphs,
|
2012-09-04 05:28:34 +02:00
|
|
|
unsigned int num_glyphs)
|
|
|
|
{
|
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);
|
|
|
|
if (unlikely (!substitute.serialize (c, glyphs, num_glyphs))) return_trace (false);
|
|
|
|
return_trace (true);
|
2012-09-04 05:28:34 +02:00
|
|
|
}
|
|
|
|
|
2015-02-17 15:27:44 +01:00
|
|
|
inline bool sanitize (hb_sanitize_context_t *c) const
|
|
|
|
{
|
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-09-03 04:47:50 +02:00
|
|
|
inline bool intersects (const hb_set_t *glyphs) const
|
|
|
|
{ return (this+coverage).intersects (glyphs); }
|
|
|
|
|
2012-04-24 05:03:12 +02:00
|
|
|
inline 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-08-26 06:15:39 +02:00
|
|
|
for (hb_auto_t<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
|
|
|
}
|
|
|
|
|
2012-11-17 04:07:06 +01:00
|
|
|
inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
|
|
|
|
{
|
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
|
|
|
}
|
|
|
|
|
2012-07-28 23:31:01 +02:00
|
|
|
inline const Coverage &get_coverage (void) const
|
2018-09-03 04:47:50 +02:00
|
|
|
{ return this+coverage; }
|
2012-07-28 23:31:01 +02:00
|
|
|
|
2012-11-22 20:38:10 +01:00
|
|
|
inline bool would_apply (hb_would_apply_context_t *c) const
|
|
|
|
{
|
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-01-18 01:46:51 +01:00
|
|
|
inline 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
|
|
|
|
2012-09-04 05:28:34 +02:00
|
|
|
inline bool serialize (hb_serialize_context_t *c,
|
2012-09-05 00:17:57 +02:00
|
|
|
Supplier<GlyphID> &glyphs,
|
|
|
|
Supplier<unsigned int> &substitute_len_list,
|
2012-09-04 05:28:34 +02:00
|
|
|
unsigned int num_glyphs,
|
2012-09-05 00:17:57 +02:00
|
|
|
Supplier<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);
|
|
|
|
if (unlikely (!sequence.serialize (c, num_glyphs))) return_trace (false);
|
2012-09-05 00:17:57 +02:00
|
|
|
for (unsigned int i = 0; i < num_glyphs; i++)
|
|
|
|
if (unlikely (!sequence[i].serialize (c, this).serialize (c,
|
|
|
|
substitute_glyphs_list,
|
2015-09-29 15:57:02 +02:00
|
|
|
substitute_len_list[i]))) return_trace (false);
|
2018-02-10 20:15:57 +01:00
|
|
|
substitute_len_list += num_glyphs;
|
2015-09-29 15:57:02 +02:00
|
|
|
if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
|
|
|
|
return_trace (true);
|
2012-09-04 05:28:34 +02:00
|
|
|
}
|
|
|
|
|
2018-09-04 02:33:34 +02:00
|
|
|
inline bool subset (hb_subset_context_t *c) const
|
|
|
|
{
|
|
|
|
TRACE_SUBSET (this);
|
|
|
|
// TODO(subset)
|
|
|
|
return_trace (false);
|
|
|
|
}
|
|
|
|
|
2015-02-17 15:27:44 +01:00
|
|
|
inline bool sanitize (hb_sanitize_context_t *c) const
|
|
|
|
{
|
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
|
|
|
|
{
|
2012-09-04 05:28:34 +02:00
|
|
|
inline bool serialize (hb_serialize_context_t *c,
|
2012-09-05 00:17:57 +02:00
|
|
|
Supplier<GlyphID> &glyphs,
|
|
|
|
Supplier<unsigned int> &substitute_len_list,
|
2012-09-04 05:28:34 +02:00
|
|
|
unsigned int num_glyphs,
|
2012-09-05 00:17:57 +02:00
|
|
|
Supplier<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) {
|
2015-09-29 15:57:02 +02:00
|
|
|
case 1: return_trace (u.format1.serialize (c, glyphs, substitute_len_list, num_glyphs, substitute_glyphs_list));
|
|
|
|
default:return_trace (false);
|
2012-09-04 05:28:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-09 07:59:30 +01:00
|
|
|
template <typename context_t>
|
|
|
|
inline typename context_t::return_t dispatch (context_t *c) const
|
|
|
|
{
|
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
|
|
|
|
{
|
|
|
|
inline void closure (hb_closure_context_t *c) const
|
|
|
|
{
|
|
|
|
TRACE_CLOSURE (this);
|
|
|
|
unsigned int count = alternates.len;
|
|
|
|
for (unsigned int i = 0; i < count; i++)
|
|
|
|
c->out->add (alternates[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
|
|
|
|
{
|
|
|
|
TRACE_COLLECT_GLYPHS (this);
|
|
|
|
c->output->add_array (alternates.arrayZ, alternates.len);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool apply (hb_ot_apply_context_t *c) const
|
|
|
|
{
|
|
|
|
TRACE_APPLY (this);
|
|
|
|
unsigned int count = alternates.len;
|
|
|
|
|
|
|
|
if (unlikely (!count)) return_trace (false);
|
|
|
|
|
|
|
|
hb_mask_t glyph_mask = c->buffer->cur().mask;
|
|
|
|
hb_mask_t lookup_mask = c->lookup_mask;
|
|
|
|
|
|
|
|
/* 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);
|
|
|
|
|
|
|
|
if (unlikely (alt_index > count || alt_index == 0)) return_trace (false);
|
|
|
|
|
|
|
|
c->replace_glyph (alternates[alt_index - 1]);
|
2008-01-23 23:01:55 +01:00
|
|
|
|
2018-09-03 04:47:50 +02:00
|
|
|
return_trace (true);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool serialize (hb_serialize_context_t *c,
|
|
|
|
Supplier<GlyphID> &glyphs,
|
|
|
|
unsigned int num_glyphs)
|
|
|
|
{
|
|
|
|
TRACE_SERIALIZE (this);
|
|
|
|
if (unlikely (!c->extend_min (*this))) return_trace (false);
|
|
|
|
if (unlikely (!alternates.serialize (c, glyphs, num_glyphs))) return_trace (false);
|
|
|
|
return_trace (true);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool sanitize (hb_sanitize_context_t *c) const
|
|
|
|
{
|
|
|
|
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-09-03 04:47:50 +02:00
|
|
|
inline bool intersects (const hb_set_t *glyphs) const
|
|
|
|
{ return (this+coverage).intersects (glyphs); }
|
|
|
|
|
2012-04-24 05:03:12 +02:00
|
|
|
inline 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-08-26 06:15:39 +02:00
|
|
|
for (hb_auto_t<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 */
|
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
|
|
|
}
|
|
|
|
|
2012-11-17 04:07:06 +01:00
|
|
|
inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
|
|
|
|
{
|
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-08-26 06:15:39 +02:00
|
|
|
for (hb_auto_t<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 */
|
2018-09-03 04:47:50 +02:00
|
|
|
(this+alternateSet[iter.get_coverage ()]).collect_glyphs (c);
|
2012-11-17 04:07:06 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-28 23:31:01 +02:00
|
|
|
inline const Coverage &get_coverage (void) const
|
2018-09-03 04:47:50 +02:00
|
|
|
{ return this+coverage; }
|
2012-07-28 23:31:01 +02:00
|
|
|
|
2012-11-22 20:38:10 +01:00
|
|
|
inline bool would_apply (hb_would_apply_context_t *c) const
|
|
|
|
{
|
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-01-18 01:46:51 +01:00
|
|
|
inline 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
|
|
|
|
2012-09-04 05:31:14 +02:00
|
|
|
inline bool serialize (hb_serialize_context_t *c,
|
2012-09-05 00:17:57 +02:00
|
|
|
Supplier<GlyphID> &glyphs,
|
|
|
|
Supplier<unsigned int> &alternate_len_list,
|
2012-09-04 05:31:14 +02:00
|
|
|
unsigned int num_glyphs,
|
2012-09-05 00:17:57 +02:00
|
|
|
Supplier<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);
|
|
|
|
if (unlikely (!alternateSet.serialize (c, num_glyphs))) return_trace (false);
|
2012-09-05 00:17:57 +02:00
|
|
|
for (unsigned int i = 0; i < num_glyphs; i++)
|
|
|
|
if (unlikely (!alternateSet[i].serialize (c, this).serialize (c,
|
|
|
|
alternate_glyphs_list,
|
2015-09-29 15:57:02 +02:00
|
|
|
alternate_len_list[i]))) return_trace (false);
|
2018-02-10 20:15:57 +01:00
|
|
|
alternate_len_list += num_glyphs;
|
2015-09-29 15:57:02 +02:00
|
|
|
if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
|
|
|
|
return_trace (true);
|
2012-09-04 05:31:14 +02:00
|
|
|
}
|
|
|
|
|
2018-09-04 02:33:34 +02:00
|
|
|
inline bool subset (hb_subset_context_t *c) const
|
|
|
|
{
|
|
|
|
TRACE_SUBSET (this);
|
|
|
|
// TODO(subset)
|
|
|
|
return_trace (false);
|
|
|
|
}
|
|
|
|
|
2015-02-17 15:27:44 +01:00
|
|
|
inline bool sanitize (hb_sanitize_context_t *c) const
|
|
|
|
{
|
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
|
|
|
|
{
|
2012-09-04 05:31:14 +02:00
|
|
|
inline bool serialize (hb_serialize_context_t *c,
|
2012-09-05 00:17:57 +02:00
|
|
|
Supplier<GlyphID> &glyphs,
|
|
|
|
Supplier<unsigned int> &alternate_len_list,
|
2012-09-04 05:31:14 +02:00
|
|
|
unsigned int num_glyphs,
|
2012-09-05 00:17:57 +02:00
|
|
|
Supplier<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) {
|
2015-09-29 15:57:02 +02:00
|
|
|
case 1: return_trace (u.format1.serialize (c, glyphs, alternate_len_list, num_glyphs, alternate_glyphs_list));
|
|
|
|
default:return_trace (false);
|
2012-09-04 05:31:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-09 07:59:30 +01:00
|
|
|
template <typename context_t>
|
|
|
|
inline typename context_t::return_t dispatch (context_t *c) const
|
|
|
|
{
|
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-09-03 04:47:50 +02:00
|
|
|
inline bool intersects (const hb_set_t *glyphs) const
|
|
|
|
{
|
|
|
|
unsigned int count = component.len;
|
|
|
|
for (unsigned int i = 1; i < count; i++)
|
|
|
|
if (!glyphs->has (component[i]))
|
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-04-24 05:03:12 +02:00
|
|
|
inline 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 = component.len;
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2012-11-17 04:07:06 +01:00
|
|
|
inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
|
|
|
|
{
|
2012-11-24 00:13:48 +01:00
|
|
|
TRACE_COLLECT_GLYPHS (this);
|
2018-05-09 01:56:11 +02:00
|
|
|
c->input->add_array (component.arrayZ, component.len ? component.len - 1 : 0);
|
2012-12-04 23:08:41 +01:00
|
|
|
c->output->add (ligGlyph);
|
2012-11-17 04:07:06 +01:00
|
|
|
}
|
|
|
|
|
2012-07-19 20:35:23 +02:00
|
|
|
inline 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-08-08 04:25:24 +02:00
|
|
|
if (c->len != component.len)
|
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-01-18 01:46:51 +01:00
|
|
|
inline 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-18 08:03:58 +02:00
|
|
|
unsigned int count = component.len;
|
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
|
|
|
bool is_mark_ligature = false;
|
|
|
|
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
|
|
|
&is_mark_ligature,
|
|
|
|
&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
|
|
|
is_mark_ligature,
|
|
|
|
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
|
|
|
|
2012-09-05 00:17:57 +02:00
|
|
|
inline bool serialize (hb_serialize_context_t *c,
|
|
|
|
GlyphID ligature,
|
|
|
|
Supplier<GlyphID> &components, /* Starting from second */
|
|
|
|
unsigned int num_components /* Including first component */)
|
|
|
|
{
|
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;
|
2015-09-29 15:57:02 +02:00
|
|
|
if (unlikely (!component.serialize (c, components, num_components))) return_trace (false);
|
|
|
|
return_trace (true);
|
2012-09-05 00:17:57 +02:00
|
|
|
}
|
|
|
|
|
2009-08-04 06:58:28 +02:00
|
|
|
public:
|
2015-02-17 15:27:44 +01:00
|
|
|
inline bool sanitize (hb_sanitize_context_t *c) const
|
|
|
|
{
|
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-09-03 04:47:50 +02:00
|
|
|
inline bool intersects (const hb_set_t *glyphs) const
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-04-24 05:03:12 +02:00
|
|
|
inline 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
|
|
|
}
|
|
|
|
|
2012-11-17 04:07:06 +01:00
|
|
|
inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
|
|
|
|
{
|
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);
|
|
|
|
}
|
|
|
|
|
2012-07-19 20:35:23 +02:00
|
|
|
inline 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-01-18 01:46:51 +01:00
|
|
|
inline 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
|
|
|
|
2012-09-05 00:17:57 +02:00
|
|
|
inline bool serialize (hb_serialize_context_t *c,
|
|
|
|
Supplier<GlyphID> &ligatures,
|
|
|
|
Supplier<unsigned int> &component_count_list,
|
|
|
|
unsigned int num_ligatures,
|
|
|
|
Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
|
|
|
|
{
|
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);
|
|
|
|
if (unlikely (!ligature.serialize (c, num_ligatures))) return_trace (false);
|
2012-09-05 00:17:57 +02:00
|
|
|
for (unsigned int i = 0; i < num_ligatures; i++)
|
|
|
|
if (unlikely (!ligature[i].serialize (c, this).serialize (c,
|
|
|
|
ligatures[i],
|
|
|
|
component_list,
|
2015-09-29 15:57:02 +02:00
|
|
|
component_count_list[i]))) return_trace (false);
|
2018-02-10 20:15:57 +01:00
|
|
|
ligatures += num_ligatures;
|
|
|
|
component_count_list += num_ligatures;
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (true);
|
2012-09-05 00:17:57 +02:00
|
|
|
}
|
|
|
|
|
2015-02-17 15:27:44 +01:00
|
|
|
inline bool sanitize (hb_sanitize_context_t *c) const
|
|
|
|
{
|
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-09-03 04:47:50 +02:00
|
|
|
inline bool intersects (const hb_set_t *glyphs) const
|
|
|
|
{
|
|
|
|
unsigned int count = ligatureSet.len;
|
|
|
|
for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-04-24 05:03:12 +02:00
|
|
|
inline 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-08-26 06:15:39 +02:00
|
|
|
for (hb_auto_t<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
|
|
|
}
|
|
|
|
|
2012-11-17 04:07:06 +01:00
|
|
|
inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
|
|
|
|
{
|
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-08-26 06:15:39 +02:00
|
|
|
for (hb_auto_t<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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-28 23:31:01 +02:00
|
|
|
inline const Coverage &get_coverage (void) const
|
2018-09-03 04:47:50 +02:00
|
|
|
{ return this+coverage; }
|
2012-07-28 23:31:01 +02:00
|
|
|
|
2012-07-19 20:35:23 +02:00
|
|
|
inline 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-01-18 01:46:51 +01:00
|
|
|
inline 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
|
|
|
|
2012-09-05 00:17:57 +02:00
|
|
|
inline bool serialize (hb_serialize_context_t *c,
|
|
|
|
Supplier<GlyphID> &first_glyphs,
|
|
|
|
Supplier<unsigned int> &ligature_per_first_glyph_count_list,
|
|
|
|
unsigned int num_first_glyphs,
|
|
|
|
Supplier<GlyphID> &ligatures_list,
|
|
|
|
Supplier<unsigned int> &component_count_list,
|
|
|
|
Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
|
|
|
|
{
|
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);
|
|
|
|
if (unlikely (!ligatureSet.serialize (c, num_first_glyphs))) return_trace (false);
|
2012-09-05 00:17:57 +02:00
|
|
|
for (unsigned int i = 0; i < num_first_glyphs; i++)
|
|
|
|
if (unlikely (!ligatureSet[i].serialize (c, this).serialize (c,
|
|
|
|
ligatures_list,
|
|
|
|
component_count_list,
|
|
|
|
ligature_per_first_glyph_count_list[i],
|
2015-09-29 15:57:02 +02:00
|
|
|
component_list))) return_trace (false);
|
2018-02-10 20:15:57 +01:00
|
|
|
ligature_per_first_glyph_count_list += num_first_glyphs;
|
2015-09-29 15:57:02 +02:00
|
|
|
if (unlikely (!coverage.serialize (c, this).serialize (c, first_glyphs, num_first_glyphs))) return_trace (false);
|
|
|
|
return_trace (true);
|
2012-09-05 00:17:57 +02:00
|
|
|
}
|
|
|
|
|
2018-09-04 02:33:34 +02:00
|
|
|
inline bool subset (hb_subset_context_t *c) const
|
|
|
|
{
|
|
|
|
TRACE_SUBSET (this);
|
|
|
|
// TODO(subset)
|
|
|
|
return_trace (false);
|
|
|
|
}
|
|
|
|
|
2015-02-17 15:27:44 +01:00
|
|
|
inline bool sanitize (hb_sanitize_context_t *c) const
|
|
|
|
{
|
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
|
|
|
|
{
|
2012-09-05 00:17:57 +02:00
|
|
|
inline bool serialize (hb_serialize_context_t *c,
|
|
|
|
Supplier<GlyphID> &first_glyphs,
|
|
|
|
Supplier<unsigned int> &ligature_per_first_glyph_count_list,
|
|
|
|
unsigned int num_first_glyphs,
|
|
|
|
Supplier<GlyphID> &ligatures_list,
|
|
|
|
Supplier<unsigned int> &component_count_list,
|
|
|
|
Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
|
|
|
|
{
|
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,
|
|
|
|
num_first_glyphs,
|
|
|
|
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>
|
|
|
|
inline typename context_t::return_t dispatch (context_t *c) const
|
|
|
|
{
|
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
|
|
|
|
2010-04-23 02:15:11 +02:00
|
|
|
inline bool is_reverse (void) const;
|
2009-04-16 19:40:13 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2009-05-20 05:42:30 +02:00
|
|
|
struct ReverseChainSingleSubstFormat1
|
|
|
|
{
|
2018-09-03 04:47:50 +02:00
|
|
|
inline bool intersects (const hb_set_t *glyphs) const
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-04-24 05:03:12 +02:00
|
|
|
inline 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-08-26 06:15:39 +02:00
|
|
|
for (hb_auto_t<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
|
|
|
}
|
|
|
|
|
2012-11-17 04:07:06 +01:00
|
|
|
inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
|
|
|
|
{
|
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
|
|
|
}
|
|
|
|
|
2012-07-28 23:31:01 +02:00
|
|
|
inline const Coverage &get_coverage (void) const
|
2018-09-03 04:47:50 +02:00
|
|
|
{ return this+coverage; }
|
2012-07-28 23:31:01 +02:00
|
|
|
|
2012-11-22 20:38:10 +01:00
|
|
|
inline bool would_apply (hb_would_apply_context_t *c) const
|
|
|
|
{
|
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-01-18 01:46:51 +01:00
|
|
|
inline 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-09-04 02:33:34 +02:00
|
|
|
inline bool subset (hb_subset_context_t *c) const
|
|
|
|
{
|
|
|
|
TRACE_SUBSET (this);
|
|
|
|
// TODO(subset)
|
|
|
|
return_trace (false);
|
|
|
|
}
|
|
|
|
|
2015-02-17 15:27:44 +01:00
|
|
|
inline bool sanitize (hb_sanitize_context_t *c) const
|
|
|
|
{
|
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>
|
2013-03-09 07:55:04 +01:00
|
|
|
inline 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>
|
2013-03-09 07:55:04 +01:00
|
|
|
inline 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);
|
2015-10-09 18:25:55 +02:00
|
|
|
if (unlikely (!c->may_dispatch (this, &u.sub_format))) return_trace (c->no_dispatch_return_value ());
|
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 {
|
2018-01-10 03:07:30 +01:00
|
|
|
HBUINT16 sub_format;
|
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:
|
2015-02-17 14:05:30 +01:00
|
|
|
DEFINE_SIZE_UNION (2, sub_format);
|
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;
|
|
|
|
|
|
|
|
inline const SubTable& get_subtable (unsigned int i) const
|
|
|
|
{ return Lookup::get_subtable<SubTable> (i); }
|
2009-04-16 01:50:16 +02:00
|
|
|
|
2010-04-23 02:15:11 +02:00
|
|
|
inline 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
|
|
|
|
|
|
|
inline bool is_reverse (void) 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-01-18 01:46:51 +01:00
|
|
|
inline 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-09-03 04:47:50 +02:00
|
|
|
inline bool intersects (const hb_set_t *glyphs) const
|
|
|
|
{
|
|
|
|
hb_intersects_context_t c (glyphs);
|
|
|
|
return dispatch (&c);
|
|
|
|
}
|
|
|
|
|
2018-06-06 02:14:42 +02:00
|
|
|
inline 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
|
|
|
}
|
|
|
|
|
2013-05-03 23:33:16 +02:00
|
|
|
inline 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>
|
|
|
|
inline void add_coverage (set_t *glyphs) const
|
|
|
|
{
|
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
|
|
|
}
|
|
|
|
|
2015-01-29 05:55:42 +01:00
|
|
|
inline 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-09-04 01:53:03 +02:00
|
|
|
inline SubTable& serialize_subtable (hb_serialize_context_t *c,
|
|
|
|
unsigned int i)
|
|
|
|
{ return get_subtables<SubTable> ()[i].serialize (c, this); }
|
2012-09-05 03:13:17 +02:00
|
|
|
|
|
|
|
inline bool serialize_single (hb_serialize_context_t *c,
|
|
|
|
uint32_t lookup_props,
|
|
|
|
Supplier<GlyphID> &glyphs,
|
|
|
|
Supplier<GlyphID> &substitutes,
|
|
|
|
unsigned int num_glyphs)
|
|
|
|
{
|
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);
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes, num_glyphs));
|
2012-09-05 03:13:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
inline bool serialize_multiple (hb_serialize_context_t *c,
|
|
|
|
uint32_t lookup_props,
|
|
|
|
Supplier<GlyphID> &glyphs,
|
|
|
|
Supplier<unsigned int> &substitute_len_list,
|
|
|
|
unsigned int num_glyphs,
|
|
|
|
Supplier<GlyphID> &substitute_glyphs_list)
|
|
|
|
{
|
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,
|
|
|
|
num_glyphs,
|
|
|
|
substitute_glyphs_list));
|
2012-09-05 03:13:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
inline bool serialize_alternate (hb_serialize_context_t *c,
|
|
|
|
uint32_t lookup_props,
|
|
|
|
Supplier<GlyphID> &glyphs,
|
|
|
|
Supplier<unsigned int> &alternate_len_list,
|
|
|
|
unsigned int num_glyphs,
|
|
|
|
Supplier<GlyphID> &alternate_glyphs_list)
|
|
|
|
{
|
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,
|
|
|
|
num_glyphs,
|
|
|
|
alternate_glyphs_list));
|
2012-09-05 03:13:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
inline bool serialize_ligature (hb_serialize_context_t *c,
|
|
|
|
uint32_t lookup_props,
|
|
|
|
Supplier<GlyphID> &first_glyphs,
|
|
|
|
Supplier<unsigned int> &ligature_per_first_glyph_count_list,
|
|
|
|
unsigned int num_first_glyphs,
|
|
|
|
Supplier<GlyphID> &ligatures_list,
|
|
|
|
Supplier<unsigned int> &component_count_list,
|
|
|
|
Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
|
|
|
|
{
|
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,
|
|
|
|
num_first_glyphs,
|
|
|
|
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>
|
|
|
|
static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
|
|
|
|
|
2018-06-12 05:23:40 +02:00
|
|
|
static inline 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);
|
|
|
|
|
|
|
|
c->flush ();
|
|
|
|
|
|
|
|
return ret;
|
2018-06-06 02:14:42 +02:00
|
|
|
}
|
|
|
|
|
2013-03-09 07:59:30 +01:00
|
|
|
template <typename context_t>
|
|
|
|
inline typename context_t::return_t dispatch (context_t *c) const
|
2018-09-04 01:53:03 +02:00
|
|
|
{ return Lookup::dispatch<SubTable> (c); }
|
|
|
|
|
|
|
|
inline 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
|
|
|
|
2015-02-17 15:27:44 +01:00
|
|
|
inline 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
|
|
|
|
{
|
2013-09-09 21:43:10 +02:00
|
|
|
static const hb_tag_t tableTag = HB_OT_TAG_GSUB;
|
2008-01-24 00:02:28 +01:00
|
|
|
|
2009-05-20 05:42:30 +02:00
|
|
|
inline 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-09-02 03:34:50 +02:00
|
|
|
inline 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
|
|
|
|
2015-02-17 15:27:44 +01:00
|
|
|
inline 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
|
|
|
|
|
|
|
typedef GSUBGPOS::accelerator_t<GSUB> accelerator_t;
|
2008-01-24 00:02:28 +01:00
|
|
|
};
|
2009-05-16 00:54:53 +02:00
|
|
|
|
|
|
|
|
2009-05-18 03:06:08 +02:00
|
|
|
/* Out-of-class implementation for methods recursing */
|
2009-05-16 00:54:53 +02:00
|
|
|
|
2014-04-28 23:29:39 +02:00
|
|
|
/*static*/ inline bool ExtensionSubst::is_reverse (void) 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-08-26 18:12:25 +02:00
|
|
|
const SubstLookup &l = _get_gsub_relaxed (c->face).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-08-26 18:12:25 +02:00
|
|
|
const SubstLookup &l = _get_gsub_relaxed (c->face).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
|
|
|
}
|
|
|
|
|
2018-08-27 00:11:24 +02:00
|
|
|
struct GSUB_accelerator_t : GSUB::accelerator_t {};
|
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 */
|