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

Packit Service 5bcba8
/*
Packit Service 5bcba8
 * Copyright © 2007,2008,2009,2010  Red Hat, Inc.
Packit Service 5bcba8
 * Copyright © 2010,2012,2013  Google, Inc.
Packit Service 5bcba8
 *
Packit Service 5bcba8
 *  This is part of HarfBuzz, a text shaping library.
Packit Service 5bcba8
 *
Packit Service 5bcba8
 * Permission is hereby granted, without written agreement and without
Packit Service 5bcba8
 * license or royalty fees, to use, copy, modify, and distribute this
Packit Service 5bcba8
 * software and its documentation for any purpose, provided that the
Packit Service 5bcba8
 * above copyright notice and the following two paragraphs appear in
Packit Service 5bcba8
 * all copies of this software.
Packit Service 5bcba8
 *
Packit Service 5bcba8
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
Packit Service 5bcba8
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
Packit Service 5bcba8
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
Packit Service 5bcba8
 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
Packit Service 5bcba8
 * DAMAGE.
Packit Service 5bcba8
 *
Packit Service 5bcba8
 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
Packit Service 5bcba8
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
Packit Service 5bcba8
 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
Packit Service 5bcba8
 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
Packit Service 5bcba8
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
Packit Service 5bcba8
 *
Packit Service 5bcba8
 * Red Hat Author(s): Behdad Esfahbod
Packit Service 5bcba8
 * Google Author(s): Behdad Esfahbod
Packit Service 5bcba8
 */
Packit Service 5bcba8
Packit Service 5bcba8
#ifndef HB_OT_LAYOUT_GSUB_TABLE_HH
Packit Service 5bcba8
#define HB_OT_LAYOUT_GSUB_TABLE_HH
Packit Service 5bcba8
Packit Service 5bcba8
#include "hb-ot-layout-gsubgpos-private.hh"
Packit Service 5bcba8
Packit Service 5bcba8
Packit Service 5bcba8
namespace OT {
Packit Service 5bcba8
Packit Service 5bcba8
Packit Service 5bcba8
struct SingleSubstFormat1
Packit Service 5bcba8
{
Packit Service 5bcba8
  inline void closure (hb_closure_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_CLOSURE (this);
Packit Service 5bcba8
    Coverage::Iter iter;
Packit Service 5bcba8
    for (iter.init (this+coverage); iter.more (); iter.next ())
Packit Service 5bcba8
    {
Packit Service 5bcba8
      /* TODO Switch to range-based API to work around malicious fonts.
Packit Service 5bcba8
       * https://github.com/behdad/harfbuzz/issues/363 */
Packit Service 5bcba8
      hb_codepoint_t glyph_id = iter.get_glyph ();
Packit Service 5bcba8
      if (c->glyphs->has (glyph_id))
Packit Service 5bcba8
	c->glyphs->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
Packit Service 5bcba8
    }
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_COLLECT_GLYPHS (this);
Packit Service 5bcba8
    Coverage::Iter iter;
Packit Service 5bcba8
    for (iter.init (this+coverage); iter.more (); iter.next ())
Packit Service 5bcba8
    {
Packit Service 5bcba8
      /* TODO Switch to range-based API to work around malicious fonts.
Packit Service 5bcba8
       * https://github.com/behdad/harfbuzz/issues/363 */
Packit Service 5bcba8
      hb_codepoint_t glyph_id = iter.get_glyph ();
Packit Service 5bcba8
      c->input->add (glyph_id);
Packit Service 5bcba8
      c->output->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
Packit Service 5bcba8
    }
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline const Coverage &get_coverage (void) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    return this+coverage;
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline bool would_apply (hb_would_apply_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_WOULD_APPLY (this);
Packit Service 5bcba8
    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline bool apply (hb_apply_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_APPLY (this);
Packit Service 5bcba8
    hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
Packit Service 5bcba8
    unsigned int index = (this+coverage).get_coverage (glyph_id);
Packit Service 5bcba8
    if (likely (index == NOT_COVERED)) return_trace (false);
Packit Service 5bcba8
Packit Service 5bcba8
    /* According to the Adobe Annotated OpenType Suite, result is always
Packit Service 5bcba8
     * limited to 16bit. */
Packit Service 5bcba8
    glyph_id = (glyph_id + deltaGlyphID) & 0xFFFFu;
Packit Service 5bcba8
    c->replace_glyph (glyph_id);
Packit Service 5bcba8
Packit Service 5bcba8
    return_trace (true);
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline bool serialize (hb_serialize_context_t *c,
Packit Service 5bcba8
			 Supplier<GlyphID> &glyphs,
Packit Service 5bcba8
			 unsigned int num_glyphs,
Packit Service 5bcba8
			 int delta)
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_SERIALIZE (this);
Packit Service 5bcba8
    if (unlikely (!c->extend_min (*this))) return_trace (false);
Packit Service 5bcba8
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
Packit Service 5bcba8
    deltaGlyphID.set (delta); /* TODO(serilaize) overflow? */
Packit Service 5bcba8
    return_trace (true);
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline bool sanitize (hb_sanitize_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_SANITIZE (this);
Packit Service 5bcba8
    return_trace (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  protected:
Packit Service 5bcba8
  USHORT	format;			/* Format identifier--format = 1 */
Packit Service 5bcba8
  OffsetTo<Coverage>
Packit Service 5bcba8
		coverage;		/* Offset to Coverage table--from
Packit Service 5bcba8
					 * beginning of Substitution table */
Packit Service 5bcba8
  SHORT		deltaGlyphID;		/* Add to original GlyphID to get
Packit Service 5bcba8
					 * substitute GlyphID */
Packit Service 5bcba8
  public:
Packit Service 5bcba8
  DEFINE_SIZE_STATIC (6);
Packit Service 5bcba8
};
Packit Service 5bcba8
Packit Service 5bcba8
struct SingleSubstFormat2
Packit Service 5bcba8
{
Packit Service 5bcba8
  inline void closure (hb_closure_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_CLOSURE (this);
Packit Service 5bcba8
    Coverage::Iter iter;
Packit Service 5bcba8
    unsigned int count = substitute.len;
Packit Service 5bcba8
    for (iter.init (this+coverage); iter.more (); iter.next ())
Packit Service 5bcba8
    {
Packit Service 5bcba8
      if (unlikely (iter.get_coverage () >= count))
Packit Service 5bcba8
        break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
Packit Service 5bcba8
      if (c->glyphs->has (iter.get_glyph ()))
Packit Service 5bcba8
	c->glyphs->add (substitute[iter.get_coverage ()]);
Packit Service 5bcba8
    }
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_COLLECT_GLYPHS (this);
Packit Service 5bcba8
    Coverage::Iter iter;
Packit Service 5bcba8
    unsigned int count = substitute.len;
Packit Service 5bcba8
    for (iter.init (this+coverage); iter.more (); iter.next ())
Packit Service 5bcba8
    {
Packit Service 5bcba8
      if (unlikely (iter.get_coverage () >= count))
Packit Service 5bcba8
        break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
Packit Service 5bcba8
      c->input->add (iter.get_glyph ());
Packit Service 5bcba8
      c->output->add (substitute[iter.get_coverage ()]);
Packit Service 5bcba8
    }
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline const Coverage &get_coverage (void) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    return this+coverage;
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline bool would_apply (hb_would_apply_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_WOULD_APPLY (this);
Packit Service 5bcba8
    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline bool apply (hb_apply_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_APPLY (this);
Packit Service 5bcba8
    hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
Packit Service 5bcba8
    unsigned int index = (this+coverage).get_coverage (glyph_id);
Packit Service 5bcba8
    if (likely (index == NOT_COVERED)) return_trace (false);
Packit Service 5bcba8
Packit Service 5bcba8
    if (unlikely (index >= substitute.len)) return_trace (false);
Packit Service 5bcba8
Packit Service 5bcba8
    glyph_id = substitute[index];
Packit Service 5bcba8
    c->replace_glyph (glyph_id);
Packit Service 5bcba8
Packit Service 5bcba8
    return_trace (true);
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline bool serialize (hb_serialize_context_t *c,
Packit Service 5bcba8
			 Supplier<GlyphID> &glyphs,
Packit Service 5bcba8
			 Supplier<GlyphID> &substitutes,
Packit Service 5bcba8
			 unsigned int num_glyphs)
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_SERIALIZE (this);
Packit Service 5bcba8
    if (unlikely (!c->extend_min (*this))) return_trace (false);
Packit Service 5bcba8
    if (unlikely (!substitute.serialize (c, substitutes, num_glyphs))) return_trace (false);
Packit Service 5bcba8
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
Packit Service 5bcba8
    return_trace (true);
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline bool sanitize (hb_sanitize_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_SANITIZE (this);
Packit Service 5bcba8
    return_trace (coverage.sanitize (c, this) && substitute.sanitize (c));
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  protected:
Packit Service 5bcba8
  USHORT	format;			/* Format identifier--format = 2 */
Packit Service 5bcba8
  OffsetTo<Coverage>
Packit Service 5bcba8
		coverage;		/* Offset to Coverage table--from
Packit Service 5bcba8
					 * beginning of Substitution table */
Packit Service 5bcba8
  ArrayOf<GlyphID>
Packit Service 5bcba8
		substitute;		/* Array of substitute
Packit Service 5bcba8
					 * GlyphIDs--ordered by Coverage Index */
Packit Service 5bcba8
  public:
Packit Service 5bcba8
  DEFINE_SIZE_ARRAY (6, substitute);
Packit Service 5bcba8
};
Packit Service 5bcba8
Packit Service 5bcba8
struct SingleSubst
Packit Service 5bcba8
{
Packit Service 5bcba8
  inline bool serialize (hb_serialize_context_t *c,
Packit Service 5bcba8
			 Supplier<GlyphID> &glyphs,
Packit Service 5bcba8
			 Supplier<GlyphID> &substitutes,
Packit Service 5bcba8
			 unsigned int num_glyphs)
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_SERIALIZE (this);
Packit Service 5bcba8
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
Packit Service 5bcba8
    unsigned int format = 2;
Packit Service 5bcba8
    int delta = 0;
Packit Service 5bcba8
    if (num_glyphs) {
Packit Service 5bcba8
      format = 1;
Packit Service 5bcba8
      /* TODO(serialize) check for wrap-around */
Packit Service 5bcba8
      delta = substitutes[0] - glyphs[0];
Packit Service 5bcba8
      for (unsigned int i = 1; i < num_glyphs; i++)
Packit Service 5bcba8
	if (delta != substitutes[i] - glyphs[i]) {
Packit Service 5bcba8
	  format = 2;
Packit Service 5bcba8
	  break;
Packit Service 5bcba8
	}
Packit Service 5bcba8
    }
Packit Service 5bcba8
    u.format.set (format);
Packit Service 5bcba8
    switch (u.format) {
Packit Service 5bcba8
    case 1: return_trace (u.format1.serialize (c, glyphs, num_glyphs, delta));
Packit Service 5bcba8
    case 2: return_trace (u.format2.serialize (c, glyphs, substitutes, num_glyphs));
Packit Service 5bcba8
    default:return_trace (false);
Packit Service 5bcba8
    }
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  template <typename context_t>
Packit Service 5bcba8
  inline typename context_t::return_t dispatch (context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_DISPATCH (this, u.format);
Packit Service 5bcba8
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
Packit Service 5bcba8
    switch (u.format) {
Packit Service 5bcba8
    case 1: return_trace (c->dispatch (u.format1));
Packit Service 5bcba8
    case 2: return_trace (c->dispatch (u.format2));
Packit Service 5bcba8
    default:return_trace (c->default_return_value ());
Packit Service 5bcba8
    }
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  protected:
Packit Service 5bcba8
  union {
Packit Service 5bcba8
  USHORT		format;		/* Format identifier */
Packit Service 5bcba8
  SingleSubstFormat1	format1;
Packit Service 5bcba8
  SingleSubstFormat2	format2;
Packit Service 5bcba8
  } u;
Packit Service 5bcba8
};
Packit Service 5bcba8
Packit Service 5bcba8
Packit Service 5bcba8
struct Sequence
Packit Service 5bcba8
{
Packit Service 5bcba8
  inline void closure (hb_closure_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_CLOSURE (this);
Packit Service 5bcba8
    unsigned int count = substitute.len;
Packit Service 5bcba8
    for (unsigned int i = 0; i < count; i++)
Packit Service 5bcba8
      c->glyphs->add (substitute[i]);
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_COLLECT_GLYPHS (this);
Packit Service 5bcba8
    unsigned int count = substitute.len;
Packit Service 5bcba8
    for (unsigned int i = 0; i < count; i++)
Packit Service 5bcba8
      c->output->add (substitute[i]);
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline bool apply (hb_apply_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_APPLY (this);
Packit Service 5bcba8
    unsigned int count = substitute.len;
Packit Service 5bcba8
Packit Service 5bcba8
    /* Special-case to make it in-place and not consider this
Packit Service 5bcba8
     * as a "multiplied" substitution. */
Packit Service 5bcba8
    if (unlikely (count == 1))
Packit Service 5bcba8
    {
Packit Service 5bcba8
      c->replace_glyph (substitute.array[0]);
Packit Service 5bcba8
      return_trace (true);
Packit Service 5bcba8
    }
Packit Service 5bcba8
    /* Spec disallows this, but Uniscribe allows it.
Packit Service 5bcba8
     * https://github.com/behdad/harfbuzz/issues/253 */
Packit Service 5bcba8
    else if (unlikely (count == 0))
Packit Service 5bcba8
    {
Packit Service 5bcba8
      c->buffer->delete_glyph ();
Packit Service 5bcba8
      return_trace (true);
Packit Service 5bcba8
    }
Packit Service 5bcba8
Packit Service 5bcba8
    unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ?
Packit Service 5bcba8
			 HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0;
Packit Service 5bcba8
Packit Service 5bcba8
    for (unsigned int i = 0; i < count; i++) {
Packit Service 5bcba8
      _hb_glyph_info_set_lig_props_for_component (&c->buffer->cur(), i);
Packit Service 5bcba8
      c->output_glyph_for_component (substitute.array[i], klass);
Packit Service 5bcba8
    }
Packit Service 5bcba8
    c->buffer->skip_glyph ();
Packit Service 5bcba8
Packit Service 5bcba8
    return_trace (true);
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline bool serialize (hb_serialize_context_t *c,
Packit Service 5bcba8
			 Supplier<GlyphID> &glyphs,
Packit Service 5bcba8
			 unsigned int num_glyphs)
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_SERIALIZE (this);
Packit Service 5bcba8
    if (unlikely (!c->extend_min (*this))) return_trace (false);
Packit Service 5bcba8
    if (unlikely (!substitute.serialize (c, glyphs, num_glyphs))) return_trace (false);
Packit Service 5bcba8
    return_trace (true);
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline bool sanitize (hb_sanitize_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_SANITIZE (this);
Packit Service 5bcba8
    return_trace (substitute.sanitize (c));
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  protected:
Packit Service 5bcba8
  ArrayOf<GlyphID>
Packit Service 5bcba8
		substitute;		/* String of GlyphIDs to substitute */
Packit Service 5bcba8
  public:
Packit Service 5bcba8
  DEFINE_SIZE_ARRAY (2, substitute);
Packit Service 5bcba8
};
Packit Service 5bcba8
Packit Service 5bcba8
struct MultipleSubstFormat1
Packit Service 5bcba8
{
Packit Service 5bcba8
  inline void closure (hb_closure_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_CLOSURE (this);
Packit Service 5bcba8
    Coverage::Iter iter;
Packit Service 5bcba8
    unsigned int count = sequence.len;
Packit Service 5bcba8
    for (iter.init (this+coverage); iter.more (); iter.next ())
Packit Service 5bcba8
    {
Packit Service 5bcba8
      if (unlikely (iter.get_coverage () >= count))
Packit Service 5bcba8
        break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
Packit Service 5bcba8
      if (c->glyphs->has (iter.get_glyph ()))
Packit Service 5bcba8
	(this+sequence[iter.get_coverage ()]).closure (c);
Packit Service 5bcba8
    }
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_COLLECT_GLYPHS (this);
Packit Service 5bcba8
    (this+coverage).add_coverage (c->input);
Packit Service 5bcba8
    unsigned int count = sequence.len;
Packit Service 5bcba8
    for (unsigned int i = 0; i < count; i++)
Packit Service 5bcba8
	(this+sequence[i]).collect_glyphs (c);
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline const Coverage &get_coverage (void) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    return this+coverage;
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline bool would_apply (hb_would_apply_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_WOULD_APPLY (this);
Packit Service 5bcba8
    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline bool apply (hb_apply_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_APPLY (this);
Packit Service 5bcba8
Packit Service 5bcba8
    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
Packit Service 5bcba8
    if (likely (index == NOT_COVERED)) return_trace (false);
Packit Service 5bcba8
Packit Service 5bcba8
    return_trace ((this+sequence[index]).apply (c));
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline bool serialize (hb_serialize_context_t *c,
Packit Service 5bcba8
			 Supplier<GlyphID> &glyphs,
Packit Service 5bcba8
			 Supplier<unsigned int> &substitute_len_list,
Packit Service 5bcba8
			 unsigned int num_glyphs,
Packit Service 5bcba8
			 Supplier<GlyphID> &substitute_glyphs_list)
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_SERIALIZE (this);
Packit Service 5bcba8
    if (unlikely (!c->extend_min (*this))) return_trace (false);
Packit Service 5bcba8
    if (unlikely (!sequence.serialize (c, num_glyphs))) return_trace (false);
Packit Service 5bcba8
    for (unsigned int i = 0; i < num_glyphs; i++)
Packit Service 5bcba8
      if (unlikely (!sequence[i].serialize (c, this).serialize (c,
Packit Service 5bcba8
								substitute_glyphs_list,
Packit Service 5bcba8
								substitute_len_list[i]))) return_trace (false);
Packit Service 5bcba8
    substitute_len_list.advance (num_glyphs);
Packit Service 5bcba8
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
Packit Service 5bcba8
    return_trace (true);
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline bool sanitize (hb_sanitize_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_SANITIZE (this);
Packit Service 5bcba8
    return_trace (coverage.sanitize (c, this) && sequence.sanitize (c, this));
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  protected:
Packit Service 5bcba8
  USHORT	format;			/* Format identifier--format = 1 */
Packit Service 5bcba8
  OffsetTo<Coverage>
Packit Service 5bcba8
		coverage;		/* Offset to Coverage table--from
Packit Service 5bcba8
					 * beginning of Substitution table */
Packit Service 5bcba8
  OffsetArrayOf<Sequence>
Packit Service 5bcba8
		sequence;		/* Array of Sequence tables
Packit Service 5bcba8
					 * ordered by Coverage Index */
Packit Service 5bcba8
  public:
Packit Service 5bcba8
  DEFINE_SIZE_ARRAY (6, sequence);
Packit Service 5bcba8
};
Packit Service 5bcba8
Packit Service 5bcba8
struct MultipleSubst
Packit Service 5bcba8
{
Packit Service 5bcba8
  inline bool serialize (hb_serialize_context_t *c,
Packit Service 5bcba8
			 Supplier<GlyphID> &glyphs,
Packit Service 5bcba8
			 Supplier<unsigned int> &substitute_len_list,
Packit Service 5bcba8
			 unsigned int num_glyphs,
Packit Service 5bcba8
			 Supplier<GlyphID> &substitute_glyphs_list)
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_SERIALIZE (this);
Packit Service 5bcba8
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
Packit Service 5bcba8
    unsigned int format = 1;
Packit Service 5bcba8
    u.format.set (format);
Packit Service 5bcba8
    switch (u.format) {
Packit Service 5bcba8
    case 1: return_trace (u.format1.serialize (c, glyphs, substitute_len_list, num_glyphs, substitute_glyphs_list));
Packit Service 5bcba8
    default:return_trace (false);
Packit Service 5bcba8
    }
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  template <typename context_t>
Packit Service 5bcba8
  inline typename context_t::return_t dispatch (context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_DISPATCH (this, u.format);
Packit Service 5bcba8
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
Packit Service 5bcba8
    switch (u.format) {
Packit Service 5bcba8
    case 1: return_trace (c->dispatch (u.format1));
Packit Service 5bcba8
    default:return_trace (c->default_return_value ());
Packit Service 5bcba8
    }
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  protected:
Packit Service 5bcba8
  union {
Packit Service 5bcba8
  USHORT		format;		/* Format identifier */
Packit Service 5bcba8
  MultipleSubstFormat1	format1;
Packit Service 5bcba8
  } u;
Packit Service 5bcba8
};
Packit Service 5bcba8
Packit Service 5bcba8
Packit Service 5bcba8
typedef ArrayOf<GlyphID> AlternateSet;	/* Array of alternate GlyphIDs--in
Packit Service 5bcba8
					 * arbitrary order */
Packit Service 5bcba8
Packit Service 5bcba8
struct AlternateSubstFormat1
Packit Service 5bcba8
{
Packit Service 5bcba8
  inline void closure (hb_closure_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_CLOSURE (this);
Packit Service 5bcba8
    Coverage::Iter iter;
Packit Service 5bcba8
    unsigned int count = alternateSet.len;
Packit Service 5bcba8
    for (iter.init (this+coverage); iter.more (); iter.next ())
Packit Service 5bcba8
    {
Packit Service 5bcba8
      if (unlikely (iter.get_coverage () >= count))
Packit Service 5bcba8
        break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
Packit Service 5bcba8
      if (c->glyphs->has (iter.get_glyph ())) {
Packit Service 5bcba8
	const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
Packit Service 5bcba8
	unsigned int count = alt_set.len;
Packit Service 5bcba8
	for (unsigned int i = 0; i < count; i++)
Packit Service 5bcba8
	  c->glyphs->add (alt_set[i]);
Packit Service 5bcba8
      }
Packit Service 5bcba8
    }
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_COLLECT_GLYPHS (this);
Packit Service 5bcba8
    Coverage::Iter iter;
Packit Service 5bcba8
    unsigned int count = alternateSet.len;
Packit Service 5bcba8
    for (iter.init (this+coverage); iter.more (); iter.next ())
Packit Service 5bcba8
    {
Packit Service 5bcba8
      if (unlikely (iter.get_coverage () >= count))
Packit Service 5bcba8
        break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
Packit Service 5bcba8
      c->input->add (iter.get_glyph ());
Packit Service 5bcba8
      const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
Packit Service 5bcba8
      unsigned int count = alt_set.len;
Packit Service 5bcba8
      for (unsigned int i = 0; i < count; i++)
Packit Service 5bcba8
	c->output->add (alt_set[i]);
Packit Service 5bcba8
    }
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline const Coverage &get_coverage (void) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    return this+coverage;
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline bool would_apply (hb_would_apply_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_WOULD_APPLY (this);
Packit Service 5bcba8
    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline bool apply (hb_apply_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_APPLY (this);
Packit Service 5bcba8
    hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
Packit Service 5bcba8
Packit Service 5bcba8
    unsigned int index = (this+coverage).get_coverage (glyph_id);
Packit Service 5bcba8
    if (likely (index == NOT_COVERED)) return_trace (false);
Packit Service 5bcba8
Packit Service 5bcba8
    const AlternateSet &alt_set = this+alternateSet[index];
Packit Service 5bcba8
Packit Service 5bcba8
    if (unlikely (!alt_set.len)) return_trace (false);
Packit Service 5bcba8
Packit Service 5bcba8
    hb_mask_t glyph_mask = c->buffer->cur().mask;
Packit Service 5bcba8
    hb_mask_t lookup_mask = c->lookup_mask;
Packit Service 5bcba8
Packit Service 5bcba8
    /* Note: This breaks badly if two features enabled this lookup together. */
Packit Service 5bcba8
    unsigned int shift = _hb_ctz (lookup_mask);
Packit Service 5bcba8
    unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift);
Packit Service 5bcba8
Packit Service 5bcba8
    if (unlikely (alt_index > alt_set.len || alt_index == 0)) return_trace (false);
Packit Service 5bcba8
Packit Service 5bcba8
    glyph_id = alt_set[alt_index - 1];
Packit Service 5bcba8
Packit Service 5bcba8
    c->replace_glyph (glyph_id);
Packit Service 5bcba8
Packit Service 5bcba8
    return_trace (true);
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline bool serialize (hb_serialize_context_t *c,
Packit Service 5bcba8
			 Supplier<GlyphID> &glyphs,
Packit Service 5bcba8
			 Supplier<unsigned int> &alternate_len_list,
Packit Service 5bcba8
			 unsigned int num_glyphs,
Packit Service 5bcba8
			 Supplier<GlyphID> &alternate_glyphs_list)
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_SERIALIZE (this);
Packit Service 5bcba8
    if (unlikely (!c->extend_min (*this))) return_trace (false);
Packit Service 5bcba8
    if (unlikely (!alternateSet.serialize (c, num_glyphs))) return_trace (false);
Packit Service 5bcba8
    for (unsigned int i = 0; i < num_glyphs; i++)
Packit Service 5bcba8
      if (unlikely (!alternateSet[i].serialize (c, this).serialize (c,
Packit Service 5bcba8
								    alternate_glyphs_list,
Packit Service 5bcba8
								    alternate_len_list[i]))) return_trace (false);
Packit Service 5bcba8
    alternate_len_list.advance (num_glyphs);
Packit Service 5bcba8
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
Packit Service 5bcba8
    return_trace (true);
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline bool sanitize (hb_sanitize_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_SANITIZE (this);
Packit Service 5bcba8
    return_trace (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  protected:
Packit Service 5bcba8
  USHORT	format;			/* Format identifier--format = 1 */
Packit Service 5bcba8
  OffsetTo<Coverage>
Packit Service 5bcba8
		coverage;		/* Offset to Coverage table--from
Packit Service 5bcba8
					 * beginning of Substitution table */
Packit Service 5bcba8
  OffsetArrayOf<AlternateSet>
Packit Service 5bcba8
		alternateSet;		/* Array of AlternateSet tables
Packit Service 5bcba8
					 * ordered by Coverage Index */
Packit Service 5bcba8
  public:
Packit Service 5bcba8
  DEFINE_SIZE_ARRAY (6, alternateSet);
Packit Service 5bcba8
};
Packit Service 5bcba8
Packit Service 5bcba8
struct AlternateSubst
Packit Service 5bcba8
{
Packit Service 5bcba8
  inline bool serialize (hb_serialize_context_t *c,
Packit Service 5bcba8
			 Supplier<GlyphID> &glyphs,
Packit Service 5bcba8
			 Supplier<unsigned int> &alternate_len_list,
Packit Service 5bcba8
			 unsigned int num_glyphs,
Packit Service 5bcba8
			 Supplier<GlyphID> &alternate_glyphs_list)
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_SERIALIZE (this);
Packit Service 5bcba8
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
Packit Service 5bcba8
    unsigned int format = 1;
Packit Service 5bcba8
    u.format.set (format);
Packit Service 5bcba8
    switch (u.format) {
Packit Service 5bcba8
    case 1: return_trace (u.format1.serialize (c, glyphs, alternate_len_list, num_glyphs, alternate_glyphs_list));
Packit Service 5bcba8
    default:return_trace (false);
Packit Service 5bcba8
    }
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  template <typename context_t>
Packit Service 5bcba8
  inline typename context_t::return_t dispatch (context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_DISPATCH (this, u.format);
Packit Service 5bcba8
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
Packit Service 5bcba8
    switch (u.format) {
Packit Service 5bcba8
    case 1: return_trace (c->dispatch (u.format1));
Packit Service 5bcba8
    default:return_trace (c->default_return_value ());
Packit Service 5bcba8
    }
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  protected:
Packit Service 5bcba8
  union {
Packit Service 5bcba8
  USHORT		format;		/* Format identifier */
Packit Service 5bcba8
  AlternateSubstFormat1	format1;
Packit Service 5bcba8
  } u;
Packit Service 5bcba8
};
Packit Service 5bcba8
Packit Service 5bcba8
Packit Service 5bcba8
struct Ligature
Packit Service 5bcba8
{
Packit Service 5bcba8
  inline void closure (hb_closure_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_CLOSURE (this);
Packit Service 5bcba8
    unsigned int count = component.len;
Packit Service 5bcba8
    for (unsigned int i = 1; i < count; i++)
Packit Service 5bcba8
      if (!c->glyphs->has (component[i]))
Packit Service 5bcba8
        return;
Packit Service 5bcba8
    c->glyphs->add (ligGlyph);
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_COLLECT_GLYPHS (this);
Packit Service 5bcba8
    unsigned int count = component.len;
Packit Service 5bcba8
    for (unsigned int i = 1; i < count; i++)
Packit Service 5bcba8
      c->input->add (component[i]);
Packit Service 5bcba8
    c->output->add (ligGlyph);
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline bool would_apply (hb_would_apply_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_WOULD_APPLY (this);
Packit Service 5bcba8
    if (c->len != component.len)
Packit Service 5bcba8
      return_trace (false);
Packit Service 5bcba8
Packit Service 5bcba8
    for (unsigned int i = 1; i < c->len; i++)
Packit Service 5bcba8
      if (likely (c->glyphs[i] != component[i]))
Packit Service 5bcba8
	return_trace (false);
Packit Service 5bcba8
Packit Service 5bcba8
    return_trace (true);
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline bool apply (hb_apply_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_APPLY (this);
Packit Service 5bcba8
    unsigned int count = component.len;
Packit Service 5bcba8
Packit Service 5bcba8
    if (unlikely (!count)) return_trace (false);
Packit Service 5bcba8
Packit Service 5bcba8
    /* Special-case to make it in-place and not consider this
Packit Service 5bcba8
     * as a "ligated" substitution. */
Packit Service 5bcba8
    if (unlikely (count == 1))
Packit Service 5bcba8
    {
Packit Service 5bcba8
      c->replace_glyph (ligGlyph);
Packit Service 5bcba8
      return_trace (true);
Packit Service 5bcba8
    }
Packit Service 5bcba8
Packit Service 5bcba8
    bool is_mark_ligature = false;
Packit Service 5bcba8
    unsigned int total_component_count = 0;
Packit Service 5bcba8
Packit Service 5bcba8
    unsigned int match_length = 0;
Packit Service 5bcba8
    unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
Packit Service 5bcba8
Packit Service 5bcba8
    if (likely (!match_input (c, count,
Packit Service 5bcba8
			      &component[1],
Packit Service 5bcba8
			      match_glyph,
Packit Service 5bcba8
			      NULL,
Packit Service 5bcba8
			      &match_length,
Packit Service 5bcba8
			      match_positions,
Packit Service 5bcba8
			      &is_mark_ligature,
Packit Service 5bcba8
			      &total_component_count)))
Packit Service 5bcba8
      return_trace (false);
Packit Service 5bcba8
Packit Service 5bcba8
    ligate_input (c,
Packit Service 5bcba8
		  count,
Packit Service 5bcba8
		  match_positions,
Packit Service 5bcba8
		  match_length,
Packit Service 5bcba8
		  ligGlyph,
Packit Service 5bcba8
		  is_mark_ligature,
Packit Service 5bcba8
		  total_component_count);
Packit Service 5bcba8
Packit Service 5bcba8
    return_trace (true);
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline bool serialize (hb_serialize_context_t *c,
Packit Service 5bcba8
			 GlyphID ligature,
Packit Service 5bcba8
			 Supplier<GlyphID> &components, /* Starting from second */
Packit Service 5bcba8
			 unsigned int num_components /* Including first component */)
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_SERIALIZE (this);
Packit Service 5bcba8
    if (unlikely (!c->extend_min (*this))) return_trace (false);
Packit Service 5bcba8
    ligGlyph = ligature;
Packit Service 5bcba8
    if (unlikely (!component.serialize (c, components, num_components))) return_trace (false);
Packit Service 5bcba8
    return_trace (true);
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  public:
Packit Service 5bcba8
  inline bool sanitize (hb_sanitize_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_SANITIZE (this);
Packit Service 5bcba8
    return_trace (ligGlyph.sanitize (c) && component.sanitize (c));
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  protected:
Packit Service 5bcba8
  GlyphID	ligGlyph;		/* GlyphID of ligature to substitute */
Packit Service 5bcba8
  HeadlessArrayOf<GlyphID>
Packit Service 5bcba8
		component;		/* Array of component GlyphIDs--start
Packit Service 5bcba8
					 * with the second  component--ordered
Packit Service 5bcba8
					 * in writing direction */
Packit Service 5bcba8
  public:
Packit Service 5bcba8
  DEFINE_SIZE_ARRAY (4, component);
Packit Service 5bcba8
};
Packit Service 5bcba8
Packit Service 5bcba8
struct LigatureSet
Packit Service 5bcba8
{
Packit Service 5bcba8
  inline void closure (hb_closure_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_CLOSURE (this);
Packit Service 5bcba8
    unsigned int num_ligs = ligature.len;
Packit Service 5bcba8
    for (unsigned int i = 0; i < num_ligs; i++)
Packit Service 5bcba8
      (this+ligature[i]).closure (c);
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_COLLECT_GLYPHS (this);
Packit Service 5bcba8
    unsigned int num_ligs = ligature.len;
Packit Service 5bcba8
    for (unsigned int i = 0; i < num_ligs; i++)
Packit Service 5bcba8
      (this+ligature[i]).collect_glyphs (c);
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline bool would_apply (hb_would_apply_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_WOULD_APPLY (this);
Packit Service 5bcba8
    unsigned int num_ligs = ligature.len;
Packit Service 5bcba8
    for (unsigned int i = 0; i < num_ligs; i++)
Packit Service 5bcba8
    {
Packit Service 5bcba8
      const Ligature &lig = this+ligature[i];
Packit Service 5bcba8
      if (lig.would_apply (c))
Packit Service 5bcba8
        return_trace (true);
Packit Service 5bcba8
    }
Packit Service 5bcba8
    return_trace (false);
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline bool apply (hb_apply_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_APPLY (this);
Packit Service 5bcba8
    unsigned int num_ligs = ligature.len;
Packit Service 5bcba8
    for (unsigned int i = 0; i < num_ligs; i++)
Packit Service 5bcba8
    {
Packit Service 5bcba8
      const Ligature &lig = this+ligature[i];
Packit Service 5bcba8
      if (lig.apply (c)) return_trace (true);
Packit Service 5bcba8
    }
Packit Service 5bcba8
Packit Service 5bcba8
    return_trace (false);
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline bool serialize (hb_serialize_context_t *c,
Packit Service 5bcba8
			 Supplier<GlyphID> &ligatures,
Packit Service 5bcba8
			 Supplier<unsigned int> &component_count_list,
Packit Service 5bcba8
			 unsigned int num_ligatures,
Packit Service 5bcba8
			 Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_SERIALIZE (this);
Packit Service 5bcba8
    if (unlikely (!c->extend_min (*this))) return_trace (false);
Packit Service 5bcba8
    if (unlikely (!ligature.serialize (c, num_ligatures))) return_trace (false);
Packit Service 5bcba8
    for (unsigned int i = 0; i < num_ligatures; i++)
Packit Service 5bcba8
      if (unlikely (!ligature[i].serialize (c, this).serialize (c,
Packit Service 5bcba8
								ligatures[i],
Packit Service 5bcba8
								component_list,
Packit Service 5bcba8
								component_count_list[i]))) return_trace (false);
Packit Service 5bcba8
    ligatures.advance (num_ligatures);
Packit Service 5bcba8
    component_count_list.advance (num_ligatures);
Packit Service 5bcba8
    return_trace (true);
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline bool sanitize (hb_sanitize_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_SANITIZE (this);
Packit Service 5bcba8
    return_trace (ligature.sanitize (c, this));
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  protected:
Packit Service 5bcba8
  OffsetArrayOf<Ligature>
Packit Service 5bcba8
		ligature;		/* Array LigatureSet tables
Packit Service 5bcba8
					 * ordered by preference */
Packit Service 5bcba8
  public:
Packit Service 5bcba8
  DEFINE_SIZE_ARRAY (2, ligature);
Packit Service 5bcba8
};
Packit Service 5bcba8
Packit Service 5bcba8
struct LigatureSubstFormat1
Packit Service 5bcba8
{
Packit Service 5bcba8
  inline void closure (hb_closure_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_CLOSURE (this);
Packit Service 5bcba8
    Coverage::Iter iter;
Packit Service 5bcba8
    unsigned int count = ligatureSet.len;
Packit Service 5bcba8
    for (iter.init (this+coverage); iter.more (); iter.next ())
Packit Service 5bcba8
    {
Packit Service 5bcba8
      if (unlikely (iter.get_coverage () >= count))
Packit Service 5bcba8
        break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
Packit Service 5bcba8
      if (c->glyphs->has (iter.get_glyph ()))
Packit Service 5bcba8
	(this+ligatureSet[iter.get_coverage ()]).closure (c);
Packit Service 5bcba8
    }
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_COLLECT_GLYPHS (this);
Packit Service 5bcba8
    Coverage::Iter iter;
Packit Service 5bcba8
    unsigned int count = ligatureSet.len;
Packit Service 5bcba8
    for (iter.init (this+coverage); iter.more (); iter.next ())
Packit Service 5bcba8
    {
Packit Service 5bcba8
      if (unlikely (iter.get_coverage () >= count))
Packit Service 5bcba8
        break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
Packit Service 5bcba8
      c->input->add (iter.get_glyph ());
Packit Service 5bcba8
      (this+ligatureSet[iter.get_coverage ()]).collect_glyphs (c);
Packit Service 5bcba8
    }
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline const Coverage &get_coverage (void) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    return this+coverage;
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline bool would_apply (hb_would_apply_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_WOULD_APPLY (this);
Packit Service 5bcba8
    unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
Packit Service 5bcba8
    if (likely (index == NOT_COVERED)) return_trace (false);
Packit Service 5bcba8
Packit Service 5bcba8
    const LigatureSet &lig_set = this+ligatureSet[index];
Packit Service 5bcba8
    return_trace (lig_set.would_apply (c));
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline bool apply (hb_apply_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_APPLY (this);
Packit Service 5bcba8
    hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
Packit Service 5bcba8
Packit Service 5bcba8
    unsigned int index = (this+coverage).get_coverage (glyph_id);
Packit Service 5bcba8
    if (likely (index == NOT_COVERED)) return_trace (false);
Packit Service 5bcba8
Packit Service 5bcba8
    const LigatureSet &lig_set = this+ligatureSet[index];
Packit Service 5bcba8
    return_trace (lig_set.apply (c));
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline bool serialize (hb_serialize_context_t *c,
Packit Service 5bcba8
			 Supplier<GlyphID> &first_glyphs,
Packit Service 5bcba8
			 Supplier<unsigned int> &ligature_per_first_glyph_count_list,
Packit Service 5bcba8
			 unsigned int num_first_glyphs,
Packit Service 5bcba8
			 Supplier<GlyphID> &ligatures_list,
Packit Service 5bcba8
			 Supplier<unsigned int> &component_count_list,
Packit Service 5bcba8
			 Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_SERIALIZE (this);
Packit Service 5bcba8
    if (unlikely (!c->extend_min (*this))) return_trace (false);
Packit Service 5bcba8
    if (unlikely (!ligatureSet.serialize (c, num_first_glyphs))) return_trace (false);
Packit Service 5bcba8
    for (unsigned int i = 0; i < num_first_glyphs; i++)
Packit Service 5bcba8
      if (unlikely (!ligatureSet[i].serialize (c, this).serialize (c,
Packit Service 5bcba8
								   ligatures_list,
Packit Service 5bcba8
								   component_count_list,
Packit Service 5bcba8
								   ligature_per_first_glyph_count_list[i],
Packit Service 5bcba8
								   component_list))) return_trace (false);
Packit Service 5bcba8
    ligature_per_first_glyph_count_list.advance (num_first_glyphs);
Packit Service 5bcba8
    if (unlikely (!coverage.serialize (c, this).serialize (c, first_glyphs, num_first_glyphs))) return_trace (false);
Packit Service 5bcba8
    return_trace (true);
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline bool sanitize (hb_sanitize_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_SANITIZE (this);
Packit Service 5bcba8
    return_trace (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  protected:
Packit Service 5bcba8
  USHORT	format;			/* Format identifier--format = 1 */
Packit Service 5bcba8
  OffsetTo<Coverage>
Packit Service 5bcba8
		coverage;		/* Offset to Coverage table--from
Packit Service 5bcba8
					 * beginning of Substitution table */
Packit Service 5bcba8
  OffsetArrayOf<LigatureSet>
Packit Service 5bcba8
		ligatureSet;		/* Array LigatureSet tables
Packit Service 5bcba8
					 * ordered by Coverage Index */
Packit Service 5bcba8
  public:
Packit Service 5bcba8
  DEFINE_SIZE_ARRAY (6, ligatureSet);
Packit Service 5bcba8
};
Packit Service 5bcba8
Packit Service 5bcba8
struct LigatureSubst
Packit Service 5bcba8
{
Packit Service 5bcba8
  inline bool serialize (hb_serialize_context_t *c,
Packit Service 5bcba8
			 Supplier<GlyphID> &first_glyphs,
Packit Service 5bcba8
			 Supplier<unsigned int> &ligature_per_first_glyph_count_list,
Packit Service 5bcba8
			 unsigned int num_first_glyphs,
Packit Service 5bcba8
			 Supplier<GlyphID> &ligatures_list,
Packit Service 5bcba8
			 Supplier<unsigned int> &component_count_list,
Packit Service 5bcba8
			 Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_SERIALIZE (this);
Packit Service 5bcba8
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
Packit Service 5bcba8
    unsigned int format = 1;
Packit Service 5bcba8
    u.format.set (format);
Packit Service 5bcba8
    switch (u.format) {
Packit Service 5bcba8
    case 1: return_trace (u.format1.serialize (c,
Packit Service 5bcba8
					       first_glyphs,
Packit Service 5bcba8
					       ligature_per_first_glyph_count_list,
Packit Service 5bcba8
					       num_first_glyphs,
Packit Service 5bcba8
					       ligatures_list,
Packit Service 5bcba8
					       component_count_list,
Packit Service 5bcba8
					       component_list));
Packit Service 5bcba8
    default:return_trace (false);
Packit Service 5bcba8
    }
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  template <typename context_t>
Packit Service 5bcba8
  inline typename context_t::return_t dispatch (context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_DISPATCH (this, u.format);
Packit Service 5bcba8
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
Packit Service 5bcba8
    switch (u.format) {
Packit Service 5bcba8
    case 1: return_trace (c->dispatch (u.format1));
Packit Service 5bcba8
    default:return_trace (c->default_return_value ());
Packit Service 5bcba8
    }
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  protected:
Packit Service 5bcba8
  union {
Packit Service 5bcba8
  USHORT		format;		/* Format identifier */
Packit Service 5bcba8
  LigatureSubstFormat1	format1;
Packit Service 5bcba8
  } u;
Packit Service 5bcba8
};
Packit Service 5bcba8
Packit Service 5bcba8
Packit Service 5bcba8
struct ContextSubst : Context {};
Packit Service 5bcba8
Packit Service 5bcba8
struct ChainContextSubst : ChainContext {};
Packit Service 5bcba8
Packit Service 5bcba8
struct ExtensionSubst : Extension<ExtensionSubst>
Packit Service 5bcba8
{
Packit Service 5bcba8
  typedef struct SubstLookupSubTable LookupSubTable;
Packit Service 5bcba8
Packit Service 5bcba8
  inline bool is_reverse (void) const;
Packit Service 5bcba8
};
Packit Service 5bcba8
Packit Service 5bcba8
Packit Service 5bcba8
struct ReverseChainSingleSubstFormat1
Packit Service 5bcba8
{
Packit Service 5bcba8
  inline void closure (hb_closure_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_CLOSURE (this);
Packit Service 5bcba8
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
Packit Service 5bcba8
Packit Service 5bcba8
    unsigned int count;
Packit Service 5bcba8
Packit Service 5bcba8
    count = backtrack.len;
Packit Service 5bcba8
    for (unsigned int i = 0; i < count; i++)
Packit Service 5bcba8
      if (!(this+backtrack[i]).intersects (c->glyphs))
Packit Service 5bcba8
        return;
Packit Service 5bcba8
Packit Service 5bcba8
    count = lookahead.len;
Packit Service 5bcba8
    for (unsigned int i = 0; i < count; i++)
Packit Service 5bcba8
      if (!(this+lookahead[i]).intersects (c->glyphs))
Packit Service 5bcba8
        return;
Packit Service 5bcba8
Packit Service 5bcba8
    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
Packit Service 5bcba8
    Coverage::Iter iter;
Packit Service 5bcba8
    count = substitute.len;
Packit Service 5bcba8
    for (iter.init (this+coverage); iter.more (); iter.next ())
Packit Service 5bcba8
    {
Packit Service 5bcba8
      if (unlikely (iter.get_coverage () >= count))
Packit Service 5bcba8
        break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
Packit Service 5bcba8
      if (c->glyphs->has (iter.get_glyph ()))
Packit Service 5bcba8
	c->glyphs->add (substitute[iter.get_coverage ()]);
Packit Service 5bcba8
    }
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_COLLECT_GLYPHS (this);
Packit Service 5bcba8
Packit Service 5bcba8
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
Packit Service 5bcba8
Packit Service 5bcba8
    unsigned int count;
Packit Service 5bcba8
Packit Service 5bcba8
    (this+coverage).add_coverage (c->input);
Packit Service 5bcba8
Packit Service 5bcba8
    count = backtrack.len;
Packit Service 5bcba8
    for (unsigned int i = 0; i < count; i++)
Packit Service 5bcba8
      (this+backtrack[i]).add_coverage (c->before);
Packit Service 5bcba8
Packit Service 5bcba8
    count = lookahead.len;
Packit Service 5bcba8
    for (unsigned int i = 0; i < count; i++)
Packit Service 5bcba8
      (this+lookahead[i]).add_coverage (c->after);
Packit Service 5bcba8
Packit Service 5bcba8
    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
Packit Service 5bcba8
    count = substitute.len;
Packit Service 5bcba8
    for (unsigned int i = 0; i < count; i++)
Packit Service 5bcba8
      c->output->add (substitute[i]);
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline const Coverage &get_coverage (void) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    return this+coverage;
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline bool would_apply (hb_would_apply_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_WOULD_APPLY (this);
Packit Service 5bcba8
    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline bool apply (hb_apply_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_APPLY (this);
Packit Service 5bcba8
    if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL))
Packit Service 5bcba8
      return_trace (false); /* No chaining to this type */
Packit Service 5bcba8
Packit Service 5bcba8
    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
Packit Service 5bcba8
    if (likely (index == NOT_COVERED)) return_trace (false);
Packit Service 5bcba8
Packit Service 5bcba8
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
Packit Service 5bcba8
    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
Packit Service 5bcba8
Packit Service 5bcba8
    if (match_backtrack (c,
Packit Service 5bcba8
			 backtrack.len, (USHORT *) backtrack.array,
Packit Service 5bcba8
			 match_coverage, this) &&
Packit Service 5bcba8
        match_lookahead (c,
Packit Service 5bcba8
			 lookahead.len, (USHORT *) lookahead.array,
Packit Service 5bcba8
			 match_coverage, this,
Packit Service 5bcba8
			 1))
Packit Service 5bcba8
    {
Packit Service 5bcba8
      c->replace_glyph_inplace (substitute[index]);
Packit Service 5bcba8
      /* Note: We DON'T decrease buffer->idx.  The main loop does it
Packit Service 5bcba8
       * for us.  This is useful for preventing surprises if someone
Packit Service 5bcba8
       * calls us through a Context lookup. */
Packit Service 5bcba8
      return_trace (true);
Packit Service 5bcba8
    }
Packit Service 5bcba8
Packit Service 5bcba8
    return_trace (false);
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline bool sanitize (hb_sanitize_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_SANITIZE (this);
Packit Service 5bcba8
    if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
Packit Service 5bcba8
      return_trace (false);
Packit Service 5bcba8
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
Packit Service 5bcba8
    if (!lookahead.sanitize (c, this))
Packit Service 5bcba8
      return_trace (false);
Packit Service 5bcba8
    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
Packit Service 5bcba8
    return_trace (substitute.sanitize (c));
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  protected:
Packit Service 5bcba8
  USHORT	format;			/* Format identifier--format = 1 */
Packit Service 5bcba8
  OffsetTo<Coverage>
Packit Service 5bcba8
		coverage;		/* Offset to Coverage table--from
Packit Service 5bcba8
					 * beginning of table */
Packit Service 5bcba8
  OffsetArrayOf<Coverage>
Packit Service 5bcba8
		backtrack;		/* Array of coverage tables
Packit Service 5bcba8
					 * in backtracking sequence, in  glyph
Packit Service 5bcba8
					 * sequence order */
Packit Service 5bcba8
  OffsetArrayOf<Coverage>
Packit Service 5bcba8
		lookaheadX;		/* Array of coverage tables
Packit Service 5bcba8
					 * in lookahead sequence, in glyph
Packit Service 5bcba8
					 * sequence order */
Packit Service 5bcba8
  ArrayOf<GlyphID>
Packit Service 5bcba8
		substituteX;		/* Array of substitute
Packit Service 5bcba8
					 * GlyphIDs--ordered by Coverage Index */
Packit Service 5bcba8
  public:
Packit Service 5bcba8
  DEFINE_SIZE_MIN (10);
Packit Service 5bcba8
};
Packit Service 5bcba8
Packit Service 5bcba8
struct ReverseChainSingleSubst
Packit Service 5bcba8
{
Packit Service 5bcba8
  template <typename context_t>
Packit Service 5bcba8
  inline typename context_t::return_t dispatch (context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_DISPATCH (this, u.format);
Packit Service 5bcba8
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
Packit Service 5bcba8
    switch (u.format) {
Packit Service 5bcba8
    case 1: return_trace (c->dispatch (u.format1));
Packit Service 5bcba8
    default:return_trace (c->default_return_value ());
Packit Service 5bcba8
    }
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  protected:
Packit Service 5bcba8
  union {
Packit Service 5bcba8
  USHORT				format;		/* Format identifier */
Packit Service 5bcba8
  ReverseChainSingleSubstFormat1	format1;
Packit Service 5bcba8
  } u;
Packit Service 5bcba8
};
Packit Service 5bcba8
Packit Service 5bcba8
Packit Service 5bcba8
Packit Service 5bcba8
/*
Packit Service 5bcba8
 * SubstLookup
Packit Service 5bcba8
 */
Packit Service 5bcba8
Packit Service 5bcba8
struct SubstLookupSubTable
Packit Service 5bcba8
{
Packit Service 5bcba8
  friend struct SubstLookup;
Packit Service 5bcba8
Packit Service 5bcba8
  enum Type {
Packit Service 5bcba8
    Single		= 1,
Packit Service 5bcba8
    Multiple		= 2,
Packit Service 5bcba8
    Alternate		= 3,
Packit Service 5bcba8
    Ligature		= 4,
Packit Service 5bcba8
    Context		= 5,
Packit Service 5bcba8
    ChainContext	= 6,
Packit Service 5bcba8
    Extension		= 7,
Packit Service 5bcba8
    ReverseChainSingle	= 8
Packit Service 5bcba8
  };
Packit Service 5bcba8
Packit Service 5bcba8
  template <typename context_t>
Packit Service 5bcba8
  inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_DISPATCH (this, lookup_type);
Packit Service 5bcba8
    if (unlikely (!c->may_dispatch (this, &u.sub_format))) return_trace (c->no_dispatch_return_value ());
Packit Service 5bcba8
    switch (lookup_type) {
Packit Service 5bcba8
    case Single:		return_trace (u.single.dispatch (c));
Packit Service 5bcba8
    case Multiple:		return_trace (u.multiple.dispatch (c));
Packit Service 5bcba8
    case Alternate:		return_trace (u.alternate.dispatch (c));
Packit Service 5bcba8
    case Ligature:		return_trace (u.ligature.dispatch (c));
Packit Service 5bcba8
    case Context:		return_trace (u.context.dispatch (c));
Packit Service 5bcba8
    case ChainContext:		return_trace (u.chainContext.dispatch (c));
Packit Service 5bcba8
    case Extension:		return_trace (u.extension.dispatch (c));
Packit Service 5bcba8
    case ReverseChainSingle:	return_trace (u.reverseChainContextSingle.dispatch (c));
Packit Service 5bcba8
    default:			return_trace (c->default_return_value ());
Packit Service 5bcba8
    }
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  protected:
Packit Service 5bcba8
  union {
Packit Service 5bcba8
  USHORT			sub_format;
Packit Service 5bcba8
  SingleSubst			single;
Packit Service 5bcba8
  MultipleSubst			multiple;
Packit Service 5bcba8
  AlternateSubst		alternate;
Packit Service 5bcba8
  LigatureSubst			ligature;
Packit Service 5bcba8
  ContextSubst			context;
Packit Service 5bcba8
  ChainContextSubst		chainContext;
Packit Service 5bcba8
  ExtensionSubst		extension;
Packit Service 5bcba8
  ReverseChainSingleSubst	reverseChainContextSingle;
Packit Service 5bcba8
  } u;
Packit Service 5bcba8
  public:
Packit Service 5bcba8
  DEFINE_SIZE_UNION (2, sub_format);
Packit Service 5bcba8
};
Packit Service 5bcba8
Packit Service 5bcba8
Packit Service 5bcba8
struct SubstLookup : Lookup
Packit Service 5bcba8
{
Packit Service 5bcba8
  inline const SubstLookupSubTable& get_subtable (unsigned int i) const
Packit Service 5bcba8
  { return Lookup::get_subtable<SubstLookupSubTable> (i); }
Packit Service 5bcba8
Packit Service 5bcba8
  inline static bool lookup_type_is_reverse (unsigned int lookup_type)
Packit Service 5bcba8
  { return lookup_type == SubstLookupSubTable::ReverseChainSingle; }
Packit Service 5bcba8
Packit Service 5bcba8
  inline bool is_reverse (void) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    unsigned int type = get_type ();
Packit Service 5bcba8
    if (unlikely (type == SubstLookupSubTable::Extension))
Packit Service 5bcba8
      return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
Packit Service 5bcba8
    return lookup_type_is_reverse (type);
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline bool apply (hb_apply_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_APPLY (this);
Packit Service 5bcba8
    return_trace (dispatch (c));
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline hb_closure_context_t::return_t closure (hb_closure_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_CLOSURE (this);
Packit Service 5bcba8
    c->set_recurse_func (dispatch_recurse_func<hb_closure_context_t>);
Packit Service 5bcba8
    return_trace (dispatch (c));
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_COLLECT_GLYPHS (this);
Packit Service 5bcba8
    c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
Packit Service 5bcba8
    return_trace (dispatch (c));
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  template <typename set_t>
Packit Service 5bcba8
  inline void add_coverage (set_t *glyphs) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    hb_add_coverage_context_t<set_t> c (glyphs);
Packit Service 5bcba8
    dispatch (&c);
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline bool would_apply (hb_would_apply_context_t *c,
Packit Service 5bcba8
			   const hb_ot_layout_lookup_accelerator_t *accel) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_WOULD_APPLY (this);
Packit Service 5bcba8
    if (unlikely (!c->len))  return_trace (false);
Packit Service 5bcba8
    if (!accel->may_have (c->glyphs[0]))  return_trace (false);
Packit Service 5bcba8
      return_trace (dispatch (c));
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);
Packit Service 5bcba8
Packit Service 5bcba8
  inline SubstLookupSubTable& serialize_subtable (hb_serialize_context_t *c,
Packit Service 5bcba8
						  unsigned int i)
Packit Service 5bcba8
  { return get_subtables<SubstLookupSubTable> ()[i].serialize (c, this); }
Packit Service 5bcba8
Packit Service 5bcba8
  inline bool serialize_single (hb_serialize_context_t *c,
Packit Service 5bcba8
				uint32_t lookup_props,
Packit Service 5bcba8
			        Supplier<GlyphID> &glyphs,
Packit Service 5bcba8
			        Supplier<GlyphID> &substitutes,
Packit Service 5bcba8
			        unsigned int num_glyphs)
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_SERIALIZE (this);
Packit Service 5bcba8
    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Single, lookup_props, 1))) return_trace (false);
Packit Service 5bcba8
    return_trace (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes, num_glyphs));
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline bool serialize_multiple (hb_serialize_context_t *c,
Packit Service 5bcba8
				  uint32_t lookup_props,
Packit Service 5bcba8
				  Supplier<GlyphID> &glyphs,
Packit Service 5bcba8
				  Supplier<unsigned int> &substitute_len_list,
Packit Service 5bcba8
				  unsigned int num_glyphs,
Packit Service 5bcba8
				  Supplier<GlyphID> &substitute_glyphs_list)
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_SERIALIZE (this);
Packit Service 5bcba8
    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Multiple, lookup_props, 1))) return_trace (false);
Packit Service 5bcba8
    return_trace (serialize_subtable (c, 0).u.multiple.serialize (c,
Packit Service 5bcba8
								  glyphs,
Packit Service 5bcba8
								  substitute_len_list,
Packit Service 5bcba8
								  num_glyphs,
Packit Service 5bcba8
								  substitute_glyphs_list));
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline bool serialize_alternate (hb_serialize_context_t *c,
Packit Service 5bcba8
				   uint32_t lookup_props,
Packit Service 5bcba8
				   Supplier<GlyphID> &glyphs,
Packit Service 5bcba8
				   Supplier<unsigned int> &alternate_len_list,
Packit Service 5bcba8
				   unsigned int num_glyphs,
Packit Service 5bcba8
				   Supplier<GlyphID> &alternate_glyphs_list)
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_SERIALIZE (this);
Packit Service 5bcba8
    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Alternate, lookup_props, 1))) return_trace (false);
Packit Service 5bcba8
    return_trace (serialize_subtable (c, 0).u.alternate.serialize (c,
Packit Service 5bcba8
								   glyphs,
Packit Service 5bcba8
								   alternate_len_list,
Packit Service 5bcba8
								   num_glyphs,
Packit Service 5bcba8
								   alternate_glyphs_list));
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  inline bool serialize_ligature (hb_serialize_context_t *c,
Packit Service 5bcba8
				  uint32_t lookup_props,
Packit Service 5bcba8
				  Supplier<GlyphID> &first_glyphs,
Packit Service 5bcba8
				  Supplier<unsigned int> &ligature_per_first_glyph_count_list,
Packit Service 5bcba8
				  unsigned int num_first_glyphs,
Packit Service 5bcba8
				  Supplier<GlyphID> &ligatures_list,
Packit Service 5bcba8
				  Supplier<unsigned int> &component_count_list,
Packit Service 5bcba8
				  Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_SERIALIZE (this);
Packit Service 5bcba8
    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Ligature, lookup_props, 1))) return_trace (false);
Packit Service 5bcba8
    return_trace (serialize_subtable (c, 0).u.ligature.serialize (c,
Packit Service 5bcba8
								  first_glyphs,
Packit Service 5bcba8
								  ligature_per_first_glyph_count_list,
Packit Service 5bcba8
								  num_first_glyphs,
Packit Service 5bcba8
								  ligatures_list,
Packit Service 5bcba8
								  component_count_list,
Packit Service 5bcba8
								  component_list));
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  template <typename context_t>
Packit Service 5bcba8
  static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
Packit Service 5bcba8
Packit Service 5bcba8
  template <typename context_t>
Packit Service 5bcba8
  inline typename context_t::return_t dispatch (context_t *c) const
Packit Service 5bcba8
  { return Lookup::dispatch<SubstLookupSubTable> (c); }
Packit Service 5bcba8
Packit Service 5bcba8
  inline bool sanitize (hb_sanitize_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_SANITIZE (this);
Packit Service 5bcba8
    if (unlikely (!Lookup::sanitize (c))) return_trace (false);
Packit Service 5bcba8
    if (unlikely (!dispatch (c))) return_trace (false);
Packit Service 5bcba8
Packit Service 5bcba8
    if (unlikely (get_type () == SubstLookupSubTable::Extension))
Packit Service 5bcba8
    {
Packit Service 5bcba8
      /* The spec says all subtables of an Extension lookup should
Packit Service 5bcba8
       * have the same type.  This is specially important if one has
Packit Service 5bcba8
       * a reverse type! */
Packit Service 5bcba8
      unsigned int type = get_subtable (0).u.extension.get_type ();
Packit Service 5bcba8
      unsigned int count = get_subtable_count ();
Packit Service 5bcba8
      for (unsigned int i = 1; i < count; i++)
Packit Service 5bcba8
        if (get_subtable (i).u.extension.get_type () != type)
Packit Service 5bcba8
	  return_trace (false);
Packit Service 5bcba8
    }
Packit Service 5bcba8
    return_trace (true);
Packit Service 5bcba8
  }
Packit Service 5bcba8
};
Packit Service 5bcba8
Packit Service 5bcba8
typedef OffsetListOf<SubstLookup> SubstLookupList;
Packit Service 5bcba8
Packit Service 5bcba8
/*
Packit Service 5bcba8
 * GSUB -- The Glyph Substitution Table
Packit Service 5bcba8
 */
Packit Service 5bcba8
Packit Service 5bcba8
struct GSUB : GSUBGPOS
Packit Service 5bcba8
{
Packit Service 5bcba8
  static const hb_tag_t tableTag	= HB_OT_TAG_GSUB;
Packit Service 5bcba8
Packit Service 5bcba8
  inline const SubstLookup& get_lookup (unsigned int i) const
Packit Service 5bcba8
  { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); }
Packit Service 5bcba8
Packit Service 5bcba8
  static inline void substitute_start (hb_font_t *font, hb_buffer_t *buffer);
Packit Service 5bcba8
Packit Service 5bcba8
  inline bool sanitize (hb_sanitize_context_t *c) const
Packit Service 5bcba8
  {
Packit Service 5bcba8
    TRACE_SANITIZE (this);
Packit Service 5bcba8
    if (unlikely (!GSUBGPOS::sanitize (c))) return_trace (false);
Packit Service 5bcba8
    const OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
Packit Service 5bcba8
    return_trace (list.sanitize (c, this));
Packit Service 5bcba8
  }
Packit Service 5bcba8
};
Packit Service 5bcba8
Packit Service 5bcba8
Packit Service 5bcba8
void
Packit Service 5bcba8
GSUB::substitute_start (hb_font_t *font, hb_buffer_t *buffer)
Packit Service 5bcba8
{
Packit Service 5bcba8
  _hb_buffer_assert_gsubgpos_vars (buffer);
Packit Service 5bcba8
Packit Service 5bcba8
  const GDEF &gdef = *hb_ot_layout_from_face (font->face)->gdef;
Packit Service 5bcba8
  unsigned int count = buffer->len;
Packit Service 5bcba8
  for (unsigned int i = 0; i < count; i++)
Packit Service 5bcba8
  {
Packit Service 5bcba8
    _hb_glyph_info_set_glyph_props (&buffer->info[i], gdef.get_glyph_props (buffer->info[i].codepoint));
Packit Service 5bcba8
    _hb_glyph_info_clear_lig_props (&buffer->info[i]);
Packit Service 5bcba8
    buffer->info[i].syllable() = 0;
Packit Service 5bcba8
  }
Packit Service 5bcba8
}
Packit Service 5bcba8
Packit Service 5bcba8
Packit Service 5bcba8
/* Out-of-class implementation for methods recursing */
Packit Service 5bcba8
Packit Service 5bcba8
/*static*/ inline bool ExtensionSubst::is_reverse (void) const
Packit Service 5bcba8
{
Packit Service 5bcba8
  unsigned int type = get_type ();
Packit Service 5bcba8
  if (unlikely (type == SubstLookupSubTable::Extension))
Packit Service 5bcba8
    return CastR<ExtensionSubst> (get_subtable<LookupSubTable>()).is_reverse ();
Packit Service 5bcba8
  return SubstLookup::lookup_type_is_reverse (type);
Packit Service 5bcba8
}
Packit Service 5bcba8
Packit Service 5bcba8
template <typename context_t>
Packit Service 5bcba8
/*static*/ inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
Packit Service 5bcba8
{
Packit Service 5bcba8
  const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
Packit Service 5bcba8
  const SubstLookup &l = gsub.get_lookup (lookup_index);
Packit Service 5bcba8
  return l.dispatch (c);
Packit Service 5bcba8
}
Packit Service 5bcba8
Packit Service 5bcba8
/*static*/ inline bool SubstLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
Packit Service 5bcba8
{
Packit Service 5bcba8
  const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
Packit Service 5bcba8
  const SubstLookup &l = gsub.get_lookup (lookup_index);
Packit Service 5bcba8
  unsigned int saved_lookup_props = c->lookup_props;
Packit Service 5bcba8
  unsigned int saved_lookup_index = c->lookup_index;
Packit Service 5bcba8
  c->set_lookup_index (lookup_index);
Packit Service 5bcba8
  c->set_lookup_props (l.get_props ());
Packit Service 5bcba8
  bool ret = l.dispatch (c);
Packit Service 5bcba8
  c->set_lookup_index (saved_lookup_index);
Packit Service 5bcba8
  c->set_lookup_props (saved_lookup_props);
Packit Service 5bcba8
  return ret;
Packit Service 5bcba8
}
Packit Service 5bcba8
Packit Service 5bcba8
Packit Service 5bcba8
} /* namespace OT */
Packit Service 5bcba8
Packit Service 5bcba8
Packit Service 5bcba8
#endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */