text:
/*
 * Copyright © 2007,2008,2009  Red Hat, Inc.
 * Copyright © 2010,2011,2012  Google, Inc.
 *
 *  This is part of HarfBuzz, a text shaping library.
 *
 * 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
 */

#ifndef HB_OT_LAYOUT_GDEF_TABLE_HH
#define HB_OT_LAYOUT_GDEF_TABLE_HH

#include "hb-ot-layout-common.hh"

#include "hb-font.hh"

namespace OT {

/*
 * Attachment List Table
 */

typedef ArrayOf<HBUINT16> AttachPoint;	/* Array of contour point indices--in
					 * increasing numerical order */

struct AttachList
{
  unsigned int get_attach_points (hb_codepoint_t glyph_id,
				  unsigned int start_offset,
				  unsigned int *point_count /* IN/OUT */,
				  unsigned int *point_array /* OUT */) const
  {
    unsigned int index = (this+coverage).get_coverage (glyph_id);
    if (index == NOT_COVERED)
    {
      if (point_count)
	*point_count = 0;
      return 0;
    }

    const AttachPoint &points = this+attachPoint[index];

    if (point_count)
    {
      hb_array_t<const HBUINT16> array = points.sub_array (start_offset, point_count);
      unsigned int count = array.length;
      for (unsigned int i = 0; i < count; i++)
	point_array[i] = array[i];
    }

    return points.len;
  }

  bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    return_trace (coverage.sanitize (c, this) && attachPoint.sanitize (c, this));
  }

  protected:
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table -- from
					 * beginning of AttachList table */
  OffsetArrayOf<AttachPoint>
		attachPoint;		/* Array of AttachPoint tables
					 * in Coverage Index order */
  public:
  DEFINE_SIZE_ARRAY (4, attachPoint);
};

/*
 * Ligature Caret Table
 */

struct CaretValueFormat1
{
  friend struct CaretValue;
  bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    auto *out = c->serializer->embed (this);
    if (unlikely (!out)) return_trace (false);
    return_trace (true);
  }

  private:
  hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction) const
  {
    return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_x (coordinate) : font->em_scale_y (coordinate);
  }

  bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this));
  }

  protected:
  HBUINT16	caretValueFormat;	/* Format identifier--format = 1 */
  FWORD		coordinate;		/* X or Y value, in design units */
  public:
  DEFINE_SIZE_STATIC (4);
};

struct CaretValueFormat2
{
  friend struct CaretValue;
  bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    auto *out = c->serializer->embed (this);
    if (unlikely (!out)) return_trace (false);
    return_trace (true);
  }

  private:
  hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, hb_codepoint_t glyph_id) const
  {
    hb_position_t x, y;
    font->get_glyph_contour_point_for_origin (glyph_id, caretValuePoint, direction, &x, &y);
    return HB_DIRECTION_IS_HORIZONTAL (direction) ? x : y;
  }

  bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this));
  }

  protected:
  HBUINT16	caretValueFormat;	/* Format identifier--format = 2 */
  HBUINT16	caretValuePoint;	/* Contour point index on glyph */
  public:
  DEFINE_SIZE_STATIC (4);
};

struct CaretValueFormat3
{
  friend struct CaretValue;

  hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction,
				 const VariationStore &var_store) const
  {
    return HB_DIRECTION_IS_HORIZONTAL (direction) ?
	   font->em_scale_x (coordinate) + (this+deviceTable).get_x_delta (font, var_store) :
	   font->em_scale_y (coordinate) + (this+deviceTable).get_y_delta (font, var_store);
  }

  bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    auto *out = c->serializer->embed (this);
    if (unlikely (!out)) return_trace (false);

    return_trace (out->deviceTable.serialize_copy (c->serializer, deviceTable, this));
  }

  bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this) && deviceTable.sanitize (c, this));
  }

  protected:
  HBUINT16	caretValueFormat;	/* Format identifier--format = 3 */
  FWORD		coordinate;		/* X or Y value, in design units */
  OffsetTo<Device>
		deviceTable;		/* Offset to Device table for X or Y
					 * value--from beginning of CaretValue
					 * table */
  public:
  DEFINE_SIZE_STATIC (6);
};

struct CaretValue
{
  hb_position_t get_caret_value (hb_font_t *font,
					hb_direction_t direction,
					hb_codepoint_t glyph_id,
					const VariationStore &var_store) const
  {
    switch (u.format) {
    case 1: return u.format1.get_caret_value (font, direction);
    case 2: return u.format2.get_caret_value (font, direction, glyph_id);
    case 3: return u.format3.get_caret_value (font, direction, var_store);
    default:return 0;
    }
  }

  template <typename context_t, typename ...Ts>
  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
  {
    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, hb_forward<Ts> (ds)...));
    case 2: return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
    case 3: return_trace (c->dispatch (u.format3, hb_forward<Ts> (ds)...));
    default:return_trace (c->default_return_value ());
    }
  }

  bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    if (!u.format.sanitize (c)) return_trace (false);
    switch (u.format) {
    case 1: return_trace (u.format1.sanitize (c));
    case 2: return_trace (u.format2.sanitize (c));
    case 3: return_trace (u.format3.sanitize (c));
    default:return_trace (true);
    }
  }

  protected:
  union {
  HBUINT16		format;		/* Format identifier */
  CaretValueFormat1	format1;
  CaretValueFormat2	format2;
  CaretValueFormat3	format3;
  } u;
  public:
  DEFINE_SIZE_UNION (2, format);
};

struct LigGlyph
{
  unsigned int get_lig_carets (hb_font_t *font,
			       hb_direction_t direction,
			       hb_codepoint_t glyph_id,
			       const VariationStore &var_store,
			       unsigned int start_offset,
			       unsigned int *caret_count /* IN/OUT */,
			       hb_position_t *caret_array /* OUT */) const
  {
    if (caret_count)
    {
      hb_array_t <const OffsetTo<CaretValue>> array = carets.sub_array (start_offset, caret_count);
      unsigned int count = array.length;
      for (unsigned int i = 0; i < count; i++)
	caret_array[i] = (this+array[i]).get_caret_value (font, direction, glyph_id, var_store);
    }

    return carets.len;
  }

  bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    auto *out = c->serializer->start_embed (*this);
    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);

    + hb_iter (carets)
    | hb_apply (subset_offset_array (c, out->carets, this))
    ;

    return_trace (bool (out->carets));
  }

  bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    return_trace (carets.sanitize (c, this));
  }

  protected:
  OffsetArrayOf<CaretValue>
		carets;			/* Offset array of CaretValue tables
					 * --from beginning of LigGlyph table
					 * --in increasing coordinate order */
  public:
  DEFINE_SIZE_ARRAY (2, carets);
};

struct LigCaretList
{
  unsigned int get_lig_carets (hb_font_t *font,
			       hb_direction_t direction,
			       hb_codepoint_t glyph_id,
			       const VariationStore &var_store,
			       unsigned int start_offset,
			       unsigned int *caret_count /* IN/OUT */,
			       hb_position_t *caret_array /* OUT */) const
  {
    unsigned int index = (this+coverage).get_coverage (glyph_id);
    if (index == NOT_COVERED)
    {
      if (caret_count)
	*caret_count = 0;
      return 0;
    }
    const LigGlyph &lig_glyph = this+ligGlyph[index];
    return lig_glyph.get_lig_carets (font, direction, glyph_id, var_store, start_offset, caret_count, caret_array);
  }

  bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    const hb_set_t &glyphset = *c->plan->glyphset ();
    const hb_map_t &glyph_map = *c->plan->glyph_map;

    auto *out = c->serializer->start_embed (*this);
    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);

    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
    + hb_zip (this+coverage, ligGlyph)
    | hb_filter (glyphset, hb_first)
    | hb_filter (subset_offset_array (c, out->ligGlyph, this), hb_second)
    | hb_map (hb_first)
    | hb_map (glyph_map)
    | hb_sink (new_coverage)
    ;
    out->coverage.serialize (c->serializer, out)
		 .serialize (c->serializer, new_coverage.iter ());
    return_trace (bool (new_coverage));
  }

  bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    return_trace (coverage.sanitize (c, this) && ligGlyph.sanitize (c, this));
  }

  protected:
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of LigCaretList table */
  OffsetArrayOf<LigGlyph>
		ligGlyph;		/* Array of LigGlyph tables
					 * in Coverage Index order */
  public:
  DEFINE_SIZE_ARRAY (4, ligGlyph);
};

struct MarkGlyphSetsFormat1
{
  bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const
  { return (this+coverage[set_index]).get_coverage (glyph_id) != NOT_COVERED; }

  bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    auto *out = c->serializer->start_embed (*this);
    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
    out->format = format;

    bool ret = true;
    for (const LOffsetTo<Coverage>& offset : coverage.iter ())
    {
      auto *o = out->coverage.serialize_append (c->serializer);
      if (unlikely (!o))
      {
	ret = false;
	break;
      }

      //not using o->serialize_subset (c, offset, this, out) here because
      //OTS doesn't allow null offset.
      //See issue: https://github.com/khaledhosny/ots/issues/172
      c->serializer->push ();
      c->dispatch (this+offset);
      c->serializer->add_link (*o, c->serializer->pop_pack ());
    }

    return_trace (ret && out->coverage.len);
  }

  bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    return_trace (coverage.sanitize (c, this));
  }

  protected:
  HBUINT16	format;			/* Format identifier--format = 1 */
  ArrayOf<LOffsetTo<Coverage>>
		coverage;		/* Array of long offsets to mark set
					 * coverage tables */
  public:
  DEFINE_SIZE_ARRAY (4, coverage);
};

struct MarkGlyphSets
{
  bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const
  {
    switch (u.format) {
    case 1: return u.format1.covers (set_index, glyph_id);
    default:return false;
    }
  }

  bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    switch (u.format) {
    case 1: return_trace (u.format1.subset (c));
    default:return_trace (false);
    }
  }

  bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    if (!u.format.sanitize (c)) return_trace (false);
    switch (u.format) {
    case 1: return_trace (u.format1.sanitize (c));
    default:return_trace (true);
    }
  }

  protected:
  union {
  HBUINT16		format;		/* Format identifier */
  MarkGlyphSetsFormat1	format1;
  } u;
  public:
  DEFINE_SIZE_UNION (2, format);
};

/*
 * GDEF -- Glyph Definition
 * https://docs.microsoft.com/en-us/typography/opentype/spec/gdef
 */

struct GDEF
{
  static constexpr hb_tag_t tableTag = HB_OT_TAG_GDEF;

  enum GlyphClasses {
    UnclassifiedGlyph	= 0,
    BaseGlyph		= 1,
    LigatureGlyph	= 2,
    MarkGlyph		= 3,
    ComponentGlyph	= 4
  };

  bool has_data () const { return version.to_int (); }
  bool has_glyph_classes () const { return glyphClassDef != 0; }
  unsigned int get_glyph_class (hb_codepoint_t glyph) const
  { return (this+glyphClassDef).get_class (glyph); }
  void get_glyphs_in_class (unsigned int klass, hb_set_t *glyphs) const
  { (this+glyphClassDef).collect_class (glyphs, klass); }

  bool has_mark_attachment_types () const { return markAttachClassDef != 0; }
  unsigned int get_mark_attachment_type (hb_codepoint_t glyph) const
  { return (this+markAttachClassDef).get_class (glyph); }

  bool has_attach_points () const { return attachList != 0; }
  unsigned int get_attach_points (hb_codepoint_t glyph_id,
				  unsigned int start_offset,
				  unsigned int *point_count /* IN/OUT */,
				  unsigned int *point_array /* OUT */) const
  { return (this+attachList).get_attach_points (glyph_id, start_offset, point_count, point_array); }

  bool has_lig_carets () const { return ligCaretList != 0; }
  unsigned int get_lig_carets (hb_font_t *font,
			       hb_direction_t direction,
			       hb_codepoint_t glyph_id,
			       unsigned int start_offset,
			       unsigned int *caret_count /* IN/OUT */,
			       hb_position_t *caret_array /* OUT */) const
  { return (this+ligCaretList).get_lig_carets (font,
					       direction, glyph_id, get_var_store(),
					       start_offset, caret_count, caret_array); }

  bool has_mark_sets () const { return version.to_int () >= 0x00010002u && markGlyphSetsDef != 0; }
  bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const
  { return version.to_int () >= 0x00010002u && (this+markGlyphSetsDef).covers (set_index, glyph_id); }

  bool has_var_store () const { return version.to_int () >= 0x00010003u && varStore != 0; }
  const VariationStore &get_var_store () const
  { return version.to_int () >= 0x00010003u ? this+varStore : Null (VariationStore); }

  /* glyph_props is a 16-bit integer where the lower 8-bit have bits representing
   * glyph class and other bits, and high 8-bit the mark attachment type (if any).
   * Not to be confused with lookup_props which is very similar. */
  unsigned int get_glyph_props (hb_codepoint_t glyph) const
  {
    unsigned int klass = get_glyph_class (glyph);

    static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH == (unsigned int) LookupFlag::IgnoreBaseGlyphs), "");
    static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE == (unsigned int) LookupFlag::IgnoreLigatures), "");
    static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_MARK == (unsigned int) LookupFlag::IgnoreMarks), "");

    switch (klass) {
    default:			return 0;
    case BaseGlyph:		return HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH;
    case LigatureGlyph:		return HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE;
    case MarkGlyph:
	  klass = get_mark_attachment_type (glyph);
	  return HB_OT_LAYOUT_GLYPH_PROPS_MARK | (klass << 8);
    }
  }

  HB_INTERNAL bool is_blacklisted (hb_blob_t *blob,
				   hb_face_t *face) const;

  struct accelerator_t
  {
    void init (hb_face_t *face)
    {
      this->table = hb_sanitize_context_t ().reference_table<GDEF> (face);
      if (unlikely (this->table->is_blacklisted (this->table.get_blob (), face)))
      {
	hb_blob_destroy (this->table.get_blob ());
	this->table = hb_blob_get_empty ();
      }
    }

    void fini () { this->table.destroy (); }

    hb_blob_ptr_t<GDEF> table;
  };

  unsigned int get_size () const
  {
    return min_size +
	   (version.to_int () >= 0x00010002u ? markGlyphSetsDef.static_size : 0) +
	   (version.to_int () >= 0x00010003u ? varStore.static_size : 0);
  }

  bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    auto *out = c->serializer->embed (*this);
    if (unlikely (!out)) return_trace (false);

    out->glyphClassDef.serialize_subset (c, glyphClassDef, this);
    out->attachList = 0;//TODO(subset) serialize_subset (c, attachList, this);
    out->ligCaretList.serialize_subset (c, ligCaretList, this);
    out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this);

    if (version.to_int () >= 0x00010002u)
    {
      if (!out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this) &&
	  version.to_int () == 0x00010002u)
	out->version.minor = 0;
    }

    if (version.to_int () >= 0x00010003u)
      out->varStore = 0;// TODO(subset) serialize_subset (c, varStore, this);

    return_trace (true);
  }

  bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    return_trace (version.sanitize (c) &&
		  likely (version.major == 1) &&
		  glyphClassDef.sanitize (c, this) &&
		  attachList.sanitize (c, this) &&
		  ligCaretList.sanitize (c, this) &&
		  markAttachClassDef.sanitize (c, this) &&
		  (version.to_int () < 0x00010002u || markGlyphSetsDef.sanitize (c, this)) &&
		  (version.to_int () < 0x00010003u || varStore.sanitize (c, this)));
  }

  protected:
  FixedVersion<>version;		/* Version of the GDEF table--currently
					 * 0x00010003u */
  OffsetTo<ClassDef>
		glyphClassDef;		/* Offset to class definition table
					 * for glyph type--from beginning of
					 * GDEF header (may be Null) */
  OffsetTo<AttachList>
		attachList;		/* Offset to list of glyphs with
					 * attachment points--from beginning
					 * of GDEF header (may be Null) */
  OffsetTo<LigCaretList>
		ligCaretList;		/* Offset to list of positioning points
					 * for ligature carets--from beginning
					 * of GDEF header (may be Null) */
  OffsetTo<ClassDef>
		markAttachClassDef;	/* Offset to class definition table for
					 * mark attachment type--from beginning
					 * of GDEF header (may be Null) */
  OffsetTo<MarkGlyphSets>
		markGlyphSetsDef;	/* Offset to the table of mark set
					 * definitions--from beginning of GDEF
					 * header (may be NULL).  Introduced
					 * in version 0x00010002. */
  LOffsetTo<VariationStore>
		varStore;		/* Offset to the table of Item Variation
					 * Store--from beginning of GDEF
					 * header (may be NULL).  Introduced
					 * in version 0x00010003. */
  public:
  DEFINE_SIZE_MIN (12);
};

struct GDEF_accelerator_t : GDEF::accelerator_t {};

} /* namespace OT */

#endif /* HB_OT_LAYOUT_GDEF_TABLE_HH */


text:
/*
 * Copyright © 2009,2010  Red Hat, Inc.
 * Copyright © 2010,2011,2012,2013  Google, Inc.
 *
 *  This is part of HarfBuzz, a text shaping library.
 *
 * 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
 */

#ifndef HB_OT_MAP_HH
#define HB_OT_MAP_HH

#include "hb-buffer.hh"

#define HB_OT_MAP_MAX_BITS 8u
#define HB_OT_MAP_MAX_VALUE ((1u << HB_OT_MAP_MAX_BITS) - 1u)

struct hb_ot_shape_plan_t;

static const hb_tag_t table_tags[2] = {HB_OT_TAG_GSUB, HB_OT_TAG_GPOS};

struct hb_ot_map_t
{
  friend struct hb_ot_map_builder_t;

  public:

  struct feature_map_t {
    hb_tag_t tag; /* should be first for our bsearch to work */
    unsigned int index[2]; /* GSUB/GPOS */
    unsigned int stage[2]; /* GSUB/GPOS */
    unsigned int shift;
    hb_mask_t mask;
    hb_mask_t _1_mask; /* mask for value=1, for quick access */
    unsigned int needs_fallback : 1;
    unsigned int auto_zwnj : 1;
    unsigned int auto_zwj : 1;
    unsigned int random : 1;

    int cmp (const hb_tag_t tag_) const
    { return tag_ < tag ? -1 : tag_ > tag ? 1 : 0; }
  };

  struct lookup_map_t {
    unsigned short index;
    unsigned short auto_zwnj : 1;
    unsigned short auto_zwj : 1;
    unsigned short random : 1;
    hb_mask_t mask;

    HB_INTERNAL static int cmp (const void *pa, const void *pb)
    {
      const lookup_map_t *a = (const lookup_map_t *) pa;
      const lookup_map_t *b = (const lookup_map_t *) pb;
      return a->index < b->index ? -1 : a->index > b->index ? 1 : 0;
    }
  };

  typedef void (*pause_func_t) (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer);

  struct stage_map_t {
    unsigned int last_lookup; /* Cumulative */
    pause_func_t pause_func;
  };

  void init ()
  {
    memset (this, 0, sizeof (*this));

    features.init ();
    for (unsigned int table_index = 0; table_index < 2; table_index++)
    {
      lookups[table_index].init ();
      stages[table_index].init ();
    }
  }
  void fini ()
  {
    features.fini ();
    for (unsigned int table_index = 0; table_index < 2; table_index++)
    {
      lookups[table_index].fini ();
      stages[table_index].fini ();
    }
  }

  hb_mask_t get_global_mask () const { return global_mask; }

  hb_mask_t get_mask (hb_tag_t feature_tag, unsigned int *shift = nullptr) const
  {
    const feature_map_t *map = features.bsearch (feature_tag);
    if (shift) *shift = map ? map->shift : 0;
    return map ? map->mask : 0;
  }

  bool needs_fallback (hb_tag_t feature_tag) const
  {
    const feature_map_t *map = features.bsearch (feature_tag);
    return map ? map->needs_fallback : false;
  }

  hb_mask_t get_1_mask (hb_tag_t feature_tag) const
  {
    const feature_map_t *map = features.bsearch (feature_tag);
    return map ? map->_1_mask : 0;
  }

  unsigned int get_feature_index (unsigned int table_index, hb_tag_t feature_tag) const
  {
    const feature_map_t *map = features.bsearch (feature_tag);
    return map ? map->index[table_index] : HB_OT_LAYOUT_NO_FEATURE_INDEX;
  }

  unsigned int get_feature_stage (unsigned int table_index, hb_tag_t feature_tag) const
  {
    const feature_map_t *map = features.bsearch (feature_tag);
    return map ? map->stage[table_index] : UINT_MAX;
  }

  void get_stage_lookups (unsigned int table_index, unsigned int stage,
			  const struct lookup_map_t **plookups, unsigned int *lookup_count) const
  {
    if (unlikely (stage == UINT_MAX)) {
      *plookups = nullptr;
      *lookup_count = 0;
      return;
    }
    assert (stage <= stages[table_index].length);
    unsigned int start = stage ? stages[table_index][stage - 1].last_lookup : 0;
    unsigned int end   = stage < stages[table_index].length ? stages[table_index][stage].last_lookup : lookups[table_index].length;
    *plookups = end == start ? nullptr : &lookups[table_index][start];
    *lookup_count = end - start;
  }

  HB_INTERNAL void collect_lookups (unsigned int table_index, hb_set_t *lookups) const;
  template <typename Proxy>
  HB_INTERNAL void apply (const Proxy &proxy,
			  const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const;
  HB_INTERNAL void substitute (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const;
  HB_INTERNAL void position (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const;

  public:
  hb_tag_t chosen_script[2];
  bool found_script[2];

  private:

  hb_mask_t global_mask;

  hb_sorted_vector_t<feature_map_t> features;
  hb_vector_t<lookup_map_t> lookups[2]; /* GSUB/GPOS */
  hb_vector_t<stage_map_t> stages[2]; /* GSUB/GPOS */
};

enum hb_ot_map_feature_flags_t
{
  F_NONE		= 0x0000u,
  F_GLOBAL		= 0x0001u, /* Feature applies to all characters; results in no mask allocated for it. */
  F_HAS_FALLBACK	= 0x0002u, /* Has fallback implementation, so include mask bit even if feature not found. */
  F_MANUAL_ZWNJ		= 0x0004u, /* Don't skip over ZWNJ when matching **context**. */
  F_MANUAL_ZWJ		= 0x0008u, /* Don't skip over ZWJ when matching **input**. */
  F_MANUAL_JOINERS	= F_MANUAL_ZWNJ | F_MANUAL_ZWJ,
  F_GLOBAL_MANUAL_JOINERS= F_GLOBAL | F_MANUAL_JOINERS,
  F_GLOBAL_HAS_FALLBACK = F_GLOBAL | F_HAS_FALLBACK,
  F_GLOBAL_SEARCH	= 0x0010u, /* If feature not found in LangSys, look for it in global feature list and pick one. */
  F_RANDOM		= 0x0020u  /* Randomly select a glyph from an AlternateSubstFormat1 subtable. */
};
HB_MARK_AS_FLAG_T (hb_ot_map_feature_flags_t);

struct hb_ot_map_feature_t
{
  hb_tag_t tag;
  hb_ot_map_feature_flags_t flags;
};

struct hb_ot_shape_plan_key_t;

struct hb_ot_map_builder_t
{
  public:

  HB_INTERNAL hb_ot_map_builder_t (hb_face_t *face_,
				   const hb_segment_properties_t *props_);

  HB_INTERNAL ~hb_ot_map_builder_t ();

  HB_INTERNAL void add_feature (hb_tag_t tag,
				hb_ot_map_feature_flags_t flags=F_NONE,
				unsigned int value=1);

  void add_feature (const hb_ot_map_feature_t &feat)
  { add_feature (feat.tag, feat.flags); }

  void enable_feature (hb_tag_t tag,
			      hb_ot_map_feature_flags_t flags=F_NONE,
			      unsigned int value=1)
  { add_feature (tag, F_GLOBAL | flags, value); }

  void disable_feature (hb_tag_t tag)
  { add_feature (tag, F_GLOBAL, 0); }

  void add_gsub_pause (hb_ot_map_t::pause_func_t pause_func)
  { add_pause (0, pause_func); }
  void add_gpos_pause (hb_ot_map_t::pause_func_t pause_func)
  { add_pause (1, pause_func); }

  HB_INTERNAL void compile (hb_ot_map_t                  &m,
			    const hb_ot_shape_plan_key_t &key);

  private:

  HB_INTERNAL void add_lookups (hb_ot_map_t  &m,
				unsigned int  table_index,
				unsigned int  feature_index,
				unsigned int  variations_index,
				hb_mask_t     mask,
				bool          auto_zwnj = true,
				bool          auto_zwj = true,
				bool          random = false);

  struct feature_info_t {
    hb_tag_t tag;
    unsigned int seq; /* sequence#, used for stable sorting only */
    unsigned int max_value;
    hb_ot_map_feature_flags_t flags;
    unsigned int default_value; /* for non-global features, what should the unset glyphs take */
    unsigned int stage[2]; /* GSUB/GPOS */

    HB_INTERNAL static int cmp (const void *pa, const void *pb)
    {
      const feature_info_t *a = (const feature_info_t *) pa;
      const feature_info_t *b = (const feature_info_t *) pb;
      return (a->tag != b->tag) ?  (a->tag < b->tag ? -1 : 1) :
	     (a->seq < b->seq ? -1 : a->seq > b->seq ? 1 : 0);
    }
  };

  struct stage_info_t {
    unsigned int index;
    hb_ot_map_t::pause_func_t pause_func;
  };

  HB_INTERNAL void add_pause (unsigned int table_index, hb_ot_map_t::pause_func_t pause_func);

  public:

  hb_face_t *face;
  hb_segment_properties_t props;

  hb_tag_t chosen_script[2];
  bool found_script[2];
  unsigned int script_index[2], language_index[2];

  private:

  unsigned int current_stage[2]; /* GSUB/GPOS */
  hb_vector_t<feature_info_t> feature_infos;
  hb_vector_t<stage_info_t> stages[2]; /* GSUB/GPOS */
};

#endif /* HB_OT_MAP_HH */

repo_language: C

mime_type: text/x-c


text:
/*
 * Copyright © 2018  Ebrahim Byagowi
 *
 *  This is part of HarfBuzz, a text shaping library.
 *
 * 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.
 */

#ifndef HB_OT_STAT_TABLE_HH
#define HB_OT_STAT_TABLE_HH

#include "hb-open-type.hh"
#include "hb-ot-layout-common.hh"

/*
 * STAT -- Style Attributes
 * https://docs.microsoft.com/en-us/typography/opentype/spec/stat
 */
#define HB_OT_TAG_STAT HB_TAG('S','T','A','T')

namespace OT {

enum
{
  OLDER_SIBLING_FONT_ATTRIBUTE = 0x0001,	/* If set, this axis value table
						 * provides axis value information
						 * that is applicable to other fonts
						 * within the same font family. This
						 * is used if the other fonts were
						 * released earlier and did not include
						 * information about values for some axis.
						 * If newer versions of the other
						 * fonts include the information
						 * themselves and are present,
						 * then this record is ignored. */
  ELIDABLE_AXIS_VALUE_NAME = 0x0002		/* If set, it indicates that the axis
						 * value represents the “normal” value
						 * for the axis and may be omitted when
						 * composing name strings. */
  // Reserved = 0xFFFC				/* Reserved for future use — set to zero. */
};

struct AxisValueFormat1
{
  hb_ot_name_id_t get_value_name_id () const { return valueNameID; }

  bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    return_trace (likely (c->check_struct (this)));
  }

  protected:
  HBUINT16	format;		/* Format identifier — set to 1. */
  HBUINT16	axisIndex;	/* Zero-base index into the axis record array
				 * identifying the axis of design variation
				 * to which the axis value record applies.
				 * Must be less than designAxisCount. */
  HBUINT16	flags;		/* Flags — see below for details. */
  NameID	valueNameID;	/* The name ID for entries in the 'name' table
				 * that provide a display string for this
				 * attribute value. */
  HBFixed	value;		/* A numeric value for this attribute value. */
  public:
  DEFINE_SIZE_STATIC (12);
};

struct AxisValueFormat2
{
  hb_ot_name_id_t get_value_name_id () const { return valueNameID; }

  bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    return_trace (likely (c->check_struct (this)));
  }

  protected:
  HBUINT16	format;		/* Format identifier — set to 2. */
  HBUINT16	axisIndex;	/* Zero-base index into the axis record array
				 * identifying the axis of design variation
				 * to which the axis value record applies.
				 * Must be less than designAxisCount. */
  HBUINT16	flags;		/* Flags — see below for details. */
  NameID	valueNameID;	/* The name ID for entries in the 'name' table
				 * that provide a display string for this
				 * attribute value. */
  HBFixed	nominalValue;	/* A numeric value for this attribute value. */
  HBFixed	rangeMinValue;	/* The minimum value for a range associated
				 * with the specified name ID. */
  HBFixed	rangeMaxValue;	/* The maximum value for a range associated
				 * with the specified name ID. */
  public:
  DEFINE_SIZE_STATIC (20);
};

struct AxisValueFormat3
{
  hb_ot_name_id_t get_value_name_id () const { return valueNameID; }

  bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    return_trace (likely (c->check_struct (this)));
  }

  protected:
  HBUINT16	format;		/* Format identifier — set to 3. */
  HBUINT16	axisIndex;	/* Zero-base index into the axis record array
				 * identifying the axis of design variation
				 * to which the axis value record applies.
				 * Must be less than designAxisCount. */
  HBUINT16	flags;		/* Flags — see below for details. */
  NameID	valueNameID;	/* The name ID for entries in the 'name' table
				 * that provide a display string for this
				 * attribute value. */
  HBFixed	value;		/* A numeric value for this attribute value. */
  HBFixed	linkedValue;	/* The numeric value for a style-linked mapping
				 * from this value. */
  public:
  DEFINE_SIZE_STATIC (16);
};

struct AxisValueRecord
{
  bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    return_trace (likely (c->check_struct (this)));
  }

  protected:
  HBUINT16	axisIndex;	/* Zero-base index into the axis record array
				 * identifying the axis to which this value
				 * applies. Must be less than designAxisCount. */
  HBFixed	value;		/* A numeric value for this attribute value. */
  public:
  DEFINE_SIZE_STATIC (6);
};

struct AxisValueFormat4
{
  hb_ot_name_id_t get_value_name_id () const { return valueNameID; }

  bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    return_trace (likely (c->check_struct (this)));
  }

  protected:
  HBUINT16	format;		/* Format identifier — set to 4. */
  HBUINT16	axisCount;	/* The total number of axes contributing to
				 * this axis-values combination. */
  HBUINT16	flags;		/* Flags — see below for details. */
  NameID	valueNameID;	/* The name ID for entries in the 'name' table
				 * that provide a display string for this
				 * attribute value. */
  UnsizedArrayOf<AxisValueRecord>
		axisValues;	/* Array of AxisValue records that provide the
				 * combination of axis values, one for each
				 * contributing axis. */
  public:
  DEFINE_SIZE_ARRAY (8, axisValues);
};

struct AxisValue
{
  hb_ot_name_id_t get_value_name_id () const
  {
    switch (u.format)
    {
    case 1: return u.format1.get_value_name_id ();
    case 2: return u.format2.get_value_name_id ();
    case 3: return u.format3.get_value_name_id ();
    case 4: return u.format4.get_value_name_id ();
    default:return HB_OT_NAME_ID_INVALID;
    }
  }

  bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    if (unlikely (!c->check_struct (this)))
      return_trace (false);

    switch (u.format)
    {
    case 1: return_trace (u.format1.sanitize (c));
    case 2: return_trace (u.format2.sanitize (c));
    case 3: return_trace (u.format3.sanitize (c));
    case 4: return_trace (u.format4.sanitize (c));
    default:return_trace (true);
    }
  }

  protected:
  union
  {
  HBUINT16		format;
  AxisValueFormat1	format1;
  AxisValueFormat2	format2;
  AxisValueFormat3	format3;
  AxisValueFormat4	format4;
  } u;
  public:
  DEFINE_SIZE_UNION (2, format);
};

struct StatAxisRecord
{
  hb_ot_name_id_t get_name_id () const { return nameID; }

  bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    return_trace (likely (c->check_struct (this)));
  }

  protected:
  Tag		tag;		/* A tag identifying the axis of design variation. */
  NameID	nameID;		/* The name ID for entries in the 'name' table that
				 * provide a display string for this axis. */
  HBUINT16	ordering;	/* A value that applications can use to determine
				 * primary sorting of face names, or for ordering
				 * of descriptors when composing family or face names. */
  public:
  DEFINE_SIZE_STATIC (8);
};

struct STAT
{
  static constexpr hb_tag_t tableTag = HB_OT_TAG_STAT;

  bool has_data () const { return version.to_int (); }

  unsigned get_design_axis_count () const { return designAxisCount; }

  hb_ot_name_id_t get_axis_record_name_id (unsigned axis_record_index) const
  {
    if (unlikely (axis_record_index >= designAxisCount)) return HB_OT_NAME_ID_INVALID;
    const StatAxisRecord &axis_record = get_design_axes ()[axis_record_index];
    return axis_record.get_name_id ();
  }

  unsigned get_axis_value_count () const { return axisValueCount; }

  hb_ot_name_id_t get_axis_value_name_id (unsigned axis_value_index) const
  {
    if (unlikely (axis_value_index >= axisValueCount)) return HB_OT_NAME_ID_INVALID;
    const AxisValue &axis_value = (this + get_axis_value_offsets ()[axis_value_index]);
    return axis_value.get_value_name_id ();
  }

  void collect_name_ids (hb_set_t *nameids_to_retain) const
  {
    if (!has_data ()) return;

    + get_design_axes ()
    | hb_map (&StatAxisRecord::get_name_id)
    | hb_sink (nameids_to_retain)
    ;

    + get_axis_value_offsets ()
    | hb_map (hb_add (&(this + offsetToAxisValueOffsets)))
    | hb_map (&AxisValue::get_value_name_id)
    | hb_sink (nameids_to_retain)
    ;
  }

  bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    return_trace (likely (c->check_struct (this) &&
			  version.major == 1 &&
			  version.minor > 0 &&
			  designAxesOffset.sanitize (c, this, designAxisCount) &&
			  offsetToAxisValueOffsets.sanitize (c, this, axisValueCount, &(this+offsetToAxisValueOffsets))));
  }

  protected:
  hb_array_t<const StatAxisRecord> const get_design_axes () const
  { return (this+designAxesOffset).as_array (designAxisCount); }

  hb_array_t<const OffsetTo<AxisValue>> const get_axis_value_offsets () const
  { return (this+offsetToAxisValueOffsets).as_array (axisValueCount); }

  protected:
  FixedVersion<>version;	/* Version of the stat table
				 * initially set to 0x00010002u */
  HBUINT16	designAxisSize;	/* The size in bytes of each axis record. */
  HBUINT16	designAxisCount;/* The number of design axis records. In a
				 * font with an 'fvar' table, this value must be
				 * greater than or equal to the axisCount value
				 * in the 'fvar' table. In all fonts, must
				 * be greater than zero if axisValueCount
				 * is greater than zero. */
  LNNOffsetTo<UnsizedArrayOf<StatAxisRecord>>
		designAxesOffset;
				/* Offset in bytes from the beginning of
				 * the STAT table to the start of the design
				 * axes array. If designAxisCount is zero,
				 * set to zero; if designAxisCount is greater
				 * than zero, must be greater than zero. */
  HBUINT16	axisValueCount;	/* The number of axis value tables. */
  LNNOffsetTo<UnsizedArrayOf<OffsetTo<AxisValue>>>
		offsetToAxisValueOffsets;
				/* Offset in bytes from the beginning of
				 * the STAT table to the start of the design
				 * axes value offsets array. If axisValueCount
				 * is zero, set to zero; if axisValueCount is
				 * greater than zero, must be greater than zero. */
  NameID	elidedFallbackNameID;
				/* Name ID used as fallback when projection of
				 * names into a particular font model produces
				 * a subfamily name containing only elidable
				 * elements. */
  public:
  DEFINE_SIZE_STATIC (20);
};

} /* namespace OT */

#endif /* HB_OT_STAT_TABLE_HH */


text:
#line 1 "hb-ot-shape-complex-myanmar-machine.rl"
/*
 * Copyright © 2011,2012  Google, Inc.
 *
 *  This is part of HarfBuzz, a text shaping library.
 *
 * 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.
 *
 * Google Author(s): Behdad Esfahbod
 */

#ifndef HB_OT_SHAPE_COMPLEX_MYANMAR_MACHINE_HH
#define HB_OT_SHAPE_COMPLEX_MYANMAR_MACHINE_HH

#include "hb.hh"

#line 36 "hb-ot-shape-complex-myanmar-machine.hh"
static const unsigned char _myanmar_syllable_machine_trans_keys[] = {
	1u, 32u, 3u, 30u, 5u, 29u, 5u, 8u, 5u, 29u, 3u, 25u, 5u, 25u, 5u, 25u,
	3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 1u, 16u, 3u, 29u, 3u, 29u, 3u, 29u,
	3u, 29u, 3u, 29u, 3u, 30u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u,
	5u, 29u, 5u, 8u, 5u, 29u, 3u, 25u, 5u, 25u, 5u, 25u, 3u, 29u, 3u, 29u,
	3u, 29u, 3u, 29u, 1u, 16u, 3u, 30u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u,
	3u, 29u, 3u, 30u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 30u,
	3u, 29u, 1u, 32u, 1u, 32u, 8u, 8u, 0
};

static const char _myanmar_syllable_machine_key_spans[] = {
	32, 28, 25, 4, 25, 23, 21, 21,
	27, 27, 27, 27, 16, 27, 27, 27,
	27, 27, 28, 27, 27, 27, 27, 27,
	25, 4, 25, 23, 21, 21, 27, 27,
	27, 27, 16, 28, 27, 27, 27, 27,
	27, 28, 27, 27, 27, 27, 27, 28,
	27, 32, 32, 1
};

static const short _myanmar_syllable_machine_index_offsets[] = {
	0, 33, 62, 88, 93, 119, 143, 165,
	187, 215, 243, 271, 299, 316, 344, 372,
	400, 428, 456, 485, 513, 541, 569, 597,
	625, 651, 656, 682, 706, 728, 750, 778,
	806, 834, 862, 879, 908, 936, 964, 992,
	1020, 1048, 1077, 1105, 1133, 1161, 1189, 1217,
	1246, 1274, 1307, 1340
};

static const char _myanmar_syllable_machine_indicies[] = {
	1, 1, 2, 3, 4, 4, 0, 5,
	0, 6, 1, 0, 0, 0, 0, 7,
	0, 8, 9, 0, 10, 11, 12, 13,
	14, 15, 16, 17, 18, 19, 20, 1,
	0, 22, 23, 24, 24, 21, 25, 21,
	26, 21, 21, 21, 21, 21, 21, 21,
	27, 21, 21, 28, 29, 30, 31, 32,
	33, 34, 35, 36, 37, 21, 24, 24,
	21, 25, 21, 21, 21, 21, 21, 21,
	21, 21, 21, 38, 21, 21, 21, 21,
	21, 21, 32, 21, 21, 21, 36, 21,
	24, 24, 21, 25, 21, 24, 24, 21,
	25, 21, 21, 21, 21, 21, 21, 21,
	21, 21, 21, 21, 21, 21, 21, 21,
	21, 32, 21, 21, 21, 36, 21, 39,
	21, 24, 24, 21, 25, 21, 32, 21,
	21, 21, 21, 21, 21, 21, 40, 21,
	21, 21, 21, 21, 21, 32, 21, 24,
	24, 21, 25, 21, 21, 21, 21, 21,
	21, 21, 21, 21, 40, 21, 21, 21,
	21, 21, 21, 32, 21, 24, 24, 21,
	25, 21, 21, 21, 21, 21, 21, 21,
	21, 21, 21, 21, 21, 21, 21, 21,
	21, 32, 21, 22, 21, 24, 24, 21,
	25, 21, 26, 21, 21, 21, 21, 21,
	21, 21, 41, 21, 21, 41, 21, 21,
	21, 32, 42, 21, 21, 36, 21, 22,
	21, 24, 24, 21, 25, 21, 26, 21,
	21, 21, 21, 21, 21, 21, 21, 21,
	21, 21, 21, 21, 21, 32, 21, 21,
	21, 36, 21, 22, 21, 24, 24, 21,
	25, 21, 26, 21, 21, 21, 21, 21,
	21, 21, 41, 21, 21, 21, 21, 21,
	21, 32, 42, 21, 21, 36, 21, 22,
	21, 24, 24, 21, 25, 21, 26, 21,
	21, 21, 21, 21, 21, 21, 21, 21,
	21, 21, 21, 21, 21, 32, 42, 21,
	21, 36, 21, 1, 1, 21, 21, 21,
	21, 21, 21, 21, 21, 21, 21, 21,
	21, 21, 1, 21, 22, 21, 24, 24,
	21, 25, 21, 26, 21, 21, 21, 21,
	21, 21, 21, 27, 21, 21, 28, 29,
	30, 31, 32, 33, 34, 35, 36, 21,
	22, 21, 24, 24, 21, 25, 21, 26,
	21, 21, 21, 21, 21, 21, 21, 43,
	21, 21, 21, 21, 21, 21, 32, 33,
	34, 35, 36, 21, 22, 21, 24, 24,
	21, 25, 21, 26, 21, 21, 21, 21,
	21, 21, 21, 21, 21, 21, 21, 21,
	21, 21, 32, 33, 34, 35, 36, 21,
	22, 21, 24, 24, 21, 25, 21, 26,
	21, 21, 21, 21, 21, 21, 21, 21,
	21, 21, 21, 21, 21, 21, 32, 33,
	34, 21, 36, 21, 22, 21, 24, 24,
	21, 25, 21, 26, 21, 21, 21, 21,
	21, 21, 21, 21, 21, 21, 21, 21,
	21, 21, 32, 21, 34, 21, 36, 21,
	22, 21, 24, 24, 21, 25, 21, 26,
	21, 21, 21, 21, 21, 21, 21, 21,
	21, 21, 21, 21, 21, 21, 32, 33,
	34, 35, 36, 43, 21, 22, 21, 24,
	24, 21, 25, 21, 26, 21, 21, 21,
	21, 21, 21, 21, 21, 21, 21, 28,
	21, 30, 21, 32, 33, 34, 35, 36,
	21, 22, 21, 24, 24, 21, 25, 21,
	26, 21, 21, 21, 21, 21, 21, 21,
	43, 21, 21, 28, 21, 21, 21, 32,
	33, 34, 35, 36, 21, 22, 21, 24,
	24, 21, 25, 21, 26, 21, 21, 21,
	21, 21, 21, 21, 44, 21, 21, 28,
	29, 30, 21, 32, 33, 34, 35, 36,
	21, 22, 21, 24, 24, 21, 25, 21,
	26, 21, 21, 21, 21, 21, 21, 21,
	21, 21, 21, 28, 29, 30, 21, 32,
	33, 34, 35, 36, 21, 22, 23, 24,
	24, 21, 25, 21, 26, 21, 21, 21,
	21, 21, 21, 21, 27, 21, 21, 28,
	29, 30, 31, 32, 33, 34, 35, 36,
	21, 46, 46, 45, 5, 45, 45, 45,
	45, 45, 45, 45, 45, 45, 47, 45,
	45, 45, 45, 45, 45, 14, 45, 45,
	45, 18, 45, 46, 46, 45, 5, 45,
	46, 46, 45, 5, 45, 45, 45, 45,
	45, 45, 45, 45, 45, 45, 45, 45,
	45, 45, 45, 45, 14, 45, 45, 45,
	18, 45, 48, 45, 46, 46, 45, 5,
	45, 14, 45, 45, 45, 45, 45, 45,
	45, 49, 45, 45, 45, 45, 45, 45,
	14, 45, 46, 46, 45, 5, 45, 45,
	45, 45, 45, 45, 45, 45, 45, 49,
	45, 45, 45, 45, 45, 45, 14, 45,
	46, 46, 45, 5, 45, 45, 45, 45,
	45, 45, 45, 45, 45, 45, 45, 45,
	45, 45, 45, 45, 14, 45, 2, 45,
	46, 46, 45, 5, 45, 6, 45, 45,
	45, 45, 45, 45, 45, 50, 45, 45,
	50, 45, 45, 45, 14, 51, 45, 45,
	18, 45, 2, 45, 46, 46, 45, 5,
	45, 6, 45, 45, 45, 45, 45, 45,
	45, 45, 45, 45, 45, 45, 45, 45,
	14, 45, 45, 45, 18, 45, 2, 45,
	46, 46, 45, 5, 45, 6, 45, 45,
	45, 45, 45, 45, 45, 50, 45, 45,
	45, 45, 45, 45, 14, 51, 45, 45,
	18, 45, 2, 45, 46, 46, 45, 5,
	45, 6, 45, 45, 45, 45, 45, 45,
	45, 45, 45, 45, 45, 45, 45, 45,
	14, 51, 45, 45, 18, 45, 52, 52,
	45, 45, 45, 45, 45, 45, 45, 45,
	45, 45, 45, 45, 45, 52, 45, 2,
	3, 46, 46, 45, 5, 45, 6, 45,
	45, 45, 45, 45, 45, 45, 8, 45,
	45, 10, 11, 12, 13, 14, 15, 16,
	17, 18, 19, 45, 2, 45, 46, 46,
	45, 5, 45, 6, 45, 45, 45, 45,
	45, 45, 45, 8, 45, 45, 10, 11,
	12, 13, 14, 15, 16, 17, 18, 45,
	2, 45, 46, 46, 45, 5, 45, 6,
	45, 45, 45, 45, 45, 45, 45, 53,
	45, 45, 45, 45, 45, 45, 14, 15,
	16, 17, 18, 45, 2, 45, 46, 46,
	45, 5, 45, 6, 45, 45, 45, 45,
	45, 45, 45, 45, 45, 45, 45, 45,
	45, 45, 14, 15, 16, 17, 18, 45,
	2, 45, 46, 46, 45, 5, 45, 6,
	45, 45, 45, 45, 45, 45, 45, 45,
	45, 45, 45, 45, 45, 45, 14, 15,
	16, 45, 18, 45, 2, 45, 46, 46,
	45, 5, 45, 6, 45, 45, 45, 45,
	45, 45, 45, 45, 45, 45, 45, 45,
	45, 45, 14, 45, 16, 45, 18, 45,
	2, 45, 46, 46, 45, 5, 45, 6,
	45, 45, 45, 45, 45, 45, 45, 45,
	45, 45, 45, 45, 45, 45, 14, 15,
	16, 17, 18, 53, 45, 2, 45, 46,
	46, 45, 5, 45, 6, 45, 45, 45,
	45, 45, 45, 45, 45, 45, 45, 10,
	45, 12, 45, 14, 15, 16, 17, 18,
	45, 2, 45, 46, 46, 45, 5, 45,
	6, 45, 45, 45, 45, 45, 45, 45,
	53, 45, 45, 10, 45, 45, 45, 14,
	15, 16, 17, 18, 45, 2, 45, 46,
	46, 45, 5, 45, 6, 45, 45, 45,
	45, 45, 45, 45, 54, 45, 45, 10,
	11, 12, 45, 14, 15, 16, 17, 18,
	45, 2, 45, 46, 46, 45, 5, 45,
	6, 45, 45, 45, 45, 45, 45, 45,
	45, 45, 45, 10, 11, 12, 45, 14,
	15, 16, 17, 18, 45, 2, 3, 46,
	46, 45, 5, 45, 6, 45, 45, 45,
	45, 45, 45, 45, 8, 45, 45, 10,
	11, 12, 13, 14, 15, 16, 17, 18,
	45, 22, 23, 24, 24, 21, 25, 21,
	26, 21, 21, 21, 21, 21, 21, 21,
	55, 21, 21, 28, 29, 30, 31, 32,
	33, 34, 35, 36, 37, 21, 22, 56,
	24, 24, 21, 25, 21, 26, 21, 21,
	21, 21, 21, 21, 21, 27, 21, 21,
	28, 29, 30, 31, 32, 33, 34, 35,
	36, 21, 1, 1, 2, 3, 46, 46,
	45, 5, 45, 6, 1, 45, 45, 45,
	45, 1, 45, 8, 45, 45, 10, 11,
	12, 13, 14, 15, 16, 17, 18, 19,
	45, 1, 45, 1, 1, 57, 57, 57,
	57, 57, 57, 57, 57, 1, 57, 57,
	57, 57, 1, 57, 57, 57, 57, 57,
	57, 57, 57, 57, 57, 57, 57, 57,
	57, 57, 1, 57, 58, 57, 0
};

static const char _myanmar_syllable_machine_trans_targs[] = {
	0, 1, 24, 34, 0, 25, 31, 47,
	36, 50, 37, 42, 43, 44, 27, 39,
	40, 41, 30, 46, 51, 0, 2, 12,
	0, 3, 9, 13, 14, 19, 20, 21,
	5, 16, 17, 18, 8, 23, 4, 6,
	7, 10, 11, 15, 22, 0, 0, 26,
	28, 29, 32, 33, 35, 38, 45, 48,
	49, 0, 0
};

static const char _myanmar_syllable_machine_trans_actions[] = {
	3, 0, 0, 0, 4, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 5, 0, 0,
	6, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 7, 8, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 9, 10
};

static const char _myanmar_syllable_machine_to_state_actions[] = {
	1, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0
};

static const char _myanmar_syllable_machine_from_state_actions[] = {
	2, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0
};

static const short _myanmar_syllable_machine_eof_trans[] = {
	0, 22, 22, 22, 22, 22, 22, 22,
	22, 22, 22, 22, 22, 22, 22, 22,
	22, 22, 22, 22, 22, 22, 22, 22,
	46, 46, 46, 46, 46, 46, 46, 46,
	46, 46, 46, 46, 46, 46, 46, 46,
	46, 46, 46, 46, 46, 46, 46, 22,
	22, 46, 58, 58
};

static const int myanmar_syllable_machine_start = 0;
static const int myanmar_syllable_machine_first_final = 0;
static const int myanmar_syllable_machine_error = -1;

static const int myanmar_syllable_machine_en_main = 0;

#line 36 "hb-ot-shape-complex-myanmar-machine.rl"

#line 94 "hb-ot-shape-complex-myanmar-machine.rl"

#define found_syllable(syllable_type) \
  HB_STMT_START { \
    if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \
    for (unsigned int i = ts; i < te; i++) \
      info[i].syllable() = (syllable_serial << 4) | myanmar_##syllable_type; \
    syllable_serial++; \
    if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
  } HB_STMT_END

static void
find_syllables_myanmar (hb_buffer_t *buffer)
{
  unsigned int p, pe, eof, ts, te, act HB_UNUSED;
  int cs;
  hb_glyph_info_t *info = buffer->info;

#line 320 "hb-ot-shape-complex-myanmar-machine.hh"
	{
	cs = myanmar_syllable_machine_start;
	ts = 0;
	te = 0;
	act = 0;
	}

#line 114 "hb-ot-shape-complex-myanmar-machine.rl"

  p = 0;
  pe = eof = buffer->len;

  unsigned int syllable_serial = 1;

#line 336 "hb-ot-shape-complex-myanmar-machine.hh"
	{
	int _slen;
	int _trans;
	const unsigned char *_keys;
	const char *_inds;
	if ( p == pe )
		goto _test_eof;
_resume:
	switch ( _myanmar_syllable_machine_from_state_actions[cs] ) {
	case 2:
#line 1 "NONE"
	{ts = p;}
	break;
#line 350 "hb-ot-shape-complex-myanmar-machine.hh"
	}

	_keys = _myanmar_syllable_machine_trans_keys + (cs<<1);
	_inds = _myanmar_syllable_machine_indicies + _myanmar_syllable_machine_index_offsets[cs];

	_slen = _myanmar_syllable_machine_key_spans[cs];
	_trans = _inds[ _slen > 0 && _keys[0] <=( info[p].myanmar_category()) &&
		( info[p].myanmar_category()) <= _keys[1] ?
		( info[p].myanmar_category()) - _keys[0] : _slen ];

_eof_trans:
	cs = _myanmar_syllable_machine_trans_targs[_trans];

	if ( _myanmar_syllable_machine_trans_actions[_trans] == 0 )
		goto _again;

	switch ( _myanmar_syllable_machine_trans_actions[_trans] ) {
	case 6:
#line 86 "hb-ot-shape-complex-myanmar-machine.rl"
	{te = p+1;{ found_syllable (consonant_syllable); }}
	break;
	case 4:
#line 87 "hb-ot-shape-complex-myanmar-machine.rl"
	{te = p+1;{ found_syllable (non_myanmar_cluster); }}
	break;
	case 10:
#line 88 "hb-ot-shape-complex-myanmar-machine.rl"
	{te = p+1;{ found_syllable (punctuation_cluster); }}
	break;
	case 8:
#line 89 "hb-ot-shape-complex-myanmar-machine.rl"
	{te = p+1;{ found_syllable (broken_cluster); }}
	break;
	case 3:
#line 90 "hb-ot-shape-complex-myanmar-machine.rl"
	{te = p+1;{ found_syllable (non_myanmar_cluster); }}
	break;
	case 5:
#line 86 "hb-ot-shape-complex-myanmar-machine.rl"
	{te = p;p--;{ found_syllable (consonant_syllable); }}
	break;
	case 7:
#line 89 "hb-ot-shape-complex-myanmar-machine.rl"
	{te = p;p--;{ found_syllable (broken_cluster); }}
	break;
	case 9:
#line 90 "hb-ot-shape-complex-myanmar-machine.rl"
	{te = p;p--;{ found_syllable (non_myanmar_cluster); }}
	break;
#line 400 "hb-ot-shape-complex-myanmar-machine.hh"
	}

_again:
	switch ( _myanmar_syllable_machine_to_state_actions[cs] ) {
	case 1:
#line 1 "NONE"
	{ts = 0;}
	break;
#line 409 "hb-ot-shape-complex-myanmar-machine.hh"
	}

	if ( ++p != pe )
		goto _resume;
	_test_eof: {}
	if ( p == eof )
	{
	if ( _myanmar_syllable_machine_eof_trans[cs] > 0 ) {
		_trans = _myanmar_syllable_machine_eof_trans[cs] - 1;
		goto _eof_trans;
	}
	}

	}

#line 122 "hb-ot-shape-complex-myanmar-machine.rl"

}

#undef found_syllable

#endif /* HB_OT_SHAPE_COMPLEX_MYANMAR_MACHINE_HH */


text:
/*
 * Copyright © 2012  Google, Inc.
 *
 *  This is part of HarfBuzz, a text shaping library.
 *
 * 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.
 *
 * Google Author(s): Behdad Esfahbod
 */

#ifndef HB_SHAPER_HH
#define HB_SHAPER_HH

#include "hb.hh"
#include "hb-machinery.hh"

typedef hb_bool_t hb_shape_func_t (hb_shape_plan_t    *shape_plan,
				   hb_font_t          *font,
				   hb_buffer_t        *buffer,
				   const hb_feature_t *features,
				   unsigned int        num_features);

#define HB_SHAPER_IMPLEMENT(name) \
	extern "C" HB_INTERNAL hb_shape_func_t _hb_##name##_shape;
#include "hb-shaper-list.hh"
#undef HB_SHAPER_IMPLEMENT

struct hb_shaper_entry_t {
  char name[16];
  hb_shape_func_t *func;
};

HB_INTERNAL const hb_shaper_entry_t *
_hb_shapers_get ();

template <typename Data, unsigned int WheresData, typename T>
struct hb_shaper_lazy_loader_t;

#define HB_SHAPER_ORDER(Shaper) \
  HB_PASTE (HB_SHAPER_ORDER_, Shaper)
enum hb_shaper_order_t
{
  _HB_SHAPER_ORDER_ORDER_ZERO,
#define HB_SHAPER_IMPLEMENT(Shaper) \
      HB_SHAPER_ORDER (Shaper),
#include "hb-shaper-list.hh"
#undef HB_SHAPER_IMPLEMENT
  _HB_SHAPERS_COUNT_PLUS_ONE,
  HB_SHAPERS_COUNT = _HB_SHAPERS_COUNT_PLUS_ONE - 1,
};

template <enum hb_shaper_order_t order, typename Object> struct hb_shaper_object_data_type_t;

#define HB_SHAPER_DATA_SUCCEEDED ((void *) +1)
#define HB_SHAPER_DATA_TYPE(shaper, object)		hb_##shaper##_##object##_data_t
#define HB_SHAPER_DATA_CREATE_FUNC(shaper, object)	_hb_##shaper##_shaper_##object##_data_create
#define HB_SHAPER_DATA_DESTROY_FUNC(shaper, object)	_hb_##shaper##_shaper_##object##_data_destroy

#define HB_SHAPER_DATA_INSTANTIATE_SHAPERS(shaper, object) \
	\
	struct HB_SHAPER_DATA_TYPE (shaper, object); /* Type forward declaration. */ \
	extern "C" HB_INTERNAL HB_SHAPER_DATA_TYPE (shaper, object) * \
	HB_SHAPER_DATA_CREATE_FUNC (shaper, object) (hb_##object##_t *object); \
	extern "C" HB_INTERNAL void \
	HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (HB_SHAPER_DATA_TYPE (shaper, object) *shaper##_##object); \
	\
	template <> \
	struct hb_shaper_object_data_type_t<HB_SHAPER_ORDER (shaper), hb_##object##_t> \
	{ \
	  typedef HB_SHAPER_DATA_TYPE(shaper, object) value; \
	}; \
	\
	template <unsigned int WheresData> \
	struct hb_shaper_lazy_loader_t<hb_##object##_t, WheresData, HB_SHAPER_DATA_TYPE(shaper, object)> \
		: hb_lazy_loader_t<HB_SHAPER_DATA_TYPE(shaper, object), \
				   hb_shaper_lazy_loader_t<hb_##object##_t, \
							   WheresData, \
							   HB_SHAPER_DATA_TYPE(shaper, object)>, \
				   hb_##object##_t, WheresData> \
	{ \
	  typedef HB_SHAPER_DATA_TYPE(shaper, object) Type; \
	  static Type* create (hb_##object##_t *data) \
	  { return HB_SHAPER_DATA_CREATE_FUNC (shaper, object) (data); } \
	  static Type *get_null () { return nullptr; } \
	  static void destroy (Type *p) { HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (p); } \
	}; \
	\
	static_assert (true, "") /* Require semicolon after. */

template <typename Object>
struct hb_shaper_object_dataset_t
{
  void init0 (Object *parent_data)
  {
    this->parent_data = parent_data;
#define HB_SHAPER_IMPLEMENT(shaper) shaper.init0 ();
#include "hb-shaper-list.hh"
#undef HB_SHAPER_IMPLEMENT
  }
  void fini ()
  {
#define HB_SHAPER_IMPLEMENT(shaper) shaper.fini ();
#include "hb-shaper-list.hh"
#undef HB_SHAPER_IMPLEMENT
  }

  Object *parent_data; /* MUST be JUST before the lazy loaders. */
#define HB_SHAPER_IMPLEMENT(shaper) \
	hb_shaper_lazy_loader_t<Object, HB_SHAPER_ORDER(shaper), \
				typename hb_shaper_object_data_type_t<HB_SHAPER_ORDER(shaper), Object>::value \
			       > shaper;
#include "hb-shaper-list.hh"
#undef HB_SHAPER_IMPLEMENT
};

#endif /* HB_SHAPER_HH */


text:
/*
 * Copyright © 2015  Mozilla Foundation.
 * Copyright © 2015  Google, Inc.
 *
 *  This is part of HarfBuzz, a text shaping library.
 *
 * 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.
 *
 * Mozilla Author(s): Jonathan Kew
 * Google Author(s): Behdad Esfahbod
 */

#include "hb.hh"

#ifndef HB_NO_OT_SHAPE

#include "hb-ot-shape-complex-use.hh"
#include "hb-ot-shape-complex-arabic.hh"
#include "hb-ot-shape-complex-vowel-constraints.hh"

/* buffer var allocations */
#define use_category() complex_var_u8_0()

/*
 * Universal Shaping Engine.
 * https://docs.microsoft.com/en-us/typography/script-development/use
 */

static const hb_tag_t
use_basic_features[] =
{
  /*
   * Basic features.
   * These features are applied all at once, before reordering.
   */
  HB_TAG('r','k','r','f'),
  HB_TAG('a','b','v','f'),
  HB_TAG('b','l','w','f'),
  HB_TAG('h','a','l','f'),
  HB_TAG('p','s','t','f'),
  HB_TAG('v','a','t','u'),
  HB_TAG('c','j','c','t'),
};
static const hb_tag_t
use_topographical_features[] =
{
  HB_TAG('i','s','o','l'),
  HB_TAG('i','n','i','t'),
  HB_TAG('m','e','d','i'),
  HB_TAG('f','i','n','a'),
};
/* Same order as use_topographical_features. */
enum joining_form_t {
  USE_ISOL,
  USE_INIT,
  USE_MEDI,
  USE_FINA,
  _USE_NONE
};
static const hb_tag_t
use_other_features[] =
{
  /*
   * Other features.
   * These features are applied all at once, after reordering and
   * clearing syllables.
   */
  HB_TAG('a','b','v','s'),
  HB_TAG('b','l','w','s'),
  HB_TAG('h','a','l','n'),
  HB_TAG('p','r','e','s'),
  HB_TAG('p','s','t','s'),
};

static void
setup_syllables_use (const hb_ot_shape_plan_t *plan,
		     hb_font_t *font,
		     hb_buffer_t *buffer);
static void
record_rphf_use (const hb_ot_shape_plan_t *plan,
		 hb_font_t *font,
		 hb_buffer_t *buffer);
static void
record_pref_use (const hb_ot_shape_plan_t *plan,
		 hb_font_t *font,
		 hb_buffer_t *buffer);
static void
reorder_use (const hb_ot_shape_plan_t *plan,
	     hb_font_t *font,
	     hb_buffer_t *buffer);

static void
collect_features_use (hb_ot_shape_planner_t *plan)
{
  hb_ot_map_builder_t *map = &plan->map;

  /* Do this before any lookups have been applied. */
  map->add_gsub_pause (setup_syllables_use);

  /* "Default glyph pre-processing group" */
  map->enable_feature (HB_TAG('l','o','c','l'));
  map->enable_feature (HB_TAG('c','c','m','p'));
  map->enable_feature (HB_TAG('n','u','k','t'));
  map->enable_feature (HB_TAG('a','k','h','n'), F_MANUAL_ZWJ);

  /* "Reordering group" */
  map->add_gsub_pause (_hb_clear_substitution_flags);
  map->add_feature (HB_TAG('r','p','h','f'), F_MANUAL_ZWJ);
  map->add_gsub_pause (record_rphf_use);
  map->add_gsub_pause (_hb_clear_substitution_flags);
  map->enable_feature (HB_TAG('p','r','e','f'), F_MANUAL_ZWJ);
  map->add_gsub_pause (record_pref_use);

  /* "Orthographic unit shaping group" */
  for (unsigned int i = 0; i < ARRAY_LENGTH (use_basic_features); i++)
    map->enable_feature (use_basic_features[i], F_MANUAL_ZWJ);

  map->add_gsub_pause (reorder_use);
  map->add_gsub_pause (_hb_clear_syllables);

  /* "Topographical features" */
  for (unsigned int i = 0; i < ARRAY_LENGTH (use_topographical_features); i++)
    map->add_feature (use_topographical_features[i]);
  map->add_gsub_pause (nullptr);

  /* "Standard typographic presentation" */
  for (unsigned int i = 0; i < ARRAY_LENGTH (use_other_features); i++)
    map->enable_feature (use_other_features[i], F_MANUAL_ZWJ);
}

struct use_shape_plan_t
{
  hb_mask_t rphf_mask;

  arabic_shape_plan_t *arabic_plan;
};

static bool
has_arabic_joining (hb_script_t script)
{
  /* List of scripts that have data in arabic-table. */
  switch ((int) script)
  {
    /* Unicode-1.1 additions */
    case HB_SCRIPT_ARABIC:

    /* Unicode-3.0 additions */
    case HB_SCRIPT_MONGOLIAN:
    case HB_SCRIPT_SYRIAC:

    /* Unicode-5.0 additions */
    case HB_SCRIPT_NKO:
    case HB_SCRIPT_PHAGS_PA:

    /* Unicode-6.0 additions */
    case HB_SCRIPT_MANDAIC:

    /* Unicode-7.0 additions */
    case HB_SCRIPT_MANICHAEAN:
    case HB_SCRIPT_PSALTER_PAHLAVI:

    /* Unicode-9.0 additions */
    case HB_SCRIPT_ADLAM:

      return true;

    default:
      return false;
  }
}

static void *
data_create_use (const hb_ot_shape_plan_t *plan)
{
  use_shape_plan_t *use_plan = (use_shape_plan_t *) calloc (1, sizeof (use_shape_plan_t));
  if (unlikely (!use_plan))
    return nullptr;

  use_plan->rphf_mask = plan->map.get_1_mask (HB_TAG('r','p','h','f'));

  if (has_arabic_joining (plan->props.script))
  {
    use_plan->arabic_plan = (arabic_shape_plan_t *) data_create_arabic (plan);
    if (unlikely (!use_plan->arabic_plan))
    {
      free (use_plan);
      return nullptr;
    }
  }

  return use_plan;
}

static void
data_destroy_use (void *data)
{
  use_shape_plan_t *use_plan = (use_shape_plan_t *) data;

  if (use_plan->arabic_plan)
    data_destroy_arabic (use_plan->arabic_plan);

  free (data);
}

enum use_syllable_type_t {
  use_independent_cluster,
  use_virama_terminated_cluster,
  use_sakot_terminated_cluster,
  use_standard_cluster,
  use_number_joiner_terminated_cluster,
  use_numeral_cluster,
  use_symbol_cluster,
  use_broken_cluster,
  use_non_cluster,
};

#include "hb-ot-shape-complex-use-machine.hh"

static void
setup_masks_use (const hb_ot_shape_plan_t *plan,
		 hb_buffer_t              *buffer,
		 hb_font_t                *font HB_UNUSED)
{
  const use_shape_plan_t *use_plan = (const use_shape_plan_t *) plan->data;

  /* Do this before allocating use_category(). */
  if (use_plan->arabic_plan)
  {
    setup_masks_arabic_plan (use_plan->arabic_plan, buffer, plan->props.script);
  }

  HB_BUFFER_ALLOCATE_VAR (buffer, use_category);

  /* We cannot setup masks here.  We save information about characters
   * and setup masks later on in a pause-callback. */

  unsigned int count = buffer->len;
  hb_glyph_info_t *info = buffer->info;
  for (unsigned int i = 0; i < count; i++)
    info[i].use_category() = hb_use_get_category (info[i].codepoint);
}

static void
setup_rphf_mask (const hb_ot_shape_plan_t *plan,
		 hb_buffer_t *buffer)
{
  const use_shape_plan_t *use_plan = (const use_shape_plan_t *) plan->data;

  hb_mask_t mask = use_plan->rphf_mask;
  if (!mask) return;

  hb_glyph_info_t *info = buffer->info;

  foreach_syllable (buffer, start, end)
  {
    unsigned int limit = info[start].use_category() == USE_R ? 1 : hb_min (3u, end - start);
    for (unsigned int i = start; i < start + limit; i++)
      info[i].mask |= mask;
  }
}

static void
setup_topographical_masks (const hb_ot_shape_plan_t *plan,
			   hb_buffer_t *buffer)
{
  const use_shape_plan_t *use_plan = (const use_shape_plan_t *) plan->data;
  if (use_plan->arabic_plan)
    return;

  static_assert ((USE_INIT < 4 && USE_ISOL < 4 && USE_MEDI < 4 && USE_FINA < 4), "");
  hb_mask_t masks[4], all_masks = 0;
  for (unsigned int i = 0; i < 4; i++)
  {
    masks[i] = plan->map.get_1_mask (use_topographical_features[i]);
    if (masks[i] == plan->map.get_global_mask ())
      masks[i] = 0;
    all_masks |= masks[i];
  }
  if (!all_masks)
    return;
  hb_mask_t other_masks = ~all_masks;

  unsigned int last_start = 0;
  joining_form_t last_form = _USE_NONE;
  hb_glyph_info_t *info = buffer->info;
  foreach_syllable (buffer, start, end)
  {
    use_syllable_type_t syllable_type = (use_syllable_type_t) (info[start].syllable() & 0x0F);
    switch (syllable_type)
    {
      case use_independent_cluster:
      case use_symbol_cluster:
      case use_non_cluster:
	/* These don't join.  Nothing to do. */
	last_form = _USE_NONE;
	break;

      case use_virama_terminated_cluster:
      case use_sakot_terminated_cluster:
      case use_standard_cluster:
      case use_number_joiner_terminated_cluster:
      case use_numeral_cluster:
      case use_broken_cluster:

	bool join = last_form == USE_FINA || last_form == USE_ISOL;

	if (join)
	{
	  /* Fixup previous syllable's form. */
	  last_form = last_form == USE_FINA ? USE_MEDI : USE_INIT;
	  for (unsigned int i = last_start; i < start; i++)
	    info[i].mask = (info[i].mask & other_masks) | masks[last_form];
	}

	/* Form for this syllable. */
	last_form = join ? USE_FINA : USE_ISOL;
	for (unsigned int i = start; i < end; i++)
	  info[i].mask = (info[i].mask & other_masks) | masks[last_form];

	break;
    }

    last_start = start;
  }
}

static void
setup_syllables_use (const hb_ot_shape_plan_t *plan,
		     hb_font_t *font HB_UNUSED,
		     hb_buffer_t *buffer)
{
  find_syllables_use (buffer);
  foreach_syllable (buffer, start, end)
    buffer->unsafe_to_break (start, end);
  setup_rphf_mask (plan, buffer);
  setup_topographical_masks (plan, buffer);
}

static void
record_rphf_use (const hb_ot_shape_plan_t *plan,
		 hb_font_t *font HB_UNUSED,
		 hb_buffer_t *buffer)
{
  const use_shape_plan_t *use_plan = (const use_shape_plan_t *) plan->data;

  hb_mask_t mask = use_plan->rphf_mask;
  if (!mask) return;
  hb_glyph_info_t *info = buffer->info;

  foreach_syllable (buffer, start, end)
  {
    /* Mark a substituted repha as USE_R. */
    for (unsigned int i = start; i < end && (info[i].mask & mask); i++)
      if (_hb_glyph_info_substituted (&info[i]))
      {
	info[i].use_category() = USE_R;
	break;
      }
  }
}

static void
record_pref_use (const hb_ot_shape_plan_t *plan HB_UNUSED,
		 hb_font_t *font HB_UNUSED,
		 hb_buffer_t *buffer)
{
  hb_glyph_info_t *info = buffer->info;

  foreach_syllable (buffer, start, end)
  {
    /* Mark a substituted pref as VPre, as they behave the same way. */
    for (unsigned int i = start; i < end; i++)
      if (_hb_glyph_info_substituted (&info[i]))
      {
	info[i].use_category() = USE_VPre;
	break;
      }
  }
}

static inline bool
is_halant_use (const hb_glyph_info_t &info)
{
  return (info.use_category() == USE_H || info.use_category() == USE_HVM) &&
	 !_hb_glyph_info_ligated (&info);
}

static void
reorder_syllable_use (hb_buffer_t *buffer, unsigned int start, unsigned int end)
{
  use_syllable_type_t syllable_type = (use_syllable_type_t) (buffer->info[start].syllable() & 0x0F);
  /* Only a few syllable types need reordering. */
  if (unlikely (!(FLAG_UNSAFE (syllable_type) &
		  (FLAG (use_virama_terminated_cluster) |
		   FLAG (use_sakot_terminated_cluster) |
		   FLAG (use_standard_cluster) |
		   FLAG (use_broken_cluster) |
		   0))))
    return;

  hb_glyph_info_t *info = buffer->info;

#define POST_BASE_FLAGS64 (FLAG64 (USE_FM) | \
			   FLAG64 (USE_FAbv) | \
			   FLAG64 (USE_FBlw) | \
			   FLAG64 (USE_FPst) | \
			   FLAG64 (USE_MAbv) | \
			   FLAG64 (USE_MBlw) | \
			   FLAG64 (USE_MPst) | \
			   FLAG64 (USE_MPre) | \
			   FLAG64 (USE_VAbv) | \
			   FLAG64 (USE_VBlw) | \
			   FLAG64 (USE_VPst) | \
			   FLAG64 (USE_VPre) | \
			   FLAG64 (USE_VMAbv) | \
			   FLAG64 (USE_VMBlw) | \
			   FLAG64 (USE_VMPst) | \
			   FLAG64 (USE_VMPre))

  /* Move things forward. */
  if (info[start].use_category() == USE_R && end - start > 1)
  {
    /* Got a repha.  Reorder it towards the end, but before the first post-base
     * glyph. */
    for (unsigned int i = start + 1; i < end; i++)
    {
      bool is_post_base_glyph = (FLAG64_UNSAFE (info[i].use_category()) & POST_BASE_FLAGS64) ||
				is_halant_use (info[i]);
      if (is_post_base_glyph || i == end - 1)
      {
	/* If we hit a post-base glyph, move before it; otherwise move to the
	 * end. Shift things in between backward. */

	if (is_post_base_glyph)
	  i--;

	buffer->merge_clusters (start, i + 1);
	hb_glyph_info_t t = info[start];
	memmove (&info[start], &info[start + 1], (i - start) * sizeof (info[0]));
	info[i] = t;

	break;
      }
    }
  }

  /* Move things back. */
  unsigned int j = start;
  for (unsigned int i = start; i < end; i++)
  {
    uint32_t flag = FLAG_UNSAFE (info[i].use_category());
    if (is_halant_use (info[i]))
    {
      /* If we hit a halant, move after it; otherwise move to the beginning, and
       * shift things in between forward. */
      j = i + 1;
    }
    else if (((flag) & (FLAG (USE_VPre) | FLAG (USE_VMPre))) &&
	     /* Only move the first component of a MultipleSubst. */
	     0 == _hb_glyph_info_get_lig_comp (&info[i]) &&
	     j < i)
    {
      buffer->merge_clusters (j, i + 1);
      hb_glyph_info_t t = info[i];
      memmove (&info[j + 1], &info[j], (i - j) * sizeof (info[0]));
      info[j] = t;
    }
  }
}

static inline void
insert_dotted_circles_use (const hb_ot_shape_plan_t *plan HB_UNUSED,
			   hb_font_t *font,
			   hb_buffer_t *buffer)
{
  if (unlikely (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE))
    return;

  /* Note: This loop is extra overhead, but should not be measurable.
   * TODO Use a buffer scratch flag to remove the loop. */
  bool has_broken_syllables = false;
  unsigned int count = buffer->len;
  hb_glyph_info_t *info = buffer->info;
  for (unsigned int i = 0; i < count; i++)
    if ((info[i].syllable() & 0x0F) == use_broken_cluster)
    {
      has_broken_syllables = true;
      break;
    }
  if (likely (!has_broken_syllables))
    return;

  hb_glyph_info_t dottedcircle = {0};
  if (!font->get_nominal_glyph (0x25CCu, &dottedcircle.codepoint))
    return;
  dottedcircle.use_category() = hb_use_get_category (0x25CC);

  buffer->clear_output ();

  buffer->idx = 0;
  unsigned int last_syllable = 0;
  while (buffer->idx < buffer->len && buffer->successful)
  {
    unsigned int syllable = buffer->cur().syllable();
    use_syllable_type_t syllable_type = (use_syllable_type_t) (syllable & 0x0F);
    if (unlikely (last_syllable != syllable && syllable_type == use_broken_cluster))
    {
      last_syllable = syllable;

      hb_glyph_info_t ginfo = dottedcircle;
      ginfo.cluster = buffer->cur().cluster;
      ginfo.mask = buffer->cur().mask;
      ginfo.syllable() = buffer->cur().syllable();

      /* Insert dottedcircle after possible Repha. */
      while (buffer->idx < buffer->len && buffer->successful &&
	     last_syllable == buffer->cur().syllable() &&
	     buffer->cur().use_category() == USE_R)
	buffer->next_glyph ();

      buffer->output_info (ginfo);
    }
    else
      buffer->next_glyph ();
  }
  buffer->swap_buffers ();
}

static void
reorder_use (const hb_ot_shape_plan_t *plan,
	     hb_font_t *font,
	     hb_buffer_t *buffer)
{
  insert_dotted_circles_use (plan, font, buffer);

  foreach_syllable (buffer, start, end)
    reorder_syllable_use (buffer, start, end);

  HB_BUFFER_DEALLOCATE_VAR (buffer, use_category);
}

static void
preprocess_text_use (const hb_ot_shape_plan_t *plan,
		     hb_buffer_t              *buffer,
		     hb_font_t                *font)
{
  _hb_preprocess_text_vowel_constraints (plan, buffer, font);
}

static bool
compose_use (const hb_ot_shape_normalize_context_t *c,
	     hb_codepoint_t  a,
	     hb_codepoint_t  b,
	     hb_codepoint_t *ab)
{
  /* Avoid recomposing split matras. */
  if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (c->unicode->general_category (a)))
    return false;

  return (bool)c->unicode->compose (a, b, ab);
}

const hb_ot_complex_shaper_t _hb_ot_complex_shaper_use =
{
  collect_features_use,
  nullptr, /* override_features */
  data_create_use,
  data_destroy_use,
  preprocess_text_use,
  nullptr, /* postprocess_glyphs */
  HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
  nullptr, /* decompose */
  compose_use,
  setup_masks_use,
  HB_TAG_NONE, /* gpos_tag */
  nullptr, /* reorder_marks */
  HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY,
  false, /* fallback_position */
};

#endif


text:
/*
 * Copyright © 2009,2010  Red Hat, Inc.
 * Copyright © 2010,2011,2013  Google, Inc.
 *
 *  This is part of HarfBuzz, a text shaping library.
 *
 * 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
 */

#include "hb.hh"

#ifndef HB_NO_AAT_SHAPE

#include "hb-aat-map.hh"

#include "hb-aat-layout.hh"
#include "hb-aat-layout-feat-table.hh"

void hb_aat_map_builder_t::add_feature (hb_tag_t tag, unsigned value)
{
  if (!face->table.feat->has_data ()) return;

  if (tag == HB_TAG ('a','a','l','t'))
  {
    if (!face->table.feat->exposes_feature (HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES))
      return;
    feature_info_t *info = features.push();
    info->type = HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES;
    info->setting = (hb_aat_layout_feature_selector_t) value;
    info->seq = features.length;
    info->is_exclusive = true;
    return;
  }

  const hb_aat_feature_mapping_t *mapping = hb_aat_layout_find_feature_mapping (tag);
  if (!mapping) return;

  const AAT::FeatureName* feature = &face->table.feat->get_feature (mapping->aatFeatureType);
  if (!feature->has_data ())
  {
    /* Special case: Chain::compile_flags will fall back to the deprecated version of
     * small-caps if necessary, so we need to check for that possibility.
     * https://github.com/harfbuzz/harfbuzz/issues/2307 */
    if (mapping->aatFeatureType == HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE &&
	mapping->selectorToEnable == HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS)
    {
      feature = &face->table.feat->get_feature (HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE);
      if (!feature->has_data ()) return;
    }
    else return;
  }

  feature_info_t *info = features.push();
  info->type = mapping->aatFeatureType;
  info->setting = value ? mapping->selectorToEnable : mapping->selectorToDisable;
  info->seq = features.length;
  info->is_exclusive = feature->is_exclusive ();
}

void
hb_aat_map_builder_t::compile (hb_aat_map_t  &m)
{
  /* Sort features and merge duplicates */
  if (features.length)
  {
    features.qsort ();
    unsigned int j = 0;
    for (unsigned int i = 1; i < features.length; i++)
      if (features[i].type != features[j].type ||
	  /* Nonexclusive feature selectors come in even/odd pairs to turn a setting on/off
	   * respectively, so we mask out the low-order bit when checking for "duplicates"
	   * (selectors referring to the same feature setting) here. */
	  (!features[i].is_exclusive && ((features[i].setting & ~1) != (features[j].setting & ~1))))
	features[++j] = features[i];
    features.shrink (j + 1);
  }

  hb_aat_layout_compile_map (this, &m);
}

#endif


text:
/*
 * Copyright © 2014  Google, Inc.
 *
 *  This is part of HarfBuzz, a text shaping library.
 *
 * 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.
 *
 * Google Author(s): Behdad Esfahbod, Roozbeh Pournader
 */

#ifndef HB_OT_H_IN
#error "Include <hb-ot.h> instead."
#endif

#ifndef HB_OT_FONT_H
#define HB_OT_FONT_H

#include "hb.h"

HB_BEGIN_DECLS

HB_EXTERN void
hb_ot_font_set_funcs (hb_font_t *font);

HB_END_DECLS

#endif /* HB_OT_FONT_H */


text:
/*
 * Copyright © 2007,2008,2009  Red Hat, Inc.
 * Copyright © 2012,2013  Google, Inc.
 *
 *  This is part of HarfBuzz, a text shaping library.
 *
 * 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
 */

#ifndef HB_OT_LAYOUT_HH
#define HB_OT_LAYOUT_HH

#include "hb.hh"

#include "hb-font.hh"
#include "hb-buffer.hh"
#include "hb-open-type.hh"
#include "hb-ot-shape.hh"
#include "hb-set-digest.hh"

struct hb_ot_shape_plan_t;

/*
 * kern
 */

HB_INTERNAL bool
hb_ot_layout_has_kerning (hb_face_t *face);

HB_INTERNAL bool
hb_ot_layout_has_machine_kerning (hb_face_t *face);

HB_INTERNAL bool
hb_ot_layout_has_cross_kerning (hb_face_t *face);

HB_INTERNAL void
hb_ot_layout_kern (const hb_ot_shape_plan_t *plan,
		   hb_font_t *font,
		   hb_buffer_t  *buffer);

/* Private API corresponding to hb-ot-layout.h: */

HB_INTERNAL bool
hb_ot_layout_table_find_feature (hb_face_t    *face,
				 hb_tag_t      table_tag,
				 hb_tag_t      feature_tag,
				 unsigned int *feature_index);

/*
 * GDEF
 */

enum hb_ot_layout_glyph_props_flags_t
{
  /* The following three match LookupFlags::Ignore* numbers. */
  HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH	= 0x02u,
  HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE	= 0x04u,
  HB_OT_LAYOUT_GLYPH_PROPS_MARK		= 0x08u,

  HB_OT_LAYOUT_GLYPH_PROPS_CLASS_MASK   = HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH |
					  HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE |
					  HB_OT_LAYOUT_GLYPH_PROPS_MARK,

  /* The following are used internally; not derived from GDEF. */
  HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED	= 0x10u,
  HB_OT_LAYOUT_GLYPH_PROPS_LIGATED	= 0x20u,
  HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED	= 0x40u,
};
HB_MARK_AS_FLAG_T (hb_ot_layout_glyph_props_flags_t);

/*
 * GSUB/GPOS
 */

/* Should be called before all the substitute_lookup's are done. */
HB_INTERNAL void
hb_ot_layout_substitute_start (hb_font_t    *font,
			       hb_buffer_t  *buffer);

HB_INTERNAL void
hb_ot_layout_delete_glyphs_inplace (hb_buffer_t *buffer,
				    bool (*filter) (const hb_glyph_info_t *info));

namespace OT {
  struct hb_ot_apply_context_t;
  struct SubstLookup;
  struct hb_ot_layout_lookup_accelerator_t;
}

HB_INTERNAL void
hb_ot_layout_substitute_lookup (OT::hb_ot_apply_context_t *c,
				const OT::SubstLookup &lookup,
				const OT::hb_ot_layout_lookup_accelerator_t &accel);

/* Should be called before all the position_lookup's are done. */
HB_INTERNAL void
hb_ot_layout_position_start (hb_font_t    *font,
			     hb_buffer_t  *buffer);

/* Should be called after all the position_lookup's are done, to fini advances. */
HB_INTERNAL void
hb_ot_layout_position_finish_advances (hb_font_t    *font,
				       hb_buffer_t  *buffer);

/* Should be called after hb_ot_layout_position_finish_advances, to fini offsets. */
HB_INTERNAL void
hb_ot_layout_position_finish_offsets (hb_font_t    *font,
				      hb_buffer_t  *buffer);

/*
 * Buffer var routines.
 */

/* buffer var allocations, used during the entire shaping process */
#define unicode_props()		var2.u16[0]

/* buffer var allocations, used during the GSUB/GPOS processing */
#define glyph_props()		var1.u16[0] /* GDEF glyph properties */
#define lig_props()		var1.u8[2] /* GSUB/GPOS ligature tracking */
#define syllable()		var1.u8[3] /* GSUB/GPOS shaping boundaries */

/* Loop over syllables. Based on foreach_cluster(). */
#define foreach_syllable(buffer, start, end) \
  for (unsigned int \
       _count = buffer->len, \
       start = 0, end = _count ? _hb_next_syllable (buffer, 0) : 0; \
       start < _count; \
       start = end, end = _hb_next_syllable (buffer, start))

static inline unsigned int
_hb_next_syllable (hb_buffer_t *buffer, unsigned int start)
{
  hb_glyph_info_t *info = buffer->info;
  unsigned int count = buffer->len;

  unsigned int syllable = info[start].syllable();
  while (++start < count && syllable == info[start].syllable())
    ;

  return start;
}

static inline void
_hb_clear_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
		     hb_font_t *font HB_UNUSED,
		     hb_buffer_t *buffer)
{
  hb_glyph_info_t *info = buffer->info;
  unsigned int count = buffer->len;
  for (unsigned int i = 0; i < count; i++)
    info[i].syllable() = 0;
}

