harfbuzz/src/hb-ot-layout-gsub-table.hh

1350 lines
40 KiB
C++
Raw Normal View History

2008-01-23 23:01:55 +01:00
/*
2011-04-21 23:14:28 +02:00
* Copyright © 2007,2008,2009,2010 Red Hat, Inc.
* 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
* Google Author(s): Behdad Esfahbod
2008-01-23 23:01:55 +01:00
*/
#ifndef HB_OT_LAYOUT_GSUB_TABLE_HH
#define HB_OT_LAYOUT_GSUB_TABLE_HH
2008-01-23 23:01:55 +01:00
#include "hb-ot-layout-gsubgpos-private.hh"
2008-01-23 23:01:55 +01:00
2010-07-23 21:11:18 +02:00
namespace OT {
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-11-23 21:32:14 +01:00
TRACE_CLOSURE (this);
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))
c->glyphs->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
}
}
inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
2012-11-24 00:13:48 +01:00
TRACE_COLLECT_GLYPHS (this);
Coverage::Iter iter;
for (iter.init (this+coverage); iter.more (); iter.next ()) {
hb_codepoint_t glyph_id = iter.get_glyph ();
c->input->add (glyph_id);
c->output->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
}
}
inline const Coverage &get_coverage (void) const
{
return this+coverage;
}
inline bool would_apply (hb_would_apply_context_t *c) const
{
2012-11-23 21:32:14 +01:00
TRACE_WOULD_APPLY (this);
return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
}
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);
hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
unsigned int index = (this+coverage).get_coverage (glyph_id);
if (likely (index == NOT_COVERED)) return_trace (false);
2009-04-16 04:56:15 +02:00
/* According to the Adobe Annotated OpenType Suite, result is always
* limited to 16bit. */
glyph_id = (glyph_id + deltaGlyphID) & 0xFFFFu;
c->replace_glyph (glyph_id);
2009-04-16 04:56:15 +02:00
return_trace (true);
}
2009-04-16 04:56:15 +02:00
2012-09-02 02:48:22 +02:00
inline bool serialize (hb_serialize_context_t *c,
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);
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? */
return_trace (true);
2012-09-02 02:48:22 +02:00
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
2012-11-23 21:32:14 +01:00
TRACE_SANITIZE (this);
return_trace (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
2009-08-04 06:58:28 +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 */
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-11-23 21:32:14 +01:00
TRACE_CLOSURE (this);
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 ()]);
}
}
inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
2012-11-24 00:13:48 +01:00
TRACE_COLLECT_GLYPHS (this);
Coverage::Iter iter;
for (iter.init (this+coverage); iter.more (); iter.next ()) {
c->input->add (iter.get_glyph ());
c->output->add (substitute[iter.get_coverage ()]);
}
}
inline const Coverage &get_coverage (void) const
{
return this+coverage;
}
inline bool would_apply (hb_would_apply_context_t *c) const
{
2012-11-23 21:32:14 +01:00
TRACE_WOULD_APPLY (this);
return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
}
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);
hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
unsigned int index = (this+coverage).get_coverage (glyph_id);
if (likely (index == NOT_COVERED)) return_trace (false);
if (unlikely (index >= substitute.len)) return_trace (false);
glyph_id = substitute[index];
c->replace_glyph (glyph_id);
2009-05-20 05:42:30 +02:00
return_trace (true);
}
2008-01-23 23:01:55 +01:00
2012-09-02 03:43:38 +02:00
inline bool serialize (hb_serialize_context_t *c,
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);
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
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
2012-11-23 21:32:14 +01:00
TRACE_SANITIZE (this);
return_trace (coverage.sanitize (c, this) && substitute.sanitize (c));
2009-08-04 06:58:28 +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 */
public:
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,
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);
if (unlikely (!c->extend_min (u.format))) return_trace (false);
2012-09-02 03:43:38 +02:00
unsigned int format = 2;
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) {
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);
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) {
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
}
}
protected:
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;
} u;
2008-01-23 23:01:55 +01: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-11-23 21:32:14 +01:00
TRACE_CLOSURE (this);
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]);
}
inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
2012-11-24 00:13:48 +01:00
TRACE_COLLECT_GLYPHS (this);
unsigned int count = substitute.len;
for (unsigned int i = 0; i < count; i++)
c->output->add (substitute[i]);
}
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-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))
{
c->replace_glyph (substitute.array[0]);
return_trace (true);
}
/* Spec disallows this, but Uniscribe allows it.
* https://github.com/behdad/harfbuzz/issues/253 */
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);
c->output_glyph_for_component (substitute.array[i], klass);
}
2014-06-06 00:54:44 +02:00
c->buffer->skip_glyph ();
2009-05-05 22:22:02 +02:00
return_trace (true);
2009-05-05 22:22:02 +02:00
}
inline bool serialize (hb_serialize_context_t *c,
Supplier<GlyphID> &glyphs,
unsigned int num_glyphs)
{
2012-11-23 21:32:14 +01:00
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (*this))) return_trace (false);
if (unlikely (!substitute.serialize (c, glyphs, num_glyphs))) return_trace (false);
return_trace (true);
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
2012-11-23 21:32:14 +01:00
TRACE_SANITIZE (this);
return_trace (substitute.sanitize (c));
2009-08-04 06:58:28 +02:00
}
protected:
2009-05-17 07:22:51 +02:00
ArrayOf<GlyphID>
substitute; /* String of GlyphIDs to substitute */
public:
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-11-23 21:32:14 +01:00
TRACE_CLOSURE (this);
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);
}
}
inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
2012-11-24 00:13:48 +01:00
TRACE_COLLECT_GLYPHS (this);
(this+coverage).add_coverage (c->input);
unsigned int count = sequence.len;
for (unsigned int i = 0; i < count; i++)
(this+sequence[i]).collect_glyphs (c);
}
inline const Coverage &get_coverage (void) const
{
return this+coverage;
}
inline bool would_apply (hb_would_apply_context_t *c) const
{
2012-11-23 21:32:14 +01:00
TRACE_WOULD_APPLY (this);
return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
}
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);
unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return_trace (false);
return_trace ((this+sequence[index]).apply (c));
}
2008-01-23 23:01:55 +01:00
inline bool serialize (hb_serialize_context_t *c,
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);
if (unlikely (!c->extend_min (*this))) return_trace (false);
if (unlikely (!sequence.serialize (c, num_glyphs))) return_trace (false);
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 (false);
substitute_len_list.advance (num_glyphs);
if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
return_trace (true);
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
2012-11-23 21:32:14 +01:00
TRACE_SANITIZE (this);
return_trace (coverage.sanitize (c, this) && sequence.sanitize (c, this));
2009-08-04 06:58:28 +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 */
public:
DEFINE_SIZE_ARRAY (6, sequence);
2008-01-23 23:01:55 +01:00
};
2009-05-20 05:42:30 +02:00
struct MultipleSubst
{
inline bool serialize (hb_serialize_context_t *c,
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);
if (unlikely (!c->extend_min (u.format))) return_trace (false);
unsigned int format = 1;
u.format.set (format);
switch (u.format) {
case 1: return_trace (u.format1.serialize (c, glyphs, substitute_len_list, num_glyphs, substitute_glyphs_list));
default:return_trace (false);
}
}
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);
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) {
case 1: return_trace (c->dispatch (u.format1));
default:return_trace (c->default_return_value ());
2013-03-09 07:59:30 +01:00
}
}
protected:
union {
2009-05-18 01:47:54 +02:00
USHORT format; /* Format identifier */
2010-05-11 01:45:41 +02:00
MultipleSubstFormat1 format1;
} 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-11-23 21:32:14 +01:00
TRACE_CLOSURE (this);
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]);
}
}
}
inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
2012-11-24 00:13:48 +01:00
TRACE_COLLECT_GLYPHS (this);
Coverage::Iter iter;
for (iter.init (this+coverage); iter.more (); iter.next ()) {
c->input->add (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++)
c->output->add (alt_set[i]);
}
}
inline const Coverage &get_coverage (void) const
{
return this+coverage;
}
inline bool would_apply (hb_would_apply_context_t *c) const
{
2012-11-23 21:32:14 +01:00
TRACE_WOULD_APPLY (this);
return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
}
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);
hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
2009-04-16 20:19:42 +02:00
unsigned int index = (this+coverage).get_coverage (glyph_id);
if (likely (index == NOT_COVERED)) return_trace (false);
2009-05-17 07:22:51 +02:00
const AlternateSet &alt_set = this+alternateSet[index];
2009-04-16 20:19:42 +02:00
if (unlikely (!alt_set.len)) return_trace (false);
2009-04-16 20:19:42 +02:00
hb_mask_t glyph_mask = c->buffer->cur().mask;
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. */
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
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
c->replace_glyph (glyph_id);
2009-04-16 20:19:42 +02:00
return_trace (true);
2009-04-16 20:19:42 +02:00
}
2008-01-23 23:01:55 +01:00
inline bool serialize (hb_serialize_context_t *c,
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);
if (unlikely (!c->extend_min (*this))) return_trace (false);
if (unlikely (!alternateSet.serialize (c, num_glyphs))) return_trace (false);
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 (false);
alternate_len_list.advance (num_glyphs);
if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
return_trace (true);
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
2012-11-23 21:32:14 +01:00
TRACE_SANITIZE (this);
return_trace (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
2009-08-04 06:58:28 +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 */
public:
DEFINE_SIZE_ARRAY (6, alternateSet);
2008-01-23 23:01:55 +01:00
};
2009-05-20 05:42:30 +02:00
struct AlternateSubst
{
inline bool serialize (hb_serialize_context_t *c,
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);
if (unlikely (!c->extend_min (u.format))) return_trace (false);
unsigned int format = 1;
u.format.set (format);
switch (u.format) {
case 1: return_trace (u.format1.serialize (c, glyphs, alternate_len_list, num_glyphs, alternate_glyphs_list));
default:return_trace (false);
}
}
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);
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) {
case 1: return_trace (c->dispatch (u.format1));
default:return_trace (c->default_return_value ());
2013-03-09 07:59:30 +01: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-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-11-23 21:32:14 +01:00
TRACE_CLOSURE (this);
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);
}
inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
2012-11-24 00:13:48 +01:00
TRACE_COLLECT_GLYPHS (this);
unsigned int count = component.len;
for (unsigned int i = 1; i < count; i++)
c->input->add (component[i]);
c->output->add (ligGlyph);
}
inline bool would_apply (hb_would_apply_context_t *c) const
{
2012-11-23 21:32:14 +01:00
TRACE_WOULD_APPLY (this);
if (c->len != component.len)
return_trace (false);
for (unsigned int i = 1; i < c->len; i++)
if (likely (c->glyphs[i] != component[i]))
return_trace (false);
return_trace (true);
}
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 (false);
2012-01-17 04:05:08 +01:00
/* Special-case to make it in-place and not consider this
* as a "ligated" substitution. */
if (unlikely (count == 1))
{
c->replace_glyph (ligGlyph);
return_trace (true);
}
2012-11-23 20:07:24 +01:00
bool is_mark_ligature = false;
unsigned int total_component_count = 0;
unsigned int match_length = 0;
unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
if (likely (!match_input (c, count,
&component[1],
match_glyph,
NULL,
&match_length,
match_positions,
&is_mark_ligature,
&total_component_count)))
return_trace (false);
2012-08-29 05:18:22 +02:00
ligate_input (c,
count,
match_positions,
match_length,
ligGlyph,
2012-08-29 05:18:22 +02:00
is_mark_ligature,
total_component_count);
return_trace (true);
}
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);
if (unlikely (!c->extend_min (*this))) return_trace (false);
ligGlyph = ligature;
if (unlikely (!component.serialize (c, components, num_components))) return_trace (false);
return_trace (true);
}
2009-08-04 06:58:28 +02:00
public:
inline bool sanitize (hb_sanitize_context_t *c) const
{
2012-11-23 21:32:14 +01:00
TRACE_SANITIZE (this);
return_trace (ligGlyph.sanitize (c) && component.sanitize (c));
2009-08-04 06:58:28 +02:00
}
protected:
GlyphID ligGlyph; /* GlyphID of ligature to substitute */
2009-05-18 08:03:58 +02:00
HeadlessArrayOf<GlyphID>
component; /* Array of component GlyphIDs--start
* with the second component--ordered
* in writing direction */
public:
DEFINE_SIZE_ARRAY (4, component);
};
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-11-23 21:32:14 +01:00
TRACE_CLOSURE (this);
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);
}
inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
2012-11-24 00:13:48 +01:00
TRACE_COLLECT_GLYPHS (this);
unsigned int num_ligs = ligature.len;
for (unsigned int i = 0; i < num_ligs; i++)
(this+ligature[i]).collect_glyphs (c);
}
inline bool would_apply (hb_would_apply_context_t *c) const
{
2012-11-23 21:32:14 +01:00
TRACE_WOULD_APPLY (this);
unsigned int num_ligs = ligature.len;
for (unsigned int i = 0; i < num_ligs; i++)
{
const Ligature &lig = this+ligature[i];
if (lig.would_apply (c))
return_trace (true);
}
return_trace (false);
}
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];
if (lig.apply (c)) return_trace (true);
}
return_trace (false);
}
2008-01-23 23:01:55 +01: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);
if (unlikely (!c->extend_min (*this))) return_trace (false);
if (unlikely (!ligature.serialize (c, num_ligatures))) return_trace (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 (false);
ligatures.advance (num_ligatures);
component_count_list.advance (num_ligatures);
return_trace (true);
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
2012-11-23 21:32:14 +01:00
TRACE_SANITIZE (this);
return_trace (ligature.sanitize (c, this));
2009-08-04 06:58:28 +02:00
}
protected:
2009-05-17 07:22:51 +02:00
OffsetArrayOf<Ligature>
ligature; /* Array LigatureSet tables
* ordered by preference */
public:
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-11-23 21:32:14 +01:00
TRACE_CLOSURE (this);
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);
}
}
inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
2012-11-24 00:13:48 +01:00
TRACE_COLLECT_GLYPHS (this);
Coverage::Iter iter;
for (iter.init (this+coverage); iter.more (); iter.next ()) {
c->input->add (iter.get_glyph ());
(this+ligatureSet[iter.get_coverage ()]).collect_glyphs (c);
}
}
inline const Coverage &get_coverage (void) const
{
return this+coverage;
}
inline bool would_apply (hb_would_apply_context_t *c) const
{
2012-11-23 21:32:14 +01:00
TRACE_WOULD_APPLY (this);
unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
if (likely (index == NOT_COVERED)) return_trace (false);
const LigatureSet &lig_set = this+ligatureSet[index];
return_trace (lig_set.would_apply (c));
}
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);
hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
2009-04-16 22:53:40 +02:00
unsigned int index = (this+coverage).get_coverage (glyph_id);
if (likely (index == NOT_COVERED)) return_trace (false);
2009-05-17 07:22:51 +02:00
const LigatureSet &lig_set = this+ligatureSet[index];
return_trace (lig_set.apply (c));
2009-04-16 22:53:40 +02:00
}
2008-01-23 23:01:55 +01: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);
if (unlikely (!c->extend_min (*this))) return_trace (false);
if (unlikely (!ligatureSet.serialize (c, num_first_glyphs))) return_trace (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 (false);
ligature_per_first_glyph_count_list.advance (num_first_glyphs);
if (unlikely (!coverage.serialize (c, this).serialize (c, first_glyphs, num_first_glyphs))) return_trace (false);
return_trace (true);
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
2012-11-23 21:32:14 +01:00
TRACE_SANITIZE (this);
return_trace (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
2009-08-04 06:58:28 +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
* 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 */
public:
DEFINE_SIZE_ARRAY (6, ligatureSet);
2008-01-23 23:01:55 +01:00
};
2009-05-20 05:42:30 +02:00
struct LigatureSubst
{
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);
if (unlikely (!c->extend_min (u.format))) return_trace (false);
unsigned int format = 1;
u.format.set (format);
switch (u.format) {
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);
}
}
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);
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) {
case 1: return_trace (c->dispatch (u.format1));
default:return_trace (c->default_return_value ());
2013-03-09 07:59:30 +01: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
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-11-23 21:32:14 +01:00
TRACE_CLOSURE (this);
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;
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;
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 ()]);
}
}
inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
2012-11-24 00:13:48 +01:00
TRACE_COLLECT_GLYPHS (this);
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
unsigned int count;
(this+coverage).add_coverage (c->input);
count = backtrack.len;
for (unsigned int i = 0; i < count; i++)
(this+backtrack[i]).add_coverage (c->before);
count = lookahead.len;
for (unsigned int i = 0; i < count; i++)
(this+lookahead[i]).add_coverage (c->after);
const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
count = substitute.len;
for (unsigned int i = 0; i < count; i++)
c->output->add (substitute[i]);
}
inline const Coverage &get_coverage (void) const
{
return this+coverage;
}
inline bool would_apply (hb_would_apply_context_t *c) const
{
2012-11-23 21:32:14 +01:00
TRACE_WOULD_APPLY (this);
return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
}
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);
if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL))
return_trace (false); /* No chaining to this type */
unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return_trace (false);
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
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,
1))
{
2012-07-31 00:36:42 +02:00
c->replace_glyph_inplace (substitute[index]);
/* 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. */
return_trace (true);
}
return_trace (false);
}
2008-01-23 23:01:55 +01:00
inline bool sanitize (hb_sanitize_context_t *c) const
{
2012-11-23 21:32:14 +01:00
TRACE_SANITIZE (this);
if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
return_trace (false);
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2010-05-13 20:18:49 +02:00
if (!lookahead.sanitize (c, this))
return_trace (false);
const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
return_trace (substitute.sanitize (c));
2009-08-04 06:58:28 +02:00
}
protected:
2009-05-18 02:13:02 +02:00
USHORT format; /* Format identifier--format = 1 */
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 */
OffsetArrayOf<Coverage>
lookaheadX; /* Array of coverage tables
* in lookahead sequence, in glyph
2008-01-23 23:01:55 +01:00
* sequence order */
ArrayOf<GlyphID>
substituteX; /* Array of substitute
* GlyphIDs--ordered by Coverage Index */
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
{
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);
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
switch (u.format) {
case 1: return_trace (c->dispatch (u.format1));
default:return_trace (c->default_return_value ());
}
}
protected:
union {
USHORT format; /* Format identifier */
2010-05-11 01:45:41 +02:00
ReverseChainSingleSubstFormat1 format1;
} 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;
enum Type {
Single = 1,
Multiple = 2,
Alternate = 3,
Ligature = 4,
Context = 5,
ChainContext = 6,
Extension = 7,
2009-08-18 22:41:59 +02:00
ReverseChainSingle = 8
};
template <typename context_t>
inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
{
2014-12-13 05:36:49 +01:00
TRACE_DISPATCH (this, lookup_type);
if (unlikely (!c->may_dispatch (this, &u.sub_format))) return_trace (c->no_dispatch_return_value ());
switch (lookup_type) {
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 ());
}
}
protected:
2009-04-16 01:50:16 +02:00
union {
2015-02-17 14:05:30 +01:00
USHORT sub_format;
2010-05-11 01:45:41 +02:00
SingleSubst single;
MultipleSubst multiple;
AlternateSubst alternate;
LigatureSubst ligature;
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
{
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
inline static bool lookup_type_is_reverse (unsigned int lookup_type)
{ return lookup_type == SubstLookupSubTable::ReverseChainSingle; }
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 ();
if (unlikely (type == SubstLookupSubTable::Extension))
return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
return lookup_type_is_reverse (type);
2009-04-16 01:50:16 +02:00
}
2015-02-19 08:47:18 +01:00
inline bool apply (hb_apply_context_t *c) const
{
TRACE_APPLY (this);
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);
c->set_recurse_func (dispatch_recurse_func<hb_closure_context_t>);
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);
c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
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
{
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-11-23 21:32:14 +01:00
TRACE_WOULD_APPLY (this);
if (unlikely (!c->len)) return_trace (false);
if (!accel->may_have (c->glyphs[0])) return_trace (false);
return_trace (dispatch (c));
}
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)
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);
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);
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);
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);
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
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);
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
* 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 (false);
2012-07-29 00:53:01 +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
{ return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); }
2009-04-16 01:50:16 +02:00
static inline void substitute_start (hb_font_t *font, hb_buffer_t *buffer);
inline bool sanitize (hb_sanitize_context_t *c) const
{
2012-11-23 21:32:14 +01:00
TRACE_SANITIZE (this);
if (unlikely (!GSUBGPOS::sanitize (c))) return_trace (false);
const OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
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
void
GSUB::substitute_start (hb_font_t *font, hb_buffer_t *buffer)
{
_hb_buffer_assert_gsubgpos_vars (buffer);
2011-07-28 22:48:43 +02:00
const GDEF &gdef = *hb_ot_layout_from_face (font->face)->gdef;
unsigned int count = buffer->len;
Synthesize GDEF glyph class for any glyph that does not have one in GDEF Previously we only synthesized GDEF glyph classes if the glyphClassDef array in GDEF was null. This worked well enough, and is indeed what OpenType requires: "If the font does not include a GlyphClassDef table, the client must define and maintain this information when using the GSUB and GPOS tables." That sentence does not quite make sense since one needs Unicode properties as well, but is close enough. However, looks like Arial Unicode as shipped on WinXP, does have GDEF glyph class array, but defines no classes for Hebrew. This results in Hebrew marks not getting their widths zeroed. So, with this change, we synthesize glyph class for any glyph that is not specified in the GDEF glyph class table. Since, from our point of view, a glyph not being listed in that table is a font bug, any unwanted consequence of this change is a font bug :). Note that we still don't get the same rendering as Uniscribe, since Uniscribe seems to do fallback positioning as well, even though the font does have a GPOS table (which does NOT cover Hebrew!). We are not going to try to match that though. Test string for Arial Unicode: U+05E9,U+05B8,U+05C1,U+05DC Before: [gid1166=3+991|gid1142=0+737|gid5798=0+1434] After: [gid1166=3+991|gid1142=0+0|gid5798=0+1434] Uniscribe: [gid1166=3+991|gid1142=0@348,0+0|gid5798=0+1434] Note that our new output matches what we were generating until July 2014, because the Hebrew shaper used to zero mark advances based on Unicode, NOT GDEF. That's 9e834e29e0b657f0555df1ab9cea79ff7abcf08d. Reported by Greg Douglas.
2016-03-17 19:59:43 +01:00
hb_glyph_info_t *info = buffer->info;
2013-10-18 00:42:39 +02:00
for (unsigned int i = 0; i < count; i++)
{
Synthesize GDEF glyph class for any glyph that does not have one in GDEF Previously we only synthesized GDEF glyph classes if the glyphClassDef array in GDEF was null. This worked well enough, and is indeed what OpenType requires: "If the font does not include a GlyphClassDef table, the client must define and maintain this information when using the GSUB and GPOS tables." That sentence does not quite make sense since one needs Unicode properties as well, but is close enough. However, looks like Arial Unicode as shipped on WinXP, does have GDEF glyph class array, but defines no classes for Hebrew. This results in Hebrew marks not getting their widths zeroed. So, with this change, we synthesize glyph class for any glyph that is not specified in the GDEF glyph class table. Since, from our point of view, a glyph not being listed in that table is a font bug, any unwanted consequence of this change is a font bug :). Note that we still don't get the same rendering as Uniscribe, since Uniscribe seems to do fallback positioning as well, even though the font does have a GPOS table (which does NOT cover Hebrew!). We are not going to try to match that though. Test string for Arial Unicode: U+05E9,U+05B8,U+05C1,U+05DC Before: [gid1166=3+991|gid1142=0+737|gid5798=0+1434] After: [gid1166=3+991|gid1142=0+0|gid5798=0+1434] Uniscribe: [gid1166=3+991|gid1142=0@348,0+0|gid5798=0+1434] Note that our new output matches what we were generating until July 2014, because the Hebrew shaper used to zero mark advances based on Unicode, NOT GDEF. That's 9e834e29e0b657f0555df1ab9cea79ff7abcf08d. Reported by Greg Douglas.
2016-03-17 19:59:43 +01:00
unsigned int props = gdef.get_glyph_props (info[i].codepoint);
if (!props)
{
/* Never mark default-ignorables as marks.
* They won't get in the way of lookups anyway,
* but having them as mark will cause them to be skipped
* over if the lookup-flag says so, but at least for the
* Mongolian variation selectors, looks like Uniscribe
* marks them as non-mark. Some Mongolian fonts without
* GDEF rely on this. Another notable character that
* this applies to is COMBINING GRAPHEME JOINER. */
props = (_hb_glyph_info_get_general_category (&info[i]) !=
HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK ||
_hb_glyph_info_is_default_ignorable (&info[i])) ?
HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH :
HB_OT_LAYOUT_GLYPH_PROPS_MARK;
}
_hb_glyph_info_set_glyph_props (&info[i], props);
_hb_glyph_info_clear_lig_props (&info[i]);
2013-10-18 00:42:39 +02:00
buffer->info[i].syllable() = 0;
}
}
2009-05-18 03:06:08 +02:00
/* Out-of-class implementation for methods recursing */
2009-05-16 00:54:53 +02:00
/*static*/ inline bool ExtensionSubst::is_reverse (void) const
{
unsigned int type = get_type ();
if (unlikely (type == SubstLookupSubTable::Extension))
return CastR<ExtensionSubst> (get_subtable<LookupSubTable>()).is_reverse ();
return SubstLookup::lookup_type_is_reverse (type);
}
template <typename context_t>
/*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);
return l.dispatch (c);
2012-11-23 23:55:40 +01: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
{
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);
unsigned int saved_lookup_props = c->lookup_props;
unsigned int saved_lookup_index = c->lookup_index;
c->set_lookup_index (lookup_index);
c->set_lookup_props (l.get_props ());
bool ret = l.dispatch (c);
c->set_lookup_index (saved_lookup_index);
c->set_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 */
2010-07-23 21:11:18 +02:00
#endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */