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;
|
|
|
|
for (iter.init (this+coverage); iter.more (); iter.next ()) {
|
|
|
|
hb_codepoint_t glyph_id = iter.get_glyph ();
|
|
|
|
if (c->glyphs->has (glyph_id))
|
2012-04-24 05:03:12 +02:00
|
|
|
c->glyphs->add ((glyph_id + deltaGlyphID) & 0xFFFF);
|
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);
|
2012-11-17 04:07:06 +01:00
|
|
|
Coverage::Iter iter;
|
|
|
|
for (iter.init (this+coverage); iter.more (); iter.next ()) {
|
|
|
|
hb_codepoint_t glyph_id = iter.get_glyph ();
|
2012-12-04 23:08:41 +01:00
|
|
|
c->input->add (glyph_id);
|
|
|
|
c->output->add ((glyph_id + deltaGlyphID) & 0xFFFF);
|
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);
|
2012-11-25 01:13:55 +01:00
|
|
|
return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
|
2012-11-22 20:38:10 +01:00
|
|
|
}
|
|
|
|
|
2010-05-13 20:18:49 +02:00
|
|
|
inline bool apply (hb_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);
|
2012-05-11 02:33:11 +02:00
|
|
|
if (likely (index == NOT_COVERED)) return TRACE_RETURN (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. */
|
|
|
|
glyph_id = (glyph_id + deltaGlyphID) & 0xFFFF;
|
2010-10-27 23:39:01 +02:00
|
|
|
c->replace_glyph (glyph_id);
|
2009-04-16 04:56:15 +02:00
|
|
|
|
2012-05-11 02:33:11 +02:00
|
|
|
return TRACE_RETURN (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);
|
2012-09-02 02:48:22 +02:00
|
|
|
if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
|
2012-09-02 03:30:17 +02:00
|
|
|
if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
|
2012-09-04 02:58:03 +02:00
|
|
|
deltaGlyphID.set (delta); /* TODO(serilaize) overflow? */
|
2012-09-02 02:48:22 +02:00
|
|
|
return TRACE_RETURN (true);
|
|
|
|
}
|
|
|
|
|
2010-05-13 20:18:49 +02:00
|
|
|
inline bool sanitize (hb_sanitize_context_t *c) {
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_SANITIZE (this);
|
2012-05-11 01:25:34 +02:00
|
|
|
return TRACE_RETURN (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
|
2009-08-04 06:58:28 +02:00
|
|
|
}
|
|
|
|
|
2012-07-24 21:40:37 +02:00
|
|
|
protected:
|
2009-05-18 02:13:02 +02:00
|
|
|
USHORT 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 */
|
|
|
|
SHORT deltaGlyphID; /* Add to original GlyphID to get
|
|
|
|
* 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;
|
|
|
|
for (iter.init (this+coverage); iter.more (); iter.next ()) {
|
|
|
|
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);
|
2012-11-17 04:07:06 +01:00
|
|
|
Coverage::Iter iter;
|
|
|
|
for (iter.init (this+coverage); iter.more (); iter.next ()) {
|
2012-12-04 23:08:41 +01:00
|
|
|
c->input->add (iter.get_glyph ());
|
|
|
|
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);
|
2012-11-25 01:13:55 +01:00
|
|
|
return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
|
2012-11-22 20:38:10 +01:00
|
|
|
}
|
|
|
|
|
2010-05-13 20:18:49 +02:00
|
|
|
inline bool apply (hb_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);
|
2012-05-11 02:33:11 +02:00
|
|
|
if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
|
2009-04-16 10:45:30 +02:00
|
|
|
|
2012-05-11 02:33:11 +02:00
|
|
|
if (unlikely (index >= substitute.len)) return TRACE_RETURN (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
|
|
|
|
2012-05-11 02:33:11 +02:00
|
|
|
return TRACE_RETURN (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);
|
2012-09-02 03:43:38 +02:00
|
|
|
if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
|
|
|
|
if (unlikely (!substitute.serialize (c, substitutes, num_glyphs))) return TRACE_RETURN (false);
|
2012-09-06 04:19:28 +02:00
|
|
|
if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
|
2012-09-02 03:43:38 +02:00
|
|
|
return TRACE_RETURN (true);
|
|
|
|
}
|
|
|
|
|
2010-05-13 20:18:49 +02:00
|
|
|
inline bool sanitize (hb_sanitize_context_t *c) {
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_SANITIZE (this);
|
2012-05-11 01:25:34 +02:00
|
|
|
return TRACE_RETURN (coverage.sanitize (c, this) && substitute.sanitize (c));
|
2009-08-04 06:58:28 +02:00
|
|
|
}
|
|
|
|
|
2012-07-24 21:40:37 +02:00
|
|
|
protected:
|
2009-05-18 02:13:02 +02:00
|
|
|
USHORT 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);
|
2012-09-02 03:43:38 +02:00
|
|
|
if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
|
|
|
|
unsigned int format = 2;
|
2012-09-05 00:17:21 +02:00
|
|
|
int delta;
|
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) {
|
|
|
|
case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, num_glyphs, delta));
|
|
|
|
case 2: return TRACE_RETURN (u.format2.serialize (c, glyphs, substitutes, num_glyphs));
|
|
|
|
default:return TRACE_RETURN (false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-09 07:59:30 +01:00
|
|
|
template <typename context_t>
|
|
|
|
inline typename context_t::return_t dispatch (context_t *c) const
|
|
|
|
{
|
|
|
|
TRACE_DISPATCH (this);
|
|
|
|
switch (u.format) {
|
|
|
|
case 1: return TRACE_RETURN (c->dispatch (u.format1));
|
|
|
|
case 2: return TRACE_RETURN (c->dispatch (u.format2));
|
|
|
|
default:return TRACE_RETURN (c->default_return_value ());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-05-13 20:18:49 +02:00
|
|
|
inline bool sanitize (hb_sanitize_context_t *c) {
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_SANITIZE (this);
|
2012-05-11 01:25:34 +02:00
|
|
|
if (!u.format.sanitize (c)) return TRACE_RETURN (false);
|
2009-08-04 06:58:28 +02:00
|
|
|
switch (u.format) {
|
2012-05-11 01:25:34 +02:00
|
|
|
case 1: return TRACE_RETURN (u.format1.sanitize (c));
|
|
|
|
case 2: return TRACE_RETURN (u.format2.sanitize (c));
|
|
|
|
default:return TRACE_RETURN (true);
|
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
|
|
|
union {
|
2009-05-18 01:47:54 +02:00
|
|
|
USHORT 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);
|
2012-11-17 04:07:06 +01:00
|
|
|
unsigned int count = substitute.len;
|
|
|
|
for (unsigned int i = 0; i < count; i++)
|
2012-12-04 23:08:41 +01:00
|
|
|
c->output->add (substitute[i]);
|
2012-11-17 04:07:06 +01:00
|
|
|
}
|
|
|
|
|
2010-05-13 20:18:49 +02:00
|
|
|
inline bool apply (hb_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
|
|
|
|
|
|
|
/* TODO:
|
|
|
|
* Testing shows that Uniscribe actually allows zero-len susbstitute,
|
|
|
|
* which essentially deletes a glyph. We don't allow for now. It
|
|
|
|
* can be confusing to the client since the cluster from the deleted
|
|
|
|
* glyph won't be merged with any output cluster... Also, currently
|
|
|
|
* buffer->move_to() makes assumptions about this too. Perhaps fix
|
|
|
|
* in the future after figuring out what to do with the clusters.
|
|
|
|
*/
|
2014-06-06 00:54:44 +02:00
|
|
|
if (unlikely (!count)) return TRACE_RETURN (false);
|
2009-05-05 22:22:02 +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]);
|
2014-06-06 00:54:44 +02:00
|
|
|
return TRACE_RETURN (true);
|
2013-05-02 20:44:45 +02:00
|
|
|
}
|
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);
|
|
|
|
c->output_glyph (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
|
|
|
|
2012-05-11 02:33:11 +02:00
|
|
|
return TRACE_RETURN (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);
|
2012-09-04 05:28:34 +02:00
|
|
|
if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
|
|
|
|
if (unlikely (!substitute.serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
|
|
|
|
return TRACE_RETURN (true);
|
|
|
|
}
|
|
|
|
|
2010-05-13 20:18:49 +02:00
|
|
|
inline bool sanitize (hb_sanitize_context_t *c) {
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_SANITIZE (this);
|
2012-05-11 01:25:34 +02:00
|
|
|
return TRACE_RETURN (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;
|
|
|
|
for (iter.init (this+coverage); iter.more (); iter.next ()) {
|
|
|
|
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);
|
2012-12-04 23:08:41 +01:00
|
|
|
(this+coverage).add_coverage (c->input);
|
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);
|
2012-11-25 01:13:55 +01:00
|
|
|
return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
|
2012-11-22 20:38:10 +01:00
|
|
|
}
|
|
|
|
|
2010-05-13 20:18:49 +02:00
|
|
|
inline bool apply (hb_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);
|
2012-05-11 02:33:11 +02:00
|
|
|
if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
|
2009-05-18 05:17:56 +02:00
|
|
|
|
2012-05-11 02:33:11 +02:00
|
|
|
return TRACE_RETURN ((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);
|
2012-09-04 05:28:34 +02:00
|
|
|
if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
|
|
|
|
if (unlikely (!sequence.serialize (c, num_glyphs))) return TRACE_RETURN (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,
|
|
|
|
substitute_len_list[i]))) return TRACE_RETURN (false);
|
|
|
|
substitute_len_list.advance (num_glyphs);
|
2012-09-06 04:19:28 +02:00
|
|
|
if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
|
2012-09-04 05:28:34 +02:00
|
|
|
return TRACE_RETURN (true);
|
|
|
|
}
|
|
|
|
|
2010-05-13 20:18:49 +02:00
|
|
|
inline bool sanitize (hb_sanitize_context_t *c) {
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_SANITIZE (this);
|
2012-05-11 01:25:34 +02:00
|
|
|
return TRACE_RETURN (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:
|
2009-05-18 02:13:02 +02:00
|
|
|
USHORT 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);
|
2012-09-04 05:28:34 +02:00
|
|
|
if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
|
|
|
|
unsigned int format = 1;
|
|
|
|
u.format.set (format);
|
|
|
|
switch (u.format) {
|
|
|
|
case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, substitute_len_list, num_glyphs, substitute_glyphs_list));
|
|
|
|
default:return TRACE_RETURN (false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-09 07:59:30 +01:00
|
|
|
template <typename context_t>
|
|
|
|
inline typename context_t::return_t dispatch (context_t *c) const
|
|
|
|
{
|
|
|
|
TRACE_DISPATCH (this);
|
|
|
|
switch (u.format) {
|
|
|
|
case 1: return TRACE_RETURN (c->dispatch (u.format1));
|
|
|
|
default:return TRACE_RETURN (c->default_return_value ());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-05-13 20:18:49 +02:00
|
|
|
inline bool sanitize (hb_sanitize_context_t *c) {
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_SANITIZE (this);
|
2012-05-11 01:25:34 +02:00
|
|
|
if (!u.format.sanitize (c)) return TRACE_RETURN (false);
|
2009-08-04 06:58:28 +02:00
|
|
|
switch (u.format) {
|
2012-05-11 01:25:34 +02:00
|
|
|
case 1: return TRACE_RETURN (u.format1.sanitize (c));
|
|
|
|
default:return TRACE_RETURN (true);
|
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
|
|
|
union {
|
2009-05-18 01:47:54 +02:00
|
|
|
USHORT 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;
|
|
|
|
for (iter.init (this+coverage); iter.more (); iter.next ()) {
|
|
|
|
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);
|
2012-11-17 04:07:06 +01:00
|
|
|
Coverage::Iter iter;
|
|
|
|
for (iter.init (this+coverage); iter.more (); iter.next ()) {
|
2012-12-04 23:08:41 +01:00
|
|
|
c->input->add (iter.get_glyph ());
|
2012-11-17 04:07:06 +01:00
|
|
|
const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
|
|
|
|
unsigned int count = alt_set.len;
|
|
|
|
for (unsigned int i = 0; i < count; i++)
|
2012-12-04 23:08:41 +01:00
|
|
|
c->output->add (alt_set[i]);
|
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);
|
2012-11-25 01:13:55 +01:00
|
|
|
return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
|
2012-11-22 20:38:10 +01:00
|
|
|
}
|
|
|
|
|
2010-05-13 20:18:49 +02:00
|
|
|
inline bool apply (hb_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);
|
2012-05-11 02:33:11 +02:00
|
|
|
if (likely (index == NOT_COVERED)) return TRACE_RETURN (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
|
|
|
|
2012-05-11 02:33:11 +02:00
|
|
|
if (unlikely (!alt_set.len)) return TRACE_RETURN (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
|
|
|
|
2012-05-11 02:33:11 +02:00
|
|
|
if (unlikely (alt_index > alt_set.len || alt_index == 0)) return TRACE_RETURN (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
|
|
|
|
2012-05-11 02:33:11 +02:00
|
|
|
return TRACE_RETURN (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);
|
2012-09-04 05:31:14 +02:00
|
|
|
if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
|
|
|
|
if (unlikely (!alternateSet.serialize (c, num_glyphs))) return TRACE_RETURN (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,
|
|
|
|
alternate_len_list[i]))) return TRACE_RETURN (false);
|
|
|
|
alternate_len_list.advance (num_glyphs);
|
2012-09-06 04:19:28 +02:00
|
|
|
if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
|
2012-09-04 05:31:14 +02:00
|
|
|
return TRACE_RETURN (true);
|
|
|
|
}
|
|
|
|
|
2010-05-13 20:18:49 +02:00
|
|
|
inline bool sanitize (hb_sanitize_context_t *c) {
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_SANITIZE (this);
|
2012-05-11 01:25:34 +02:00
|
|
|
return TRACE_RETURN (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:
|
2009-05-18 02:13:02 +02:00
|
|
|
USHORT 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);
|
2012-09-04 05:31:14 +02:00
|
|
|
if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
|
|
|
|
unsigned int format = 1;
|
|
|
|
u.format.set (format);
|
|
|
|
switch (u.format) {
|
|
|
|
case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, alternate_len_list, num_glyphs, alternate_glyphs_list));
|
|
|
|
default:return TRACE_RETURN (false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-09 07:59:30 +01:00
|
|
|
template <typename context_t>
|
|
|
|
inline typename context_t::return_t dispatch (context_t *c) const
|
|
|
|
{
|
|
|
|
TRACE_DISPATCH (this);
|
|
|
|
switch (u.format) {
|
|
|
|
case 1: return TRACE_RETURN (c->dispatch (u.format1));
|
|
|
|
default:return TRACE_RETURN (c->default_return_value ());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-05-13 20:18:49 +02:00
|
|
|
inline bool sanitize (hb_sanitize_context_t *c) {
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_SANITIZE (this);
|
2012-05-11 01:25:34 +02:00
|
|
|
if (!u.format.sanitize (c)) return TRACE_RETURN (false);
|
2009-08-04 06:58:28 +02:00
|
|
|
switch (u.format) {
|
2012-05-11 01:25:34 +02:00
|
|
|
case 1: return TRACE_RETURN (u.format1.sanitize (c));
|
|
|
|
default:return TRACE_RETURN (true);
|
2009-08-04 06:58:28 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-24 21:40:37 +02:00
|
|
|
protected:
|
2009-04-16 20:19:42 +02:00
|
|
|
union {
|
2009-05-18 01:47:54 +02:00
|
|
|
USHORT 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);
|
2012-11-17 04:07:06 +01:00
|
|
|
unsigned int count = component.len;
|
|
|
|
for (unsigned int i = 1; i < count; i++)
|
2012-12-04 23:08:41 +01:00
|
|
|
c->input->add (component[i]);
|
|
|
|
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)
|
2012-11-22 20:38:10 +01:00
|
|
|
return TRACE_RETURN (false);
|
2012-08-08 04:25:24 +02:00
|
|
|
|
|
|
|
for (unsigned int i = 1; i < c->len; i++)
|
|
|
|
if (likely (c->glyphs[i] != component[i]))
|
2012-11-22 20:38:10 +01:00
|
|
|
return TRACE_RETURN (false);
|
2012-08-08 04:25:24 +02:00
|
|
|
|
2012-11-22 20:38:10 +01:00
|
|
|
return TRACE_RETURN (true);
|
2012-04-20 04:21:38 +02:00
|
|
|
}
|
|
|
|
|
2010-10-27 23:39:01 +02:00
|
|
|
inline bool apply (hb_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
|
|
|
|
|
|
|
if (unlikely (!count)) return TRACE_RETURN (false);
|
2012-01-17 04:05:08 +01: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;
|
|
|
|
unsigned int match_positions[MAX_CONTEXT_LENGTH];
|
|
|
|
|
2012-08-29 04:58:55 +02:00
|
|
|
if (likely (!match_input (c, count,
|
|
|
|
&component[1],
|
|
|
|
match_glyph,
|
|
|
|
NULL,
|
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)))
|
|
|
|
return TRACE_RETURN (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
|
|
|
|
2012-05-11 02:33:11 +02:00
|
|
|
return TRACE_RETURN (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);
|
2012-09-05 00:17:57 +02:00
|
|
|
if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
|
2012-09-06 04:19:28 +02:00
|
|
|
ligGlyph = ligature;
|
2012-09-05 00:17:57 +02:00
|
|
|
if (unlikely (!component.serialize (c, components, num_components))) return TRACE_RETURN (false);
|
|
|
|
return TRACE_RETURN (true);
|
|
|
|
}
|
|
|
|
|
2009-08-04 06:58:28 +02:00
|
|
|
public:
|
2010-05-13 20:18:49 +02:00
|
|
|
inline bool sanitize (hb_sanitize_context_t *c) {
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_SANITIZE (this);
|
2012-05-11 01:25:34 +02:00
|
|
|
return TRACE_RETURN (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))
|
2012-11-22 20:38:10 +01:00
|
|
|
return TRACE_RETURN (true);
|
2012-04-20 04:21:38 +02:00
|
|
|
}
|
2012-11-22 20:38:10 +01:00
|
|
|
return TRACE_RETURN (false);
|
2012-04-20 04:21:38 +02:00
|
|
|
}
|
|
|
|
|
2010-10-27 23:39:01 +02:00
|
|
|
inline bool apply (hb_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];
|
2012-05-11 02:33:11 +02:00
|
|
|
if (lig.apply (c)) return TRACE_RETURN (true);
|
2009-05-05 19:25:13 +02:00
|
|
|
}
|
|
|
|
|
2012-05-11 02:33:11 +02:00
|
|
|
return TRACE_RETURN (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);
|
2012-09-05 00:17:57 +02:00
|
|
|
if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
|
|
|
|
if (unlikely (!ligature.serialize (c, num_ligatures))) return TRACE_RETURN (false);
|
|
|
|
for (unsigned int i = 0; i < num_ligatures; i++)
|
|
|
|
if (unlikely (!ligature[i].serialize (c, this).serialize (c,
|
|
|
|
ligatures[i],
|
|
|
|
component_list,
|
|
|
|
component_count_list[i]))) return TRACE_RETURN (false);
|
2012-09-06 04:19:28 +02:00
|
|
|
ligatures.advance (num_ligatures);
|
2012-09-05 00:17:57 +02:00
|
|
|
component_count_list.advance (num_ligatures);
|
|
|
|
return TRACE_RETURN (true);
|
|
|
|
}
|
|
|
|
|
2010-05-13 20:18:49 +02:00
|
|
|
inline bool sanitize (hb_sanitize_context_t *c) {
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_SANITIZE (this);
|
2012-05-11 01:25:34 +02:00
|
|
|
return TRACE_RETURN (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;
|
|
|
|
for (iter.init (this+coverage); iter.more (); iter.next ()) {
|
|
|
|
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);
|
2012-11-17 04:07:06 +01:00
|
|
|
Coverage::Iter iter;
|
|
|
|
for (iter.init (this+coverage); iter.more (); iter.next ()) {
|
2012-12-04 23:08:41 +01:00
|
|
|
c->input->add (iter.get_glyph ());
|
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]);
|
2012-11-22 20:38:10 +01:00
|
|
|
if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
|
|
|
|
|
|
|
|
const LigatureSet &lig_set = this+ligatureSet[index];
|
|
|
|
return TRACE_RETURN (lig_set.would_apply (c));
|
2012-04-20 04:21:38 +02:00
|
|
|
}
|
|
|
|
|
2010-05-13 20:18:49 +02:00
|
|
|
inline bool apply (hb_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);
|
2012-05-11 02:33:11 +02:00
|
|
|
if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
|
2009-05-18 05:17:56 +02:00
|
|
|
|
2009-05-17 07:22:51 +02:00
|
|
|
const LigatureSet &lig_set = this+ligatureSet[index];
|
2012-05-11 02:33:11 +02:00
|
|
|
return TRACE_RETURN (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);
|
2012-09-05 00:17:57 +02:00
|
|
|
if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
|
|
|
|
if (unlikely (!ligatureSet.serialize (c, num_first_glyphs))) return TRACE_RETURN (false);
|
|
|
|
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],
|
|
|
|
component_list))) return TRACE_RETURN (false);
|
|
|
|
ligature_per_first_glyph_count_list.advance (num_first_glyphs);
|
2012-09-06 04:19:28 +02:00
|
|
|
if (unlikely (!coverage.serialize (c, this).serialize (c, first_glyphs, num_first_glyphs))) return TRACE_RETURN (false);
|
2012-09-05 00:17:57 +02:00
|
|
|
return TRACE_RETURN (true);
|
|
|
|
}
|
|
|
|
|
2010-05-13 20:18:49 +02:00
|
|
|
inline bool sanitize (hb_sanitize_context_t *c) {
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_SANITIZE (this);
|
2012-05-11 01:25:34 +02:00
|
|
|
return TRACE_RETURN (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:
|
2009-05-18 02:13:02 +02:00
|
|
|
USHORT 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);
|
2012-09-05 00:17:57 +02:00
|
|
|
if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
|
|
|
|
unsigned int format = 1;
|
|
|
|
u.format.set (format);
|
|
|
|
switch (u.format) {
|
|
|
|
case 1: return TRACE_RETURN (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_RETURN (false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-09 07:59:30 +01:00
|
|
|
template <typename context_t>
|
|
|
|
inline typename context_t::return_t dispatch (context_t *c) const
|
|
|
|
{
|
|
|
|
TRACE_DISPATCH (this);
|
|
|
|
switch (u.format) {
|
|
|
|
case 1: return TRACE_RETURN (c->dispatch (u.format1));
|
|
|
|
default:return TRACE_RETURN (c->default_return_value ());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-05-13 20:18:49 +02:00
|
|
|
inline bool sanitize (hb_sanitize_context_t *c) {
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_SANITIZE (this);
|
2012-05-11 01:25:34 +02:00
|
|
|
if (!u.format.sanitize (c)) return TRACE_RETURN (false);
|
2009-08-04 06:58:28 +02:00
|
|
|
switch (u.format) {
|
2012-05-11 01:25:34 +02:00
|
|
|
case 1: return TRACE_RETURN (u.format1.sanitize (c));
|
|
|
|
default:return TRACE_RETURN (true);
|
2009-08-04 06:58:28 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-24 21:40:37 +02:00
|
|
|
protected:
|
2009-04-16 22:53:40 +02:00
|
|
|
union {
|
2009-05-18 01:47:54 +02:00
|
|
|
USHORT 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;
|
|
|
|
for (iter.init (this+coverage); iter.more (); iter.next ()) {
|
|
|
|
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);
|
|
|
|
|
2012-11-17 04:07:06 +01:00
|
|
|
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
|
|
|
|
|
|
|
|
unsigned int count;
|
|
|
|
|
2012-12-04 23:08:41 +01:00
|
|
|
(this+coverage).add_coverage (c->input);
|
2012-11-17 04:07:06 +01:00
|
|
|
|
|
|
|
count = backtrack.len;
|
|
|
|
for (unsigned int i = 0; i < count; i++)
|
2012-12-04 23:08:41 +01:00
|
|
|
(this+backtrack[i]).add_coverage (c->before);
|
2012-11-17 04:07:06 +01:00
|
|
|
|
|
|
|
count = lookahead.len;
|
|
|
|
for (unsigned int i = 0; i < count; i++)
|
2012-12-04 23:08:41 +01:00
|
|
|
(this+lookahead[i]).add_coverage (c->after);
|
2012-11-17 04:07:06 +01:00
|
|
|
|
|
|
|
const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
|
|
|
|
count = substitute.len;
|
|
|
|
for (unsigned int i = 0; i < count; i++)
|
2012-12-04 23:08:41 +01:00
|
|
|
c->output->add (substitute[i]);
|
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);
|
2012-11-25 01:13:55 +01:00
|
|
|
return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
|
2012-11-22 20:38:10 +01:00
|
|
|
}
|
|
|
|
|
2010-05-13 20:18:49 +02:00
|
|
|
inline bool apply (hb_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:17:51 +02:00
|
|
|
if (unlikely (c->nesting_level_left != MAX_NESTING_LEVEL))
|
|
|
|
return TRACE_RETURN (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);
|
2012-05-11 02:33:11 +02:00
|
|
|
if (likely (index == NOT_COVERED)) return TRACE_RETURN (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
|
|
|
|
2010-05-13 20:18:49 +02:00
|
|
|
if (match_backtrack (c,
|
2010-05-11 00:20:54 +02:00
|
|
|
backtrack.len, (USHORT *) backtrack.array,
|
2010-05-10 23:47:22 +02:00
|
|
|
match_coverage, this) &&
|
2010-05-13 20:18:49 +02:00
|
|
|
match_lookahead (c,
|
2010-05-11 00:20:54 +02:00
|
|
|
lookahead.len, (USHORT *) lookahead.array,
|
2010-05-10 23:47:22 +02:00
|
|
|
match_coverage, this,
|
2009-05-18 11:47:47 +02:00
|
|
|
1))
|
|
|
|
{
|
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. */
|
2012-05-11 02:33:11 +02:00
|
|
|
return TRACE_RETURN (true);
|
2009-05-18 11:47:47 +02:00
|
|
|
}
|
|
|
|
|
2012-05-11 02:33:11 +02:00
|
|
|
return TRACE_RETURN (false);
|
2009-05-18 02:48:27 +02:00
|
|
|
}
|
2008-01-23 23:01:55 +01:00
|
|
|
|
2010-05-13 20:18:49 +02:00
|
|
|
inline bool sanitize (hb_sanitize_context_t *c) {
|
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)))
|
|
|
|
return TRACE_RETURN (false);
|
2010-04-21 21:56:11 +02:00
|
|
|
OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
|
2010-05-13 20:18:49 +02:00
|
|
|
if (!lookahead.sanitize (c, this))
|
2012-05-11 01:25:34 +02:00
|
|
|
return TRACE_RETURN (false);
|
2010-04-21 21:56:11 +02:00
|
|
|
ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
|
2012-05-11 01:25:34 +02:00
|
|
|
return TRACE_RETURN (substitute.sanitize (c));
|
2009-08-04 06:58:28 +02:00
|
|
|
}
|
|
|
|
|
2012-07-24 21:40:37 +02:00
|
|
|
protected:
|
2009-05-18 02:13:02 +02:00
|
|
|
USHORT 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
|
|
|
{
|
2013-03-09 07:55:04 +01:00
|
|
|
TRACE_DISPATCH (this);
|
2012-11-17 04:07:06 +01:00
|
|
|
switch (u.format) {
|
2013-03-09 07:55:04 +01:00
|
|
|
case 1: return TRACE_RETURN (c->dispatch (u.format1));
|
2012-11-23 23:23:41 +01:00
|
|
|
default:return TRACE_RETURN (c->default_return_value ());
|
2012-07-28 23:31:01 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-05-13 20:18:49 +02:00
|
|
|
inline bool sanitize (hb_sanitize_context_t *c) {
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_SANITIZE (this);
|
2012-05-11 01:25:34 +02:00
|
|
|
if (!u.format.sanitize (c)) return TRACE_RETURN (false);
|
2009-08-04 06:58:28 +02:00
|
|
|
switch (u.format) {
|
2012-05-11 01:25:34 +02:00
|
|
|
case 1: return TRACE_RETURN (u.format1.sanitize (c));
|
|
|
|
default:return TRACE_RETURN (true);
|
2009-08-04 06:58:28 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-24 21:40:37 +02:00
|
|
|
protected:
|
2009-05-18 02:48:27 +02:00
|
|
|
union {
|
|
|
|
USHORT 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
|
|
|
{
|
2013-03-09 07:55:04 +01:00
|
|
|
TRACE_DISPATCH (this);
|
2012-04-23 19:04:38 +02:00
|
|
|
switch (lookup_type) {
|
2013-03-09 07:55:04 +01:00
|
|
|
case Single: return TRACE_RETURN (u.single.dispatch (c));
|
|
|
|
case Multiple: return TRACE_RETURN (u.multiple.dispatch (c));
|
|
|
|
case Alternate: return TRACE_RETURN (u.alternate.dispatch (c));
|
|
|
|
case Ligature: return TRACE_RETURN (u.ligature.dispatch (c));
|
|
|
|
case Context: return TRACE_RETURN (u.context.dispatch (c));
|
|
|
|
case ChainContext: return TRACE_RETURN (u.chainContext.dispatch (c));
|
|
|
|
case Extension: return TRACE_RETURN (u.extension.dispatch (c));
|
|
|
|
case ReverseChainSingle: return TRACE_RETURN (u.reverseChainContextSingle.dispatch (c));
|
2012-11-23 23:23:41 +01:00
|
|
|
default: return TRACE_RETURN (c->default_return_value ());
|
2012-07-19 20:35:23 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-05-13 20:18:49 +02:00
|
|
|
inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_SANITIZE (this);
|
2012-07-28 23:31:01 +02:00
|
|
|
if (!u.header.sub_format.sanitize (c))
|
2012-06-09 09:02:36 +02:00
|
|
|
return TRACE_RETURN (false);
|
2010-05-11 03:39:24 +02:00
|
|
|
switch (lookup_type) {
|
2012-05-11 01:25:34 +02:00
|
|
|
case Single: return TRACE_RETURN (u.single.sanitize (c));
|
|
|
|
case Multiple: return TRACE_RETURN (u.multiple.sanitize (c));
|
|
|
|
case Alternate: return TRACE_RETURN (u.alternate.sanitize (c));
|
|
|
|
case Ligature: return TRACE_RETURN (u.ligature.sanitize (c));
|
2012-07-19 20:35:23 +02:00
|
|
|
case Context: return TRACE_RETURN (u.context.sanitize (c));
|
2012-05-11 01:25:34 +02:00
|
|
|
case ChainContext: return TRACE_RETURN (u.chainContext.sanitize (c));
|
|
|
|
case Extension: return TRACE_RETURN (u.extension.sanitize (c));
|
|
|
|
case ReverseChainSingle: return TRACE_RETURN (u.reverseChainContextSingle.sanitize (c));
|
|
|
|
default: return TRACE_RETURN (true);
|
2009-08-04 06:58:28 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-24 21:40:37 +02:00
|
|
|
protected:
|
2009-04-16 01:50:16 +02:00
|
|
|
union {
|
2012-06-09 08:48:16 +02:00
|
|
|
struct {
|
|
|
|
USHORT sub_format;
|
|
|
|
} header;
|
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:
|
2012-06-09 08:48:16 +02:00
|
|
|
DEFINE_SIZE_UNION (2, header.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
|
|
|
|
{ return this+CastR<OffsetArrayOf<SubstLookupSubTable> > (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)
|
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
|
|
|
|
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>);
|
|
|
|
return TRACE_RETURN (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>);
|
|
|
|
return TRACE_RETURN (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
|
|
|
|
{
|
2012-11-22 20:38:10 +01:00
|
|
|
hb_get_coverage_context_t c;
|
2012-08-02 03:18:54 +02:00
|
|
|
const Coverage *last = NULL;
|
|
|
|
unsigned int count = get_subtable_count ();
|
|
|
|
for (unsigned int i = 0; i < count; i++) {
|
2013-03-09 07:55:04 +01:00
|
|
|
const Coverage *coverage = &get_subtable (i).dispatch (&c, get_type ());
|
2012-11-22 20:38:10 +01:00
|
|
|
if (coverage != last) {
|
|
|
|
coverage->add_coverage (glyphs);
|
|
|
|
last = coverage;
|
2012-08-02 03:18:54 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-04 21:15:19 +02:00
|
|
|
inline bool would_apply (hb_would_apply_context_t *c, const hb_set_digest_t *digest) const
|
2012-04-20 04:21:38 +02:00
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_WOULD_APPLY (this);
|
2012-11-22 20:38:10 +01:00
|
|
|
if (unlikely (!c->len)) return TRACE_RETURN (false);
|
|
|
|
if (!digest->may_have (c->glyphs[0])) return TRACE_RETURN (false);
|
2013-03-09 07:55:04 +01:00
|
|
|
return TRACE_RETURN (dispatch (c));
|
2012-04-20 04:21:38 +02:00
|
|
|
}
|
|
|
|
|
2012-04-11 23:11:05 +02:00
|
|
|
inline bool apply_once (hb_apply_context_t *c) const
|
2009-05-20 05:42:30 +02:00
|
|
|
{
|
2012-11-24 00:13:48 +01:00
|
|
|
TRACE_APPLY (this);
|
2013-02-13 17:13:06 +01:00
|
|
|
if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props))
|
2012-11-24 00:13:48 +01:00
|
|
|
return TRACE_RETURN (false);
|
2013-03-09 07:55:04 +01:00
|
|
|
return TRACE_RETURN (dispatch (c));
|
2009-04-16 01:50:16 +02:00
|
|
|
}
|
2009-04-16 10:45:30 +02:00
|
|
|
|
2012-11-22 22:05:59 +01:00
|
|
|
static bool apply_recurse_func (hb_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)
|
|
|
|
{ return CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable)[i].serialize (c, this); }
|
|
|
|
|
|
|
|
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);
|
2012-09-05 03:13:17 +02:00
|
|
|
if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Single, lookup_props, 1))) return TRACE_RETURN (false);
|
|
|
|
return TRACE_RETURN (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes, num_glyphs));
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2012-09-05 03:13:17 +02:00
|
|
|
if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Multiple, lookup_props, 1))) return TRACE_RETURN (false);
|
|
|
|
return TRACE_RETURN (serialize_subtable (c, 0).u.multiple.serialize (c, glyphs, substitute_len_list, num_glyphs,
|
|
|
|
substitute_glyphs_list));
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2012-09-05 03:13:17 +02:00
|
|
|
if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Alternate, lookup_props, 1))) return TRACE_RETURN (false);
|
|
|
|
return TRACE_RETURN (serialize_subtable (c, 0).u.alternate.serialize (c, glyphs, alternate_len_list, num_glyphs,
|
|
|
|
alternate_glyphs_list));
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2012-09-05 03:13:17 +02:00
|
|
|
if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Ligature, lookup_props, 1))) return TRACE_RETURN (false);
|
|
|
|
return TRACE_RETURN (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));
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
{
|
|
|
|
TRACE_DISPATCH (this);
|
|
|
|
unsigned int lookup_type = get_type ();
|
|
|
|
unsigned int count = get_subtable_count ();
|
|
|
|
for (unsigned int i = 0; i < count; i++) {
|
|
|
|
typename context_t::return_t r = get_subtable (i).dispatch (c, lookup_type);
|
|
|
|
if (c->stop_sublookup_iteration (r))
|
|
|
|
return TRACE_RETURN (r);
|
|
|
|
}
|
|
|
|
return TRACE_RETURN (c->default_return_value ());
|
|
|
|
}
|
|
|
|
|
2012-09-05 03:13:17 +02:00
|
|
|
inline bool sanitize (hb_sanitize_context_t *c)
|
|
|
|
{
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_SANITIZE (this);
|
2012-05-11 01:25:34 +02:00
|
|
|
if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false);
|
2012-07-12 00:01:27 +02:00
|
|
|
OffsetArrayOf<SubstLookupSubTable> &list = CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable);
|
2012-07-29 00:53:01 +02:00
|
|
|
if (unlikely (!list.sanitize (c, this, get_type ()))) return TRACE_RETURN (false);
|
|
|
|
|
|
|
|
if (unlikely (get_type () == SubstLookupSubTable::Extension))
|
|
|
|
{
|
|
|
|
/* The spec says all subtables of an Extension lookup should
|
|
|
|
* have the same type. This is specially important if one has
|
2013-02-15 17:47:24 +01:00
|
|
|
* 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)
|
|
|
|
return TRACE_RETURN (false);
|
|
|
|
}
|
|
|
|
return TRACE_RETURN (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);
|
|
|
|
static inline void substitute_finish (hb_font_t *font, hb_buffer_t *buffer);
|
2011-07-28 21:42:18 +02:00
|
|
|
|
2010-05-13 20:18:49 +02:00
|
|
|
inline bool sanitize (hb_sanitize_context_t *c) {
|
2012-11-23 21:32:14 +01:00
|
|
|
TRACE_SANITIZE (this);
|
2012-05-11 01:25:34 +02:00
|
|
|
if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false);
|
2010-04-23 22:35:01 +02:00
|
|
|
OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
|
2012-05-11 01:25:34 +02:00
|
|
|
return TRACE_RETURN (list.sanitize (c, this));
|
2009-08-04 08:27:37 +02:00
|
|
|
}
|
2010-05-10 22:57:29 +02:00
|
|
|
public:
|
|
|
|
DEFINE_SIZE_STATIC (10);
|
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
|
|
|
{
|
2013-10-18 00:42:39 +02:00
|
|
|
_hb_buffer_allocate_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++)
|
|
|
|
{
|
2013-10-18 00:21:59 +02:00
|
|
|
_hb_glyph_info_set_glyph_props (&buffer->info[i], gdef.get_glyph_props (buffer->info[i].codepoint));
|
2013-10-18 00:42:39 +02:00
|
|
|
_hb_glyph_info_clear_lig_props (&buffer->info[i]);
|
|
|
|
buffer->info[i].syllable() = 0;
|
2012-07-31 01:30:01 +02:00
|
|
|
}
|
2011-07-28 21:42:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2012-08-02 14:36:40 +02:00
|
|
|
GSUB::substitute_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer HB_UNUSED)
|
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))
|
2012-11-23 23:04:55 +01:00
|
|
|
return CastR<ExtensionSubst> (get_subtable<SubstLookupSubTable>()).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
|
|
|
}
|
|
|
|
|
2014-04-28 23:29:39 +02:00
|
|
|
/*static*/ inline bool SubstLookup::apply_recurse_func (hb_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;
|
2012-11-22 22:05:59 +01:00
|
|
|
c->set_lookup (l);
|
2012-11-24 07:13:20 +01:00
|
|
|
bool ret = l.apply_once (c);
|
|
|
|
c->lookup_props = saved_lookup_props;
|
|
|
|
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 */
|