/* unicode_props */

/* Design:
 * unicode_props() is a two-byte number.  The low byte includes:
 * - General_Category: 5 bits.
 * - A bit each for:
 *   * Is it Default_Ignorable(); we have a modified Default_Ignorable().
 *   * Whether it's one of the three Mongolian Free Variation Selectors,
 *     CGJ, or other characters that are hidden but should not be ignored
 *     like most other Default_Ignorable()s do during matching.
 *   * Whether it's a grapheme continuation.
 *
 * The high-byte has different meanings, switched by the Gen-Cat:
 * - For Mn,Mc,Me: the modified Combining_Class.
 * - For Cf: whether it's ZWJ, ZWNJ, or something else.
 * - For Ws: index of which space character this is, if space fallback
 *   is needed, ie. we don't set this by default, only if asked to.
 */

enum hb_unicode_props_flags_t {
  UPROPS_MASK_GEN_CAT	= 0x001Fu,
  UPROPS_MASK_IGNORABLE	= 0x0020u,
  UPROPS_MASK_HIDDEN	= 0x0040u, /* MONGOLIAN FREE VARIATION SELECTOR 1..3, or TAG characters */
  UPROPS_MASK_CONTINUATION=0x0080u,

  /* If GEN_CAT=FORMAT, top byte masks: */
  UPROPS_MASK_Cf_ZWJ	= 0x0100u,
  UPROPS_MASK_Cf_ZWNJ	= 0x0200u
};
HB_MARK_AS_FLAG_T (hb_unicode_props_flags_t);

static inline void
_hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_buffer_t *buffer)
{
  hb_unicode_funcs_t *unicode = buffer->unicode;
  unsigned int u = info->codepoint;
  unsigned int gen_cat = (unsigned int) unicode->general_category (u);
  unsigned int props = gen_cat;

  if (u >= 0x80u)
  {
    buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII;

    if (unlikely (unicode->is_default_ignorable (u)))
    {
      buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES;
      props |=  UPROPS_MASK_IGNORABLE;
      if (u == 0x200Cu) props |= UPROPS_MASK_Cf_ZWNJ;
      else if (u == 0x200Du) props |= UPROPS_MASK_Cf_ZWJ;
      /* Mongolian Free Variation Selectors need to be remembered
       * because although we need to hide them like default-ignorables,
       * they need to non-ignorable during shaping.  This is similar to
       * what we do for joiners in Indic-like shapers, but since the
       * FVSes are GC=Mn, we have use a separate bit to remember them.
       * Fixes:
       * https://github.com/harfbuzz/harfbuzz/issues/234 */
      else if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x180Bu, 0x180Du))) props |= UPROPS_MASK_HIDDEN;
      /* TAG characters need similar treatment. Fixes:
       * https://github.com/harfbuzz/harfbuzz/issues/463 */
      else if (unlikely (hb_in_range<hb_codepoint_t> (u, 0xE0020u, 0xE007Fu))) props |= UPROPS_MASK_HIDDEN;
      /* COMBINING GRAPHEME JOINER should not be skipped; at least some times.
       * https://github.com/harfbuzz/harfbuzz/issues/554 */
      else if (unlikely (u == 0x034Fu))
      {
	buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_CGJ;
	props |= UPROPS_MASK_HIDDEN;
      }
    }

    if (unlikely (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (gen_cat)))
    {
      props |= UPROPS_MASK_CONTINUATION;
      props |= unicode->modified_combining_class (u)<<8;
    }
  }

  info->unicode_props() = props;
}

