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
|
|
|
|
2009-08-03 02:03:12 +02:00
|
|
|
#include "hb-ot-layout-gsubgpos-private.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
|
|
|
|
2009-05-20 05:42:30 +02:00
|
|
|
struct SingleSubstFormat1
|
|
|
|
{
|
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
|
|
|
Coverage::Iter iter;
|
2016-12-20 22:01:16 +01:00
|
|
|
for (iter.init (this+coverage); iter.more (); iter.next ())
|
|
|
|
{
|
|
|
|
/* 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))
|
2014-07-11 20:54:42 +02:00
|
|
|
c->glyphs->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;
|
2012-11-17 04:07:06 +01:00
|
|
|
Coverage::Iter iter;
|
2016-12-20 22:01:16 +01:00
|
|
|
for (iter.init (this+coverage); iter.more (); iter.next ())
|
|
|
|
{
|
|
|
|
/* 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
|
|
|
|
{
|
|
|
|
return this+coverage;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
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-01-10 03:07:30 +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
|
|
|
|
{
|
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
|
|
|
Coverage::Iter iter;
|
2016-12-20 22:01:16 +01:00
|
|
|
unsigned int count = substitute.len;
|
|
|
|
for (iter.init (this+coverage); iter.more (); iter.next ())
|
|
|
|
{
|
|
|
|
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
|
|
|
c->glyphs->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
|
|
|
Coverage::Iter iter;
|
2016-12-20 22:01:16 +01:00
|
|
|
unsigned int count = substitute.len;
|
|
|
|
for (iter.init (this+coverage); iter.more (); iter.next ())
|
|
|
|
{
|
|
|
|
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
|
|
|
|
{
|
|
|
|
return this+coverage;
|
|
|
|
}
|
|
|
|
|
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 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
|
|
|
|
|
|
|
glyph_id = substitute[index];
|
2010-10-27 23:39:01 +02:00
|
|
|
c->replace_glyph (glyph_id);
|
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
|
|
|
}
|
|
|
|
|
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
|
|
|
|
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++)
|
2012-04-24 05:03:12 +02:00
|
|
|
c->glyphs->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);
|
2017-12-16 15:12:06 +01:00
|
|
|
c->output->add_array (substitute.array, 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
|
|
|
{
|
|
|
|
c->replace_glyph (substitute.array[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);
|
[indic] Don't reorder reph/pref if ligature was expanded
Normally if you want to, say, conditionally prevent a 'pref', you
would use blocking contextual matching. Some designers instead
form the 'pref' form, then undo it in context. To detect that
we now also remember glyphs that went through MultipleSubst.
In the only place that this is used, Uniscribe seems to only care
about the "last" transformation between Ligature and Multiple
substitions. Ie. if you ligate, expand, and ligate again, it
moves the pref, but if you ligate and expand it doesn't. That's
why we clear the MULTIPLIED bit when setting LIGATED.
Micro-test added. Test: U+0D2F,0D4D,0D30 with font from:
[1]
https://code.google.com/a/google.com/p/noto-alpha/issues/detail?id=186#c29
2014-06-04 22:57:42 +02:00
|
|
|
c->output_glyph_for_component (substitute.array[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
|
|
|
|
{
|
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
|
|
|
Coverage::Iter iter;
|
2016-12-20 22:01:16 +01:00
|
|
|
unsigned int count = sequence.len;
|
|
|
|
for (iter.init (this+coverage); iter.more (); iter.next ())
|
|
|
|
{
|
|
|
|
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++)
|
|
|
|
(this+sequence[i]).collect_glyphs (c);
|
|
|
|
}
|
|
|
|
|
2012-07-28 23:31:01 +02:00
|
|
|
inline const Coverage &get_coverage (void) const
|
|
|
|
{
|
|
|
|
return this+coverage;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
};
|
|
|
|
|
2008-01-23 23:01:55 +01:00
|
|
|
|
2009-05-17 07:22:51 +02:00
|
|
|
typedef ArrayOf<GlyphID> AlternateSet; /* Array of alternate GlyphIDs--in
|
2008-01-23 23:01:55 +01:00
|
|
|
* arbitrary order */
|
|
|
|
|
2009-05-20 05:42:30 +02:00
|
|
|
struct AlternateSubstFormat1
|
|
|
|
{
|
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
|
|
|
Coverage::Iter iter;
|
2016-12-20 22:01:16 +01:00
|
|
|
unsigned int count = alternateSet.len;
|
|
|
|
for (iter.init (this+coverage); iter.more (); iter.next ())
|
|
|
|
{
|
|
|
|
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 ())) {
|
|
|
|
const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
|
|
|
|
unsigned int count = alt_set.len;
|
|
|
|
for (unsigned int i = 0; i < count; i++)
|
2012-04-24 05:03:12 +02:00
|
|
|
c->glyphs->add (alt_set[i]);
|
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
|
|
|
Coverage::Iter iter;
|
2016-12-20 22:01:16 +01:00
|
|
|
unsigned int count = alternateSet.len;
|
|
|
|
for (iter.init (this+coverage); iter.more (); iter.next ())
|
|
|
|
{
|
|
|
|
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
|
|
|
const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
|
2017-12-16 15:12:06 +01:00
|
|
|
c->output->add_array (alt_set.array, alt_set.len);
|
2012-11-17 04:07:06 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-28 23:31:01 +02:00
|
|
|
inline const Coverage &get_coverage (void) const
|
|
|
|
{
|
|
|
|
return this+coverage;
|
|
|
|
}
|
|
|
|
|
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;
|
2009-04-16 20:19:42 +02:00
|
|
|
|
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-05-18 05:17:56 +02:00
|
|
|
|
2009-05-17 07:22:51 +02:00
|
|
|
const AlternateSet &alt_set = this+alternateSet[index];
|
2009-04-16 20:19:42 +02:00
|
|
|
|
2015-09-29 15:57:02 +02:00
|
|
|
if (unlikely (!alt_set.len)) return_trace (false);
|
2009-04-16 20:19:42 +02:00
|
|
|
|
2012-05-13 15:45:18 +02:00
|
|
|
hb_mask_t glyph_mask = c->buffer->cur().mask;
|
2012-04-20 04:21:38 +02:00
|
|
|
hb_mask_t lookup_mask = c->lookup_mask;
|
|
|
|
|
2010-05-21 17:43:17 +02:00
|
|
|
/* Note: This breaks badly if two features enabled this lookup together. */
|
2010-05-20 18:26:35 +02:00
|
|
|
unsigned int shift = _hb_ctz (lookup_mask);
|
2010-05-20 18:47:28 +02:00
|
|
|
unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift);
|
2009-04-16 20:19:42 +02:00
|
|
|
|
2015-09-29 15:57:02 +02:00
|
|
|
if (unlikely (alt_index > alt_set.len || alt_index == 0)) return_trace (false);
|
2009-04-16 20:19:42 +02:00
|
|
|
|
2010-05-20 18:47:28 +02:00
|
|
|
glyph_id = alt_set[alt_index - 1];
|
2009-04-16 20:19:42 +02:00
|
|
|
|
2010-10-27 23:39:01 +02:00
|
|
|
c->replace_glyph (glyph_id);
|
2009-04-16 20:19:42 +02:00
|
|
|
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (true);
|
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
|
|
|
}
|
|
|
|
|
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
|
|
|
|
{
|
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;
|
|
|
|
c->glyphs->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);
|
2017-12-16 15:12:06 +01:00
|
|
|
c->input->add_array (component.array, 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
|
|
|
|
{
|
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
|
|
|
|
{
|
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
|
|
|
Coverage::Iter iter;
|
2016-12-20 22:01:16 +01:00
|
|
|
unsigned int count = ligatureSet.len;
|
|
|
|
for (iter.init (this+coverage); iter.more (); iter.next ())
|
|
|
|
{
|
|
|
|
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;
|
2012-11-17 04:07:06 +01:00
|
|
|
Coverage::Iter iter;
|
2016-12-20 22:01:16 +01:00
|
|
|
unsigned int count = ligatureSet.len;
|
|
|
|
for (iter.init (this+coverage); iter.more (); iter.next ())
|
|
|
|
{
|
|
|
|
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
|
|
|
|
{
|
|
|
|
return this+coverage;
|
|
|
|
}
|
|
|
|
|
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);
|
2012-05-13 15:45:18 +02:00
|
|
|
hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
|
2009-04-16 22:53:40 +02:00
|
|
|
|
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-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
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
2012-11-23 23:04:55 +01:00
|
|
|
typedef struct SubstLookupSubTable LookupSubTable;
|
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
|
|
|
|
{
|
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);
|
|
|
|
Coverage::Iter iter;
|
2016-12-20 22:01:16 +01:00
|
|
|
count = substitute.len;
|
|
|
|
for (iter.init (this+coverage); iter.more (); iter.next ())
|
|
|
|
{
|
|
|
|
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
|
|
|
c->glyphs->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;
|
2017-12-16 15:12:06 +01:00
|
|
|
c->output->add_array (substitute.array, 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
|
|
|
|
{
|
|
|
|
return this+coverage;
|
|
|
|
}
|
|
|
|
|
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-01-10 03:07:30 +01:00
|
|
|
backtrack.len, (HBUINT16 *) backtrack.array,
|
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-01-10 03:07:30 +01:00
|
|
|
lookahead.len, (HBUINT16 *) lookahead.array,
|
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
|
|
|
|
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
|
2008-01-23 23:01:55 +01:00
|
|
|
* in backtracking sequence, in glyph
|
|
|
|
* 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
|
|
|
|
{
|
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
|
|
|
|
{
|
2012-07-12 00:01:27 +02:00
|
|
|
inline const SubstLookupSubTable& get_subtable (unsigned int i) const
|
2015-02-18 11:09:54 +01:00
|
|
|
{ return Lookup::get_subtable<SubstLookupSubTable> (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)
|
2012-07-12 00:01:27 +02:00
|
|
|
{ return lookup_type == SubstLookupSubTable::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 ();
|
2012-07-12 00:01:27 +02:00
|
|
|
if (unlikely (type == SubstLookupSubTable::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
|
|
|
}
|
|
|
|
|
2012-11-23 23:55:40 +01:00
|
|
|
inline hb_closure_context_t::return_t closure (hb_closure_context_t *c) const
|
|
|
|
{
|
2012-11-24 00:13:48 +01:00
|
|
|
TRACE_CLOSURE (this);
|
2013-03-09 07:55:04 +01:00
|
|
|
c->set_recurse_func (dispatch_recurse_func<hb_closure_context_t>);
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (dispatch (c));
|
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
|
|
|
|
2012-09-05 03:13:17 +02:00
|
|
|
inline SubstLookupSubTable& serialize_subtable (hb_serialize_context_t *c,
|
|
|
|
unsigned int i)
|
2015-02-18 11:09:54 +01:00
|
|
|
{ return get_subtables<SubstLookupSubTable> ()[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);
|
2015-09-29 15:57:02 +02:00
|
|
|
if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Single, lookup_props, 1))) return_trace (false);
|
|
|
|
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);
|
2015-09-29 15:57:02 +02:00
|
|
|
if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Multiple, lookup_props, 1))) return_trace (false);
|
|
|
|
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);
|
2015-09-29 15:57:02 +02:00
|
|
|
if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Alternate, lookup_props, 1))) return_trace (false);
|
|
|
|
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);
|
2015-09-29 15:57:02 +02:00
|
|
|
if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Ligature, lookup_props, 1))) return_trace (false);
|
|
|
|
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);
|
|
|
|
|
|
|
|
template <typename context_t>
|
|
|
|
inline typename context_t::return_t dispatch (context_t *c) const
|
2015-02-18 11:18:46 +01:00
|
|
|
{ return Lookup::dispatch<SubstLookupSubTable> (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
|
2012-09-05 03:13:17 +02:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_SANITIZE (this);
|
2015-09-29 15:57:02 +02:00
|
|
|
if (unlikely (!Lookup::sanitize (c))) return_trace (false);
|
|
|
|
if (unlikely (!dispatch (c))) return_trace (false);
|
2012-07-29 00:53:01 +02:00
|
|
|
|
|
|
|
if (unlikely (get_type () == SubstLookupSubTable::Extension))
|
|
|
|
{
|
|
|
|
/* The spec says all subtables of an Extension lookup should
|
2017-11-30 01:08:11 +01:00
|
|
|
* have the same type, which shall not be the Extension type
|
2018-01-16 02:44:10 +01:00
|
|
|
* itself (but we already checked for that).
|
|
|
|
* This is specially important if one has a reverse type! */
|
2012-07-29 00:53:01 +02:00
|
|
|
unsigned int type = get_subtable (0).u.extension.get_type ();
|
|
|
|
unsigned int count = get_subtable_count ();
|
|
|
|
for (unsigned int i = 1; i < count; i++)
|
|
|
|
if (get_subtable (i).u.extension.get_type () != type)
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (false);
|
2012-07-29 00:53:01 +02:00
|
|
|
}
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (true);
|
2009-08-04 08:27:37 +02:00
|
|
|
}
|
2009-04-16 01:50:16 +02:00
|
|
|
};
|
|
|
|
|
2009-08-04 08:27:37 +02:00
|
|
|
typedef OffsetListOf<SubstLookup> SubstLookupList;
|
2009-05-16 00:54:53 +02:00
|
|
|
|
2008-01-24 00:02:28 +01:00
|
|
|
/*
|
2011-08-17 14:43:45 +02:00
|
|
|
* GSUB -- The Glyph Substitution Table
|
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
|
|
|
|
2012-08-02 14:36:40 +02:00
|
|
|
static inline void substitute_start (hb_font_t *font, hb_buffer_t *buffer);
|
2011-07-28 21:42:18 +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
|
|
|
if (unlikely (!GSUBGPOS::sanitize (c))) return_trace (false);
|
2015-02-17 15:27:44 +01:00
|
|
|
const OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
|
2015-09-29 15:57:02 +02:00
|
|
|
return_trace (list.sanitize (c, this));
|
2009-08-04 08:27:37 +02:00
|
|
|
}
|
2008-01-24 00:02:28 +01:00
|
|
|
};
|
2009-05-16 00:54:53 +02:00
|
|
|
|
|
|
|
|
2011-07-28 21:42:18 +02:00
|
|
|
void
|
2012-08-02 14:36:40 +02:00
|
|
|
GSUB::substitute_start (hb_font_t *font, hb_buffer_t *buffer)
|
2011-07-28 21:42:18 +02:00
|
|
|
{
|
2014-08-02 23:18:46 +02:00
|
|
|
_hb_buffer_assert_gsubgpos_vars (buffer);
|
2011-07-28 22:48:43 +02:00
|
|
|
|
2012-08-02 14:36:40 +02:00
|
|
|
const GDEF &gdef = *hb_ot_layout_from_face (font->face)->gdef;
|
2011-07-28 21:42:18 +02:00
|
|
|
unsigned int count = buffer->len;
|
2013-10-18 00:42:39 +02:00
|
|
|
for (unsigned int i = 0; i < count; i++)
|
|
|
|
{
|
2016-12-22 20:33:54 +01:00
|
|
|
_hb_glyph_info_set_glyph_props (&buffer->info[i], gdef.get_glyph_props (buffer->info[i].codepoint));
|
|
|
|
_hb_glyph_info_clear_lig_props (&buffer->info[i]);
|
2013-10-18 00:42:39 +02:00
|
|
|
buffer->info[i].syllable() = 0;
|
2012-07-31 01:30:01 +02:00
|
|
|
}
|
2011-07-28 21:42:18 +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 ();
|
2012-07-12 00:01:27 +02:00
|
|
|
if (unlikely (type == SubstLookupSubTable::Extension))
|
2015-02-19 08:29:41 +01:00
|
|
|
return CastR<ExtensionSubst> (get_subtable<LookupSubTable>()).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
|
|
|
{
|
|
|
|
const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
|
|
|
|
const SubstLookup &l = gsub.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
|
|
|
{
|
2012-07-27 08:12:28 +02:00
|
|
|
const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
|
2009-05-17 13:52:11 +02:00
|
|
|
const SubstLookup &l = gsub.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 */
|