static inline void
_hb_glyph_info_set_general_category (hb_glyph_info_t *info,
				     hb_unicode_general_category_t gen_cat)
{
  /* Clears top-byte. */
  info->unicode_props() = (unsigned int) gen_cat | (info->unicode_props() & (0xFF & ~UPROPS_MASK_GEN_CAT));
}

static inline hb_unicode_general_category_t
_hb_glyph_info_get_general_category (const hb_glyph_info_t *info)
{
  return (hb_unicode_general_category_t) (info->unicode_props() & UPROPS_MASK_GEN_CAT);
}

static inline bool
_hb_glyph_info_is_unicode_mark (const hb_glyph_info_t *info)
{
  return HB_UNICODE_GENERAL_CATEGORY_IS_MARK (info->unicode_props() & UPROPS_MASK_GEN_CAT);
}
static inline void
_hb_glyph_info_set_modified_combining_class (hb_glyph_info_t *info,
					     unsigned int modified_class)
{
  if (unlikely (!_hb_glyph_info_is_unicode_mark (info)))
    return;
  info->unicode_props() = (modified_class<<8) | (info->unicode_props() & 0xFF);
}
static inline unsigned int
_hb_glyph_info_get_modified_combining_class (const hb_glyph_info_t *info)
{
  return _hb_glyph_info_is_unicode_mark (info) ? info->unicode_props()>>8 : 0;
}
#define info_cc(info) (_hb_glyph_info_get_modified_combining_class (&(info)))

static inline bool
_hb_glyph_info_is_unicode_space (const hb_glyph_info_t *info)
{
  return _hb_glyph_info_get_general_category (info) ==
	 HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR;
}
static inline void
_hb_glyph_info_set_unicode_space_fallback_type (hb_glyph_info_t *info, hb_unicode_funcs_t::space_t s)
{
  if (unlikely (!_hb_glyph_info_is_unicode_space (info)))
    return;
  info->unicode_props() = (((unsigned int) s)<<8) | (info->unicode_props() & 0xFF);
}
static inline hb_unicode_funcs_t::space_t
_hb_glyph_info_get_unicode_space_fallback_type (const hb_glyph_info_t *info)
{
  return _hb_glyph_info_is_unicode_space (info) ?
	 (hb_unicode_funcs_t::space_t) (info->unicode_props()>>8) :
	 hb_unicode_funcs_t::NOT_SPACE;
}

static inline bool _hb_glyph_info_ligated (const hb_glyph_info_t *info);

static inline bool
_hb_glyph_info_is_default_ignorable (const hb_glyph_info_t *info)
{
  return (info->unicode_props() & UPROPS_MASK_IGNORABLE) &&
	 !_hb_glyph_info_ligated (info);
}
static inline bool
_hb_glyph_info_is_default_ignorable_and_not_hidden (const hb_glyph_info_t *info)
{
  return ((info->unicode_props() & (UPROPS_MASK_IGNORABLE|UPROPS_MASK_HIDDEN))
	  == UPROPS_MASK_IGNORABLE) &&
	 !_hb_glyph_info_ligated (info);
}
static inline void
_hb_glyph_info_unhide (hb_glyph_info_t *info)
{
  info->unicode_props() &= ~ UPROPS_MASK_HIDDEN;
}

static inline void
_hb_glyph_info_set_continuation (hb_glyph_info_t *info)
{
  info->unicode_props() |= UPROPS_MASK_CONTINUATION;
}
static inline void
_hb_glyph_info_reset_continuation (hb_glyph_info_t *info)
{
  info->unicode_props() &= ~ UPROPS_MASK_CONTINUATION;
}
static inline bool
_hb_glyph_info_is_continuation (const hb_glyph_info_t *info)
{
  return info->unicode_props() & UPROPS_MASK_CONTINUATION;
}
/* Loop over grapheme. Based on foreach_cluster(). */
#define foreach_grapheme(buffer, start, end) \
  for (unsigned int \
       _count = buffer->len, \
       start = 0, end = _count ? _hb_next_grapheme (buffer, 0) : 0; \
       start < _count; \
       start = end, end = _hb_next_grapheme (buffer, start))

static inline unsigned int
_hb_next_grapheme (hb_buffer_t *buffer, unsigned int start)
{
  hb_glyph_info_t *info = buffer->info;
  unsigned int count = buffer->len;

  while (++start < count && _hb_glyph_info_is_continuation (&info[start]))
    ;

  return start;
}

static inline bool
_hb_glyph_info_is_unicode_format (const hb_glyph_info_t *info)
{
  return _hb_glyph_info_get_general_category (info) ==
	 HB_UNICODE_GENERAL_CATEGORY_FORMAT;
}
static inline bool
_hb_glyph_info_is_zwnj (const hb_glyph_info_t *info)
{
  return _hb_glyph_info_is_unicode_format (info) && (info->unicode_props() & UPROPS_MASK_Cf_ZWNJ);
}
static inline bool
_hb_glyph_info_is_zwj (const hb_glyph_info_t *info)
{
  return _hb_glyph_info_is_unicode_format (info) && (info->unicode_props() & UPROPS_MASK_Cf_ZWJ);
}
static inline bool
_hb_glyph_info_is_joiner (const hb_glyph_info_t *info)
{
  return _hb_glyph_info_is_unicode_format (info) && (info->unicode_props() & (UPROPS_MASK_Cf_ZWNJ|UPROPS_MASK_Cf_ZWJ));
}
static inline void
_hb_glyph_info_flip_joiners (hb_glyph_info_t *info)
{
  if (!_hb_glyph_info_is_unicode_format (info))
    return;
  info->unicode_props() ^= UPROPS_MASK_Cf_ZWNJ | UPROPS_MASK_Cf_ZWJ;
}

/* lig_props: aka lig_id / lig_comp
 *
 * When a ligature is formed:
 *
 *   - The ligature glyph and any marks in between all the same newly allocated
 *     lig_id,
 *   - The ligature glyph will get lig_num_comps set to the number of components
 *   - The marks get lig_comp > 0, reflecting which component of the ligature
 *     they were applied to.
 *   - This is used in GPOS to attach marks to the right component of a ligature
 *     in MarkLigPos,
 *   - Note that when marks are ligated together, much of the above is skipped
 *     and the current lig_id reused.
 *
 * When a multiple-substitution is done:
 *
 *   - All resulting glyphs will have lig_id = 0,
 *   - The resulting glyphs will have lig_comp = 0, 1, 2, ... respectively.
 *   - This is used in GPOS to attach marks to the first component of a
 *     multiple substitution in MarkBasePos.
 *
 * The numbers are also used in GPOS to do mark-to-mark positioning only
 * to marks that belong to the same component of the same ligature.
 */

static inline void
_hb_glyph_info_clear_lig_props (hb_glyph_info_t *info)
{
  info->lig_props() = 0;
}

#define IS_LIG_BASE 0x10

static inline void
_hb_glyph_info_set_lig_props_for_ligature (hb_glyph_info_t *info,
					   unsigned int lig_id,
					   unsigned int lig_num_comps)
{
  info->lig_props() = (lig_id << 5) | IS_LIG_BASE | (lig_num_comps & 0x0F);
}

static inline void
_hb_glyph_info_set_lig_props_for_mark (hb_glyph_info_t *info,
				       unsigned int lig_id,
				       unsigned int lig_comp)
{
  info->lig_props() = (lig_id << 5) | (lig_comp & 0x0F);
}

static inline void
_hb_glyph_info_set_lig_props_for_component (hb_glyph_info_t *info, unsigned int comp)
{
  _hb_glyph_info_set_lig_props_for_mark (info, 0, comp);
}

static inline unsigned int
_hb_glyph_info_get_lig_id (const hb_glyph_info_t *info)
{
  return info->lig_props() >> 5;
}

static inline bool
_hb_glyph_info_ligated_internal (const hb_glyph_info_t *info)
{
  return !!(info->lig_props() & IS_LIG_BASE);
}

static inline unsigned int
_hb_glyph_info_get_lig_comp (const hb_glyph_info_t *info)
{
  if (_hb_glyph_info_ligated_internal (info))
    return 0;
  else
    return info->lig_props() & 0x0F;
}

static inline unsigned int
_hb_glyph_info_get_lig_num_comps (const hb_glyph_info_t *info)
{
  if ((info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE) &&
      _hb_glyph_info_ligated_internal (info))
    return info->lig_props() & 0x0F;
  else
    return 1;
}

static inline uint8_t
_hb_allocate_lig_id (hb_buffer_t *buffer) {
  uint8_t lig_id = buffer->next_serial () & 0x07;
  if (unlikely (!lig_id))
    lig_id = _hb_allocate_lig_id (buffer); /* in case of overflow */
  return lig_id;
}

/* glyph_props: */

static inline void
_hb_glyph_info_set_glyph_props (hb_glyph_info_t *info, unsigned int props)
{
  info->glyph_props() = props;
}

static inline unsigned int
_hb_glyph_info_get_glyph_props (const hb_glyph_info_t *info)
{
  return info->glyph_props();
}

static inline bool
_hb_glyph_info_is_base_glyph (const hb_glyph_info_t *info)
{
  return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH);
}

static inline bool
_hb_glyph_info_is_ligature (const hb_glyph_info_t *info)
{
  return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE);
}

static inline bool
_hb_glyph_info_is_mark (const hb_glyph_info_t *info)
{
  return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK);
}

static inline bool
_hb_glyph_info_substituted (const hb_glyph_info_t *info)
{
  return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED);
}

static inline bool
_hb_glyph_info_ligated (const hb_glyph_info_t *info)
{
  return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATED);
}

static inline bool
_hb_glyph_info_multiplied (const hb_glyph_info_t *info)
{
  return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED);
}

static inline bool
_hb_glyph_info_ligated_and_didnt_multiply (const hb_glyph_info_t *info)
{
  return _hb_glyph_info_ligated (info) && !_hb_glyph_info_multiplied (info);
}

static inline void
_hb_glyph_info_clear_ligated_and_multiplied (hb_glyph_info_t *info)
{
  info->glyph_props() &= ~(HB_OT_LAYOUT_GLYPH_PROPS_LIGATED |
			   HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED);
}

static inline void
_hb_glyph_info_clear_substituted (hb_glyph_info_t *info)
{
  info->glyph_props() &= ~(HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED);
}

static inline void
_hb_clear_substitution_flags (const hb_ot_shape_plan_t *plan HB_UNUSED,
			      hb_font_t *font HB_UNUSED,
			      hb_buffer_t *buffer)
{
  hb_glyph_info_t *info = buffer->info;
  unsigned int count = buffer->len;
  for (unsigned int i = 0; i < count; i++)
    _hb_glyph_info_clear_substituted (&info[i]);
}

/* Allocation / deallocation. */

static inline void
_hb_buffer_allocate_unicode_vars (hb_buffer_t *buffer)
{
  HB_BUFFER_ALLOCATE_VAR (buffer, unicode_props);
}

static inline void
_hb_buffer_deallocate_unicode_vars (hb_buffer_t *buffer)
{
  HB_BUFFER_DEALLOCATE_VAR (buffer, unicode_props);
}

static inline void
_hb_buffer_assert_unicode_vars (hb_buffer_t *buffer)
{
  HB_BUFFER_ASSERT_VAR (buffer, unicode_props);
}

static inline void
_hb_buffer_allocate_gsubgpos_vars (hb_buffer_t *buffer)
{
  HB_BUFFER_ALLOCATE_VAR (buffer, glyph_props);
  HB_BUFFER_ALLOCATE_VAR (buffer, lig_props);
  HB_BUFFER_ALLOCATE_VAR (buffer, syllable);
}

static inline void
_hb_buffer_deallocate_gsubgpos_vars (hb_buffer_t *buffer)
{
  HB_BUFFER_DEALLOCATE_VAR (buffer, syllable);
  HB_BUFFER_DEALLOCATE_VAR (buffer, lig_props);
  HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_props);
}

static inline void
_hb_buffer_assert_gsubgpos_vars (hb_buffer_t *buffer)
{
  HB_BUFFER_ASSERT_VAR (buffer, glyph_props);
  HB_BUFFER_ASSERT_VAR (buffer, lig_props);
  HB_BUFFER_ASSERT_VAR (buffer, syllable);
}

/* Make sure no one directly touches our props... */
#undef unicode_props0
#undef unicode_props1
#undef lig_props
#undef glyph_props

#endif /* HB_OT_LAYOUT_HH */