text:
/*
 * Copyright © 2007,2008,2009  Red Hat, Inc.
 * 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.
 *
 * Red Hat Author(s): Behdad Esfahbod
 * Google Author(s): Behdad Esfahbod
 */

#ifndef HB_H_IN
#error "Include <hb.h> instead."
#endif

#ifndef HB_COMMON_H
#define HB_COMMON_H

#ifndef HB_EXTERN
#define HB_EXTERN extern
#endif

#ifndef HB_BEGIN_DECLS
# ifdef __cplusplus
#  define HB_BEGIN_DECLS	extern "C" {
#  define HB_END_DECLS		}
# else /* !__cplusplus */
#  define HB_BEGIN_DECLS
#  define HB_END_DECLS
# endif /* !__cplusplus */
#endif

#if defined (_SVR4) || defined (SVR4) || defined (__OpenBSD__) || \
    defined (_sgi) || defined (__sun) || defined (sun) || \
    defined (__digital__) || defined (__HP_cc)
#  include <inttypes.h>
#elif defined (_AIX)
#  include <sys/inttypes.h>
#elif defined (_MSC_VER) && _MSC_VER < 1600
/* VS 2010 (_MSC_VER 1600) has stdint.h */
typedef __int8 int8_t;
typedef unsigned __int8 uint8_t;
typedef __int16 int16_t;
typedef unsigned __int16 uint16_t;
typedef __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
#elif defined (__KERNEL__)
#  include <linux/types.h>
#else
#  include <stdint.h>
#endif

#if defined(__GNUC__) && ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
#define HB_DEPRECATED __attribute__((__deprecated__))
#elif defined(_MSC_VER) && (_MSC_VER >= 1300)
#define HB_DEPRECATED __declspec(deprecated)
#else
#define HB_DEPRECATED
#endif

#if defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))
#define HB_DEPRECATED_FOR(f) __attribute__((__deprecated__("Use '" #f "' instead")))
#elif defined(_MSC_FULL_VER) && (_MSC_FULL_VER > 140050320)
#define HB_DEPRECATED_FOR(f) __declspec(deprecated("is deprecated. Use '" #f "' instead"))
#else
#define HB_DEPRECATED_FOR(f) HB_DEPRECATED
#endif

HB_BEGIN_DECLS

typedef int hb_bool_t;

typedef uint32_t hb_codepoint_t;
typedef int32_t hb_position_t;
typedef uint32_t hb_mask_t;

typedef union _hb_var_int_t {
  uint32_t u32;
  int32_t i32;
  uint16_t u16[2];
  int16_t i16[2];
  uint8_t u8[4];
  int8_t i8[4];
} hb_var_int_t;

/* hb_tag_t */

typedef uint32_t hb_tag_t;

#define HB_TAG(c1,c2,c3,c4) ((hb_tag_t)((((uint32_t)(c1)&0xFF)<<24)|(((uint32_t)(c2)&0xFF)<<16)|(((uint32_t)(c3)&0xFF)<<8)|((uint32_t)(c4)&0xFF)))
#define HB_UNTAG(tag)   (uint8_t)(((tag)>>24)&0xFF), (uint8_t)(((tag)>>16)&0xFF), (uint8_t)(((tag)>>8)&0xFF), (uint8_t)((tag)&0xFF)

#define HB_TAG_NONE HB_TAG(0,0,0,0)
#define HB_TAG_MAX HB_TAG(0xff,0xff,0xff,0xff)
#define HB_TAG_MAX_SIGNED HB_TAG(0x7f,0xff,0xff,0xff)

/* len=-1 means str is NUL-terminated. */
HB_EXTERN hb_tag_t
hb_tag_from_string (const char *str, int len);

/* buf should have 4 bytes. */
HB_EXTERN void
hb_tag_to_string (hb_tag_t tag, char *buf);

/**
 * hb_direction_t:
 * @HB_DIRECTION_INVALID: Initial, unset direction.
 * @HB_DIRECTION_LTR: Text is set horizontally from left to right.
 * @HB_DIRECTION_RTL: Text is set horizontally from right to left.
 * @HB_DIRECTION_TTB: Text is set vertically from top to bottom.
 * @HB_DIRECTION_BTT: Text is set vertically from bottom to top.
 */
typedef enum {
  HB_DIRECTION_INVALID = 0,
  HB_DIRECTION_LTR = 4,
  HB_DIRECTION_RTL,
  HB_DIRECTION_TTB,
  HB_DIRECTION_BTT
} hb_direction_t;

/* len=-1 means str is NUL-terminated */
HB_EXTERN hb_direction_t
hb_direction_from_string (const char *str, int len);

HB_EXTERN const char *
hb_direction_to_string (hb_direction_t direction);

#define HB_DIRECTION_IS_VALID(dir)	((((unsigned int) (dir)) & ~3U) == 4)
/* Direction must be valid for the following */
#define HB_DIRECTION_IS_HORIZONTAL(dir)	((((unsigned int) (dir)) & ~1U) == 4)
#define HB_DIRECTION_IS_VERTICAL(dir)	((((unsigned int) (dir)) & ~1U) == 6)
#define HB_DIRECTION_IS_FORWARD(dir)	((((unsigned int) (dir)) & ~2U) == 4)
#define HB_DIRECTION_IS_BACKWARD(dir)	((((unsigned int) (dir)) & ~2U) == 5)
#define HB_DIRECTION_REVERSE(dir)	((hb_direction_t) (((unsigned int) (dir)) ^ 1))

/* hb_language_t */

typedef const struct hb_language_impl_t *hb_language_t;

HB_EXTERN hb_language_t
hb_language_from_string (const char *str, int len);

HB_EXTERN const char *
hb_language_to_string (hb_language_t language);

#define HB_LANGUAGE_INVALID ((hb_language_t) 0)

HB_EXTERN hb_language_t
hb_language_get_default (void);

/* hb_script_t */

/* https://unicode.org/iso15924/ */
/* https://docs.google.com/spreadsheets/d/1Y90M0Ie3MUJ6UVCRDOypOtijlMDLNNyyLk36T6iMu0o */
/* Unicode Character Database property: Script (sc) */
typedef enum
{
  /*1.1*/ HB_SCRIPT_COMMON			= HB_TAG ('Z','y','y','y'),
  /*1.1*/ HB_SCRIPT_INHERITED			= HB_TAG ('Z','i','n','h'),
  /*5.0*/ HB_SCRIPT_UNKNOWN			= HB_TAG ('Z','z','z','z'),

  /*1.1*/ HB_SCRIPT_ARABIC			= HB_TAG ('A','r','a','b'),
  /*1.1*/ HB_SCRIPT_ARMENIAN			= HB_TAG ('A','r','m','n'),
  /*1.1*/ HB_SCRIPT_BENGALI			= HB_TAG ('B','e','n','g'),
  /*1.1*/ HB_SCRIPT_CYRILLIC			= HB_TAG ('C','y','r','l'),
  /*1.1*/ HB_SCRIPT_DEVANAGARI			= HB_TAG ('D','e','v','a'),
  /*1.1*/ HB_SCRIPT_GEORGIAN			= HB_TAG ('G','e','o','r'),
  /*1.1*/ HB_SCRIPT_GREEK			= HB_TAG ('G','r','e','k'),
  /*1.1*/ HB_SCRIPT_GUJARATI			= HB_TAG ('G','u','j','r'),
  /*1.1*/ HB_SCRIPT_GURMUKHI			= HB_TAG ('G','u','r','u'),
  /*1.1*/ HB_SCRIPT_HANGUL			= HB_TAG ('H','a','n','g'),
  /*1.1*/ HB_SCRIPT_HAN				= HB_TAG ('H','a','n','i'),
  /*1.1*/ HB_SCRIPT_HEBREW			= HB_TAG ('H','e','b','r'),
  /*1.1*/ HB_SCRIPT_HIRAGANA			= HB_TAG ('H','i','r','a'),
  /*1.1*/ HB_SCRIPT_KANNADA			= HB_TAG ('K','n','d','a'),
  /*1.1*/ HB_SCRIPT_KATAKANA			= HB_TAG ('K','a','n','a'),
  /*1.1*/ HB_SCRIPT_LAO				= HB_TAG ('L','a','o','o'),
  /*1.1*/ HB_SCRIPT_LATIN			= HB_TAG ('L','a','t','n'),
  /*1.1*/ HB_SCRIPT_MALAYALAM			= HB_TAG ('M','l','y','m'),
  /*1.1*/ HB_SCRIPT_ORIYA			= HB_TAG ('O','r','y','a'),
  /*1.1*/ HB_SCRIPT_TAMIL			= HB_TAG ('T','a','m','l'),
  /*1.1*/ HB_SCRIPT_TELUGU			= HB_TAG ('T','e','l','u'),
  /*1.1*/ HB_SCRIPT_THAI			= HB_TAG ('T','h','a','i'),

  /*2.0*/ HB_SCRIPT_TIBETAN			= HB_TAG ('T','i','b','t'),

  /*3.0*/ HB_SCRIPT_BOPOMOFO			= HB_TAG ('B','o','p','o'),
  /*3.0*/ HB_SCRIPT_BRAILLE			= HB_TAG ('B','r','a','i'),
  /*3.0*/ HB_SCRIPT_CANADIAN_SYLLABICS		= HB_TAG ('C','a','n','s'),
  /*3.0*/ HB_SCRIPT_CHEROKEE			= HB_TAG ('C','h','e','r'),
  /*3.0*/ HB_SCRIPT_ETHIOPIC			= HB_TAG ('E','t','h','i'),
  /*3.0*/ HB_SCRIPT_KHMER			= HB_TAG ('K','h','m','r'),
  /*3.0*/ HB_SCRIPT_MONGOLIAN			= HB_TAG ('M','o','n','g'),
  /*3.0*/ HB_SCRIPT_MYANMAR			= HB_TAG ('M','y','m','r'),
  /*3.0*/ HB_SCRIPT_OGHAM			= HB_TAG ('O','g','a','m'),
  /*3.0*/ HB_SCRIPT_RUNIC			= HB_TAG ('R','u','n','r'),
  /*3.0*/ HB_SCRIPT_SINHALA			= HB_TAG ('S','i','n','h'),
  /*3.0*/ HB_SCRIPT_SYRIAC			= HB_TAG ('S','y','r','c'),
  /*3.0*/ HB_SCRIPT_THAANA			= HB_TAG ('T','h','a','a'),
  /*3.0*/ HB_SCRIPT_YI				= HB_TAG ('Y','i','i','i'),

  /*3.1*/ HB_SCRIPT_DESERET			= HB_TAG ('D','s','r','t'),
  /*3.1*/ HB_SCRIPT_GOTHIC			= HB_TAG ('G','o','t','h'),
  /*3.1*/ HB_SCRIPT_OLD_ITALIC			= HB_TAG ('I','t','a','l'),

  /*3.2*/ HB_SCRIPT_BUHID			= HB_TAG ('B','u','h','d'),
  /*3.2*/ HB_SCRIPT_HANUNOO			= HB_TAG ('H','a','n','o'),
  /*3.2*/ HB_SCRIPT_TAGALOG			= HB_TAG ('T','g','l','g'),
  /*3.2*/ HB_SCRIPT_TAGBANWA			= HB_TAG ('T','a','g','b'),

  /*4.0*/ HB_SCRIPT_CYPRIOT			= HB_TAG ('C','p','r','t'),
  /*4.0*/ HB_SCRIPT_LIMBU			= HB_TAG ('L','i','m','b'),
  /*4.0*/ HB_SCRIPT_LINEAR_B			= HB_TAG ('L','i','n','b'),
  /*4.0*/ HB_SCRIPT_OSMANYA			= HB_TAG ('O','s','m','a'),
  /*4.0*/ HB_SCRIPT_SHAVIAN			= HB_TAG ('S','h','a','w'),
  /*4.0*/ HB_SCRIPT_TAI_LE			= HB_TAG ('T','a','l','e'),
  /*4.0*/ HB_SCRIPT_UGARITIC			= HB_TAG ('U','g','a','r'),

  /*4.1*/ HB_SCRIPT_BUGINESE			= HB_TAG ('B','u','g','i'),
  /*4.1*/ HB_SCRIPT_COPTIC			= HB_TAG ('C','o','p','t'),
  /*4.1*/ HB_SCRIPT_GLAGOLITIC			= HB_TAG ('G','l','a','g'),
  /*4.1*/ HB_SCRIPT_KHAROSHTHI			= HB_TAG ('K','h','a','r'),
  /*4.1*/ HB_SCRIPT_NEW_TAI_LUE			= HB_TAG ('T','a','l','u'),
  /*4.1*/ HB_SCRIPT_OLD_PERSIAN			= HB_TAG ('X','p','e','o'),
  /*4.1*/ HB_SCRIPT_SYLOTI_NAGRI		= HB_TAG ('S','y','l','o'),
  /*4.1*/ HB_SCRIPT_TIFINAGH			= HB_TAG ('T','f','n','g'),

  /*5.0*/ HB_SCRIPT_BALINESE			= HB_TAG ('B','a','l','i'),
  /*5.0*/ HB_SCRIPT_CUNEIFORM			= HB_TAG ('X','s','u','x'),
  /*5.0*/ HB_SCRIPT_NKO				= HB_TAG ('N','k','o','o'),
  /*5.0*/ HB_SCRIPT_PHAGS_PA			= HB_TAG ('P','h','a','g'),
  /*5.0*/ HB_SCRIPT_PHOENICIAN			= HB_TAG ('P','h','n','x'),

  /*5.1*/ HB_SCRIPT_CARIAN			= HB_TAG ('C','a','r','i'),
  /*5.1*/ HB_SCRIPT_CHAM			= HB_TAG ('C','h','a','m'),
  /*5.1*/ HB_SCRIPT_KAYAH_LI			= HB_TAG ('K','a','l','i'),
  /*5.1*/ HB_SCRIPT_LEPCHA			= HB_TAG ('L','e','p','c'),
  /*5.1*/ HB_SCRIPT_LYCIAN			= HB_TAG ('L','y','c','i'),
  /*5.1*/ HB_SCRIPT_LYDIAN			= HB_TAG ('L','y','d','i'),
  /*5.1*/ HB_SCRIPT_OL_CHIKI			= HB_TAG ('O','l','c','k'),
  /*5.1*/ HB_SCRIPT_REJANG			= HB_TAG ('R','j','n','g'),
  /*5.1*/ HB_SCRIPT_SAURASHTRA			= HB_TAG ('S','a','u','r'),
  /*5.1*/ HB_SCRIPT_SUNDANESE			= HB_TAG ('S','u','n','d'),
  /*5.1*/ HB_SCRIPT_VAI				= HB_TAG ('V','a','i','i'),

  /*5.2*/ HB_SCRIPT_AVESTAN			= HB_TAG ('A','v','s','t'),
  /*5.2*/ HB_SCRIPT_BAMUM			= HB_TAG ('B','a','m','u'),
  /*5.2*/ HB_SCRIPT_EGYPTIAN_HIEROGLYPHS	= HB_TAG ('E','g','y','p'),
  /*5.2*/ HB_SCRIPT_IMPERIAL_ARAMAIC		= HB_TAG ('A','r','m','i'),
  /*5.2*/ HB_SCRIPT_INSCRIPTIONAL_PAHLAVI	= HB_TAG ('P','h','l','i'),
  /*5.2*/ HB_SCRIPT_INSCRIPTIONAL_PARTHIAN	= HB_TAG ('P','r','t','i'),
  /*5.2*/ HB_SCRIPT_JAVANESE			= HB_TAG ('J','a','v','a'),
  /*5.2*/ HB_SCRIPT_KAITHI			= HB_TAG ('K','t','h','i'),
  /*5.2*/ HB_SCRIPT_LISU			= HB_TAG ('L','i','s','u'),
  /*5.2*/ HB_SCRIPT_MEETEI_MAYEK		= HB_TAG ('M','t','e','i'),
  /*5.2*/ HB_SCRIPT_OLD_SOUTH_ARABIAN		= HB_TAG ('S','a','r','b'),
  /*5.2*/ HB_SCRIPT_OLD_TURKIC			= HB_TAG ('O','r','k','h'),
  /*5.2*/ HB_SCRIPT_SAMARITAN			= HB_TAG ('S','a','m','r'),
  /*5.2*/ HB_SCRIPT_TAI_THAM			= HB_TAG ('L','a','n','a'),
  /*5.2*/ HB_SCRIPT_TAI_VIET			= HB_TAG ('T','a','v','t'),

  /*6.0*/ HB_SCRIPT_BATAK			= HB_TAG ('B','a','t','k'),
  /*6.0*/ HB_SCRIPT_BRAHMI			= HB_TAG ('B','r','a','h'),
  /*6.0*/ HB_SCRIPT_MANDAIC			= HB_TAG ('M','a','n','d'),

  /*6.1*/ HB_SCRIPT_CHAKMA			= HB_TAG ('C','a','k','m'),
  /*6.1*/ HB_SCRIPT_MEROITIC_CURSIVE		= HB_TAG ('M','e','r','c'),
  /*6.1*/ HB_SCRIPT_MEROITIC_HIEROGLYPHS	= HB_TAG ('M','e','r','o'),
  /*6.1*/ HB_SCRIPT_MIAO			= HB_TAG ('P','l','r','d'),
  /*6.1*/ HB_SCRIPT_SHARADA			= HB_TAG ('S','h','r','d'),
  /*6.1*/ HB_SCRIPT_SORA_SOMPENG		= HB_TAG ('S','o','r','a'),
  /*6.1*/ HB_SCRIPT_TAKRI			= HB_TAG ('T','a','k','r'),

  /*
   * Since: 0.9.30
   */
  /*7.0*/ HB_SCRIPT_BASSA_VAH			= HB_TAG ('B','a','s','s'),
  /*7.0*/ HB_SCRIPT_CAUCASIAN_ALBANIAN		= HB_TAG ('A','g','h','b'),
  /*7.0*/ HB_SCRIPT_DUPLOYAN			= HB_TAG ('D','u','p','l'),
  /*7.0*/ HB_SCRIPT_ELBASAN			= HB_TAG ('E','l','b','a'),
  /*7.0*/ HB_SCRIPT_GRANTHA			= HB_TAG ('G','r','a','n'),
  /*7.0*/ HB_SCRIPT_KHOJKI			= HB_TAG ('K','h','o','j'),
  /*7.0*/ HB_SCRIPT_KHUDAWADI			= HB_TAG ('S','i','n','d'),
  /*7.0*/ HB_SCRIPT_LINEAR_A			= HB_TAG ('L','i','n','a'),
  /*7.0*/ HB_SCRIPT_MAHAJANI			= HB_TAG ('M','a','h','j'),
  /*7.0*/ HB_SCRIPT_MANICHAEAN			= HB_TAG ('M','a','n','i'),
  /*7.0*/ HB_SCRIPT_MENDE_KIKAKUI		= HB_TAG ('M','e','n','d'),
  /*7.0*/ HB_SCRIPT_MODI			= HB_TAG ('M','o','d','i'),
  /*7.0*/ HB_SCRIPT_MRO				= HB_TAG ('M','r','o','o'),
  /*7.0*/ HB_SCRIPT_NABATAEAN			= HB_TAG ('N','b','a','t'),
  /*7.0*/ HB_SCRIPT_OLD_NORTH_ARABIAN		= HB_TAG ('N','a','r','b'),
  /*7.0*/ HB_SCRIPT_OLD_PERMIC			= HB_TAG ('P','e','r','m'),
  /*7.0*/ HB_SCRIPT_PAHAWH_HMONG		= HB_TAG ('H','m','n','g'),
  /*7.0*/ HB_SCRIPT_PALMYRENE			= HB_TAG ('P','a','l','m'),
  /*7.0*/ HB_SCRIPT_PAU_CIN_HAU			= HB_TAG ('P','a','u','c'),
  /*7.0*/ HB_SCRIPT_PSALTER_PAHLAVI		= HB_TAG ('P','h','l','p'),
  /*7.0*/ HB_SCRIPT_SIDDHAM			= HB_TAG ('S','i','d','d'),
  /*7.0*/ HB_SCRIPT_TIRHUTA			= HB_TAG ('T','i','r','h'),
  /*7.0*/ HB_SCRIPT_WARANG_CITI			= HB_TAG ('W','a','r','a'),

  /*8.0*/ HB_SCRIPT_AHOM			= HB_TAG ('A','h','o','m'),
  /*8.0*/ HB_SCRIPT_ANATOLIAN_HIEROGLYPHS	= HB_TAG ('H','l','u','w'),
  /*8.0*/ HB_SCRIPT_HATRAN			= HB_TAG ('H','a','t','r'),
  /*8.0*/ HB_SCRIPT_MULTANI			= HB_TAG ('M','u','l','t'),
  /*8.0*/ HB_SCRIPT_OLD_HUNGARIAN		= HB_TAG ('H','u','n','g'),
  /*8.0*/ HB_SCRIPT_SIGNWRITING			= HB_TAG ('S','g','n','w'),

  /*
   * Since 1.3.0
   */
  /*9.0*/ HB_SCRIPT_ADLAM			= HB_TAG ('A','d','l','m'),
  /*9.0*/ HB_SCRIPT_BHAIKSUKI			= HB_TAG ('B','h','k','s'),
  /*9.0*/ HB_SCRIPT_MARCHEN			= HB_TAG ('M','a','r','c'),
  /*9.0*/ HB_SCRIPT_OSAGE			= HB_TAG ('O','s','g','e'),
  /*9.0*/ HB_SCRIPT_TANGUT			= HB_TAG ('T','a','n','g'),
  /*9.0*/ HB_SCRIPT_NEWA			= HB_TAG ('N','e','w','a'),

  /*
   * Since 1.6.0
   */
  /*10.0*/HB_SCRIPT_MASARAM_GONDI		= HB_TAG ('G','o','n','m'),
  /*10.0*/HB_SCRIPT_NUSHU			= HB_TAG ('N','s','h','u'),
  /*10.0*/HB_SCRIPT_SOYOMBO			= HB_TAG ('S','o','y','o'),
  /*10.0*/HB_SCRIPT_ZANABAZAR_SQUARE		= HB_TAG ('Z','a','n','b'),

  /*
   * Since 1.8.0
   */
  /*11.0*/HB_SCRIPT_DOGRA			= HB_TAG ('D','o','g','r'),
  /*11.0*/HB_SCRIPT_GUNJALA_GONDI		= HB_TAG ('G','o','n','g'),
  /*11.0*/HB_SCRIPT_HANIFI_ROHINGYA		= HB_TAG ('R','o','h','g'),
  /*11.0*/HB_SCRIPT_MAKASAR			= HB_TAG ('M','a','k','a'),
  /*11.0*/HB_SCRIPT_MEDEFAIDRIN			= HB_TAG ('M','e','d','f'),
  /*11.0*/HB_SCRIPT_OLD_SOGDIAN			= HB_TAG ('S','o','g','o'),
  /*11.0*/HB_SCRIPT_SOGDIAN			= HB_TAG ('S','o','g','d'),

  /*
   * Since 2.4.0
   */
  /*12.0*/HB_SCRIPT_ELYMAIC			= HB_TAG ('E','l','y','m'),
  /*12.0*/HB_SCRIPT_NANDINAGARI			= HB_TAG ('N','a','n','d'),
  /*12.0*/HB_SCRIPT_NYIAKENG_PUACHUE_HMONG	= HB_TAG ('H','m','n','p'),
  /*12.0*/HB_SCRIPT_WANCHO			= HB_TAG ('W','c','h','o'),

  /* No script set. */
  HB_SCRIPT_INVALID				= HB_TAG_NONE,

  /* Dummy values to ensure any hb_tag_t value can be passed/stored as hb_script_t
   * without risking undefined behavior.  We have two, for historical reasons.
   * HB_TAG_MAX used to be unsigned, but that was invalid Ansi C, so was changed
   * to _HB_SCRIPT_MAX_VALUE to be equal to HB_TAG_MAX_SIGNED as well.
   *
   * See this thread for technicalities:
   *
   *   https://lists.freedesktop.org/archives/harfbuzz/2014-March/004150.html
   */
  _HB_SCRIPT_MAX_VALUE				= HB_TAG_MAX_SIGNED, /*< skip >*/
  _HB_SCRIPT_MAX_VALUE_SIGNED			= HB_TAG_MAX_SIGNED /*< skip >*/

} hb_script_t;

/* Script functions */

HB_EXTERN hb_script_t
hb_script_from_iso15924_tag (hb_tag_t tag);

HB_EXTERN hb_script_t
hb_script_from_string (const char *str, int len);

HB_EXTERN hb_tag_t
hb_script_to_iso15924_tag (hb_script_t script);

HB_EXTERN hb_direction_t
hb_script_get_horizontal_direction (hb_script_t script);

/* User data */

typedef struct hb_user_data_key_t {
  /*< private >*/
  char unused;
} hb_user_data_key_t;

typedef void (*hb_destroy_func_t) (void *user_data);

/* Font features and variations. */

/**
 * HB_FEATURE_GLOBAL_START
 *
 * Since: 2.0.0
 */
#define HB_FEATURE_GLOBAL_START	0
/**
 * HB_FEATURE_GLOBAL_END
 *
 * Since: 2.0.0
 */
#define HB_FEATURE_GLOBAL_END	((unsigned int) -1)

/**
 * hb_feature_t:
 * @tag: a feature tag
 * @value: 0 disables the feature, non-zero (usually 1) enables the feature.
 * For features implemented as lookup type 3 (like 'salt') the @value is a one
 * based index into the alternates.
 * @start: the cluster to start applying this feature setting (inclusive).
 * @end: the cluster to end applying this feature setting (exclusive).
 *
 * The #hb_feature_t is the structure that holds information about requested
 * feature application. The feature will be applied with the given value to all
 * glyphs which are in clusters between @start (inclusive) and @end (exclusive).
 * Setting start to @HB_FEATURE_GLOBAL_START and end to @HB_FEATURE_GLOBAL_END
 * specifies that the feature always applies to the entire buffer.
 */
typedef struct hb_feature_t {
  hb_tag_t      tag;
  uint32_t      value;
  unsigned int  start;
  unsigned int  end;
} hb_feature_t;

HB_EXTERN hb_bool_t
hb_feature_from_string (const char *str, int len,
			hb_feature_t *feature);

HB_EXTERN void
hb_feature_to_string (hb_feature_t *feature,
		      char *buf, unsigned int size);

/**
 * hb_variation_t:
 *
 * Since: 1.4.2
 */
typedef struct hb_variation_t {
  hb_tag_t tag;
  float    value;
} hb_variation_t;

HB_EXTERN hb_bool_t
hb_variation_from_string (const char *str, int len,
			  hb_variation_t *variation);

HB_EXTERN void
hb_variation_to_string (hb_variation_t *variation,
			char *buf, unsigned int size);

/**
 * hb_color_t:
 *
 * Data type for holding color values.
 *
 * Since: 2.1.0
 */
typedef uint32_t hb_color_t;

#define HB_COLOR(b,g,r,a) ((hb_color_t) HB_TAG ((b),(g),(r),(a)))

HB_EXTERN uint8_t
hb_color_get_alpha (hb_color_t color);
#define hb_color_get_alpha(color)	((color) & 0xFF)

HB_EXTERN uint8_t
hb_color_get_red (hb_color_t color);
#define hb_color_get_red(color)		(((color) >> 8) & 0xFF)

HB_EXTERN uint8_t
hb_color_get_green (hb_color_t color);
#define hb_color_get_green(color)	(((color) >> 16) & 0xFF)

HB_EXTERN uint8_t
hb_color_get_blue (hb_color_t color);
#define hb_color_get_blue(color)	(((color) >> 24) & 0xFF)

HB_END_DECLS

#endif /* HB_COMMON_H */


text:
/*
 * Copyright © 2019-2020  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_H_IN
#error "Include <hb.h> instead."
#endif

#ifndef HB_DRAW_H
#define HB_DRAW_H

#include "hb.h"

HB_BEGIN_DECLS

#ifdef HB_EXPERIMENTAL_API
typedef void (*hb_draw_move_to_func_t) (hb_position_t to_x, hb_position_t to_y, void *user_data);
typedef void (*hb_draw_line_to_func_t) (hb_position_t to_x, hb_position_t to_y, void *user_data);
typedef void (*hb_draw_quadratic_to_func_t) (hb_position_t control_x, hb_position_t control_y,
					     hb_position_t to_x, hb_position_t to_y,
					     void *user_data);
typedef void (*hb_draw_cubic_to_func_t) (hb_position_t control1_x, hb_position_t control1_y,
					 hb_position_t control2_x, hb_position_t control2_y,
					 hb_position_t to_x, hb_position_t to_y,
					 void *user_data);
typedef void (*hb_draw_close_path_func_t) (void *user_data);

/**
 * hb_draw_funcs_t:
 *
 * Glyph draw callbacks.
 *
 * _move_to, _line_to and _cubic_to calls are nessecary to be defined but we
 * translate _quadratic_to calls to _cubic_to if the callback isn't defined.
 *
 * Since: EXPERIMENTAL
 **/
typedef struct hb_draw_funcs_t hb_draw_funcs_t;

HB_EXTERN void
hb_draw_funcs_set_move_to_func (hb_draw_funcs_t        *funcs,
				hb_draw_move_to_func_t  move_to);

HB_EXTERN void
hb_draw_funcs_set_line_to_func (hb_draw_funcs_t        *funcs,
				hb_draw_line_to_func_t  line_to);

HB_EXTERN void
hb_draw_funcs_set_quadratic_to_func (hb_draw_funcs_t             *funcs,
				     hb_draw_quadratic_to_func_t  quadratic_to);

HB_EXTERN void
hb_draw_funcs_set_cubic_to_func (hb_draw_funcs_t         *funcs,
				 hb_draw_cubic_to_func_t  cubic_to);

HB_EXTERN void
hb_draw_funcs_set_close_path_func (hb_draw_funcs_t           *funcs,
				   hb_draw_close_path_func_t  close_path);

HB_EXTERN hb_draw_funcs_t *
hb_draw_funcs_create (void);

HB_EXTERN hb_draw_funcs_t *
hb_draw_funcs_reference (hb_draw_funcs_t *funcs);

HB_EXTERN void
hb_draw_funcs_destroy (hb_draw_funcs_t *funcs);

HB_EXTERN void
hb_draw_funcs_make_immutable (hb_draw_funcs_t *funcs);

HB_EXTERN hb_bool_t
hb_draw_funcs_is_immutable (hb_draw_funcs_t *funcs);
#endif

HB_END_DECLS

#endif /* HB_DRAW_H */

repo_language: C

mime_type: text/x-c


text:
#!/usr/bin/env python3

import io, os.path, sys, re
import logging
logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO)

if len (sys.argv) not in (2, 3):
	print("""usage: ./gen-ucd-table ucd.nounihan.grouped.xml [/path/to/hb-common.h]

Input file, as of Unicode 12:
* https://unicode.org/Public/UCD/latest/ucdxml/ucd.nounihan.grouped.zip""", file=sys.stderr)
	sys.exit(1)

# https://github.com/harfbuzz/packtab
import packTab
import packTab.ucdxml

logging.info('Loading UCDXML...')
ucdxml = packTab.ucdxml.load_ucdxml(sys.argv[1])
ucd = packTab.ucdxml.ucdxml_get_repertoire(ucdxml)

hb_common_h = 'hb-common.h' if len (sys.argv) < 3 else sys.argv[2]

logging.info('Preparing data tables...')

gc = [u['gc'] for u in ucd]
ccc = [int(u['ccc']) for u in ucd]
bmg = [int(v, 16) - int(u) if v else 0 for u,v in enumerate(u['bmg'] for u in ucd)]
#gc_ccc_non0 = set((cat,klass) for cat,klass in zip(gc,ccc) if klass)
#gc_bmg_non0 = set((cat,mirr) for cat,mirr in zip(gc, bmg) if mirr)

sc = [u['sc'] for u in ucd]

dm = {i:tuple(int(v, 16) for v in u['dm'].split()) for i,u in enumerate(ucd)
      if u['dm'] != '#' and u['dt'] == 'can' and not (0xAC00 <= i < 0xAC00+11172)}
ce = {i for i,u in enumerate(ucd) if u['Comp_Ex'] == 'Y'}

assert not any(v for v in dm.values() if len(v) not in (1,2))
dm1 = sorted(set(v for v in dm.values() if len(v) == 1))
assert all((v[0] >> 16) in (0,2) for v in dm1)
dm1_p0_array = ['0x%04Xu' % (v[0] & 0xFFFF) for v in dm1 if (v[0] >> 16) == 0]
dm1_p2_array = ['0x%04Xu' % (v[0] & 0xFFFF) for v in dm1 if (v[0] >> 16) == 2]
dm1_order = {v:i+1 for i,v in enumerate(dm1)}

dm2 = sorted((v+(i if i not in ce and not ccc[i] else 0,), v)
             for i,v in dm.items() if len(v) == 2)

filt = lambda v: ((v[0] & 0xFFFFF800) == 0x0000 and
                  (v[1] & 0xFFFFFF80) == 0x0300 and
                  (v[2] & 0xFFF0C000) == 0x0000)
dm2_u32_array = [v for v in dm2 if filt(v[0])]
dm2_u64_array = [v for v in dm2 if not filt(v[0])]
assert dm2_u32_array + dm2_u64_array == dm2
dm2_u32_array = ["HB_CODEPOINT_ENCODE3_11_7_14 (0x%04Xu, 0x%04Xu, 0x%04Xu)" % v[0] for v in dm2_u32_array]
dm2_u64_array = ["HB_CODEPOINT_ENCODE3 (0x%04Xu, 0x%04Xu, 0x%04Xu)" % v[0] for v in dm2_u64_array]

l = 1 + len(dm1_p0_array) + len(dm1_p2_array)
dm2_order = {v[1]:i+l for i,v in enumerate(dm2)}

dm_order = {None: 0}
dm_order.update(dm1_order)
dm_order.update(dm2_order)

gc_order = dict()
for i,v in enumerate(('Cc', 'Cf', 'Cn', 'Co', 'Cs', 'Ll', 'Lm', 'Lo', 'Lt', 'Lu',
                      'Mc', 'Me', 'Mn', 'Nd', 'Nl', 'No', 'Pc', 'Pd', 'Pe', 'Pf',
                      'Pi', 'Po', 'Ps', 'Sc', 'Sk', 'Sm', 'So', 'Zl', 'Zp', 'Zs',)):
    gc_order[i] = v
    gc_order[v] = i

sc_order = dict()
sc_array = []
sc_re = re.compile(r"\b(HB_SCRIPT_[_A-Z]*).*HB_TAG [(]'(.)','(.)','(.)','(.)'[)]")
for line in open(hb_common_h):
    m = sc_re.search (line)
    if not m: continue
    name = m.group(1)
    tag = ''.join(m.group(i) for i in range(2, 6))
    i = len(sc_array)
    sc_order[tag] = i
    sc_order[i] = tag
    sc_array.append(name)

DEFAULT = 1
COMPACT = 3
SLOPPY  = 5

logging.info('Generating output...')
print("/* == Start of generated table == */")
print("/*")
print(" * The following table is generated by running:")
print(" *")
print(" *   ./gen-ucd-table.py ucd.nounihan.grouped.xml")
print(" *")
print(" * on file with this description:", ucdxml.description)
print(" */")
print()
print("#ifndef HB_UCD_TABLE_HH")
print("#define HB_UCD_TABLE_HH")
print()
print('#include "hb.hh"')
print()

code = packTab.Code('_hb_ucd')
sc_array, _ = code.addArray('hb_script_t', 'sc_map', sc_array)
dm1_p0_array, _ = code.addArray('uint16_t', 'dm1_p0_map', dm1_p0_array)
dm1_p2_array, _ = code.addArray('uint16_t', 'dm1_p2_map', dm1_p2_array)
dm2_u32_array, _ = code.addArray('uint32_t', 'dm2_u32_map', dm2_u32_array)
dm2_u64_array, _ = code.addArray('uint64_t', 'dm2_u64_map', dm2_u64_array)
code.print_c(linkage='static inline')

datasets = [
    ('gc', gc, 'Cn', gc_order),
    ('ccc', ccc, 0, None),
    ('bmg', bmg, 0, None),
    ('sc', sc, 'Zzzz', sc_order),
    ('dm', dm, None, dm_order),
]

for compression in (DEFAULT, COMPACT, SLOPPY):
    logging.info('  Compression=%d:' % compression)
    print()
    if compression == DEFAULT:
        print('#ifndef HB_OPTIMIZE_SIZE')
    elif compression == COMPACT:
        print('#elif !defined(HB_NO_UCD_UNASSIGNED)')
    else:
        print('#else')
    print()

    if compression == SLOPPY:
        for i in range(len(gc)):
            if (i % 128) and gc[i] == 'Cn':
                gc[i] = gc[i - 1]
        for i in range(len(gc) - 2, -1, -1):
            if ((i + 1) % 128) and gc[i] == 'Cn':
                gc[i] = gc[i + 1]
        for i in range(len(sc)):
            if (i % 128) and sc[i] == 'Zzzz':
                sc[i] = sc[i - 1]
        for i in range(len(sc) - 2, -1, -1):
            if ((i + 1) % 128) and sc[i] == 'Zzzz':
                sc[i] = sc[i + 1]

    code = packTab.Code('_hb_ucd')

    for name,data,default,mapping in datasets:
        sol = packTab.pack_table(data, default, mapping=mapping, compression=compression)
        logging.info('      Dataset=%-8s FullCost=%d' % (name, sol.fullCost))
        sol.genCode(code, name)

    code.print_c(linkage='static inline')

    print()

print('#endif')
print()

print()
print("#endif /* HB_UCD_TABLE_HH */")
print()
print("/* == End of generated table == */")
logging.info('Done.')


text:
/*
 * Copyright © 2019  Facebook, 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.
 *
 * Facebook Author(s): Behdad Esfahbod
 */

#include "hb.hh"
#include "hb-algs.hh"

static char *
test_func (int a, char **b)
{
  return b ? b[a] : nullptr;
}

struct A
{
  void a () {}
};

int
main (int argc, char **argv)
{
  int i = 1;
  auto p = hb_pair (1, i);

  p.second = 2;
  assert (i == 2);

  const int c = 3;
  auto pc = hb_pair (1, c);
  assert (pc.second == 3);

  auto q = p;
  assert (&q != &p);
  q.second = 4;
  assert (i == 4);

  hb_invoke (test_func, 0, nullptr);

  A a;
  hb_invoke (&A::a, a);

  assert (1 == hb_min (8, 1));
  assert (8 == hb_max (8, 1));

  int x = 1, y = 2;
  hb_min (x, 3);
  hb_min (3, x);
  hb_min (x, 4 + 3);
  int &z = hb_min (x, y);
  z = 3;
  assert (x == 3);

  hb_pair_t<const int*, int> xp = hb_pair_t<int *, long> (nullptr, 0);
  xp = hb_pair_t<int *, double> (nullptr, 1);
  xp = hb_pair_t<const int*, int> (nullptr, 1);

  assert (3 == hb_partial (hb_min, 3) (4));
  assert (3 == hb_partial<1> (hb_min, 4) (3));

  auto M0 = hb_partial<2> (hb_max, 0);
  assert (M0 (-2) == 0);
  assert (M0 (+2) == 2);

  assert (hb_add (2) (5) == 7);
  assert (hb_add (5) (2) == 7);

  x = 1;
  assert (++hb_inc (x) == 3);
  assert (x == 3);

  return 0;
}


text:
/*
 * Copyright © 2018  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_META_HH
#define HB_META_HH

#include "hb.hh"

/*
 * C++ template meta-programming & fundamentals used with them.
 */

/* Void!  For when we need a expression-type of void. */
struct hb_empty_t {};

/* https://en.cppreference.com/w/cpp/types/void_t */
template<typename... Ts> struct _hb_void_t { typedef void type; };
template<typename... Ts> using hb_void_t = typename _hb_void_t<Ts...>::type;

template<typename Head, typename... Ts> struct _hb_head_t { typedef Head type; };
template<typename... Ts> using hb_head_t = typename _hb_head_t<Ts...>::type;

template <typename T, T v> struct hb_integral_constant { static constexpr T value = v; };
template <bool b> using hb_bool_constant = hb_integral_constant<bool, b>;
using hb_true_type = hb_bool_constant<true>;
using hb_false_type = hb_bool_constant<false>;

/* Basic type SFINAE. */

template <bool B, typename T = void> struct hb_enable_if {};
template <typename T>                struct hb_enable_if<true, T> { typedef T type; };
#define hb_enable_if(Cond) typename hb_enable_if<(Cond)>::type* = nullptr
/* Concepts/Requires alias: */
#define hb_requires(Cond) hb_enable_if((Cond))

template <typename T, typename T2> struct hb_is_same : hb_false_type {};
template <typename T>              struct hb_is_same<T, T> : hb_true_type {};
#define hb_is_same(T, T2) hb_is_same<T, T2>::value

/* Function overloading SFINAE and priority. */

#define HB_RETURN(Ret, E) -> hb_head_t<Ret, decltype ((E))> { return (E); }
#define HB_AUTO_RETURN(E) -> decltype ((E)) { return (E); }
#define HB_VOID_RETURN(E) -> hb_void_t<decltype ((E))> { (E); }

template <unsigned Pri> struct hb_priority : hb_priority<Pri - 1> {};
template <>             struct hb_priority<0> {};
#define hb_prioritize hb_priority<16> ()

#define HB_FUNCOBJ(x) static_const x HB_UNUSED

template <typename T> struct hb_type_identity_t { typedef T type; };
template <typename T> using hb_type_identity = typename hb_type_identity_t<T>::type;

struct
{
  template <typename T> constexpr T*
  operator () (T& arg) const
  {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-align"
    /* https://en.cppreference.com/w/cpp/memory/addressof */
    return reinterpret_cast<T*> (
	     &const_cast<char&> (
		reinterpret_cast<const volatile char&> (arg)));
#pragma GCC diagnostic pop
  }
}
HB_FUNCOBJ (hb_addressof);

template <typename T> static inline T hb_declval ();
#define hb_declval(T) (hb_declval<T> ())

template <typename T> struct hb_match_const		: hb_type_identity_t<T>, hb_bool_constant<false>{};
template <typename T> struct hb_match_const<const T>	: hb_type_identity_t<T>, hb_bool_constant<true>	{};
template <typename T> using hb_remove_const = typename hb_match_const<T>::type;
template <typename T> using hb_add_const = const T;
#define hb_is_const(T) hb_match_const<T>::value
template <typename T> struct hb_match_reference		: hb_type_identity_t<T>, hb_bool_constant<false>{};
template <typename T> struct hb_match_reference<T &>	: hb_type_identity_t<T>, hb_bool_constant<true>	{};
template <typename T> struct hb_match_reference<T &&>	: hb_type_identity_t<T>, hb_bool_constant<true>	{};
template <typename T> using hb_remove_reference = typename hb_match_reference<T>::type;
template <typename T> auto _hb_try_add_lvalue_reference (hb_priority<1>) -> hb_type_identity<T&>;
template <typename T> auto _hb_try_add_lvalue_reference (hb_priority<0>) -> hb_type_identity<T>;
template <typename T> using hb_add_lvalue_reference = decltype (_hb_try_add_lvalue_reference<T> (hb_prioritize));
template <typename T> auto _hb_try_add_rvalue_reference (hb_priority<1>) -> hb_type_identity<T&&>;
template <typename T> auto _hb_try_add_rvalue_reference (hb_priority<0>) -> hb_type_identity<T>;
template <typename T> using hb_add_rvalue_reference = decltype (_hb_try_add_rvalue_reference<T> (hb_prioritize));
#define hb_is_reference(T) hb_match_reference<T>::value
template <typename T> struct hb_match_pointer		: hb_type_identity_t<T>, hb_bool_constant<false>{};
template <typename T> struct hb_match_pointer<T *>	: hb_type_identity_t<T>, hb_bool_constant<true>	{};
template <typename T> using hb_remove_pointer = typename hb_match_pointer<T>::type;
template <typename T> auto _hb_try_add_pointer (hb_priority<1>) -> hb_type_identity<hb_remove_reference<T>*>;
template <typename T> auto _hb_try_add_pointer (hb_priority<1>) -> hb_type_identity<T>;
template <typename T> using hb_add_pointer = decltype (_hb_try_add_pointer<T> (hb_prioritize));
#define hb_is_pointer(T) hb_match_pointer<T>::value

/* TODO Add feature-parity to std::decay. */
template <typename T> using hb_decay = hb_remove_const<hb_remove_reference<T>>;

template<bool B, class T, class F>
struct _hb_conditional { typedef T type; };
template<class T, class F>
struct _hb_conditional<false, T, F> { typedef F type; };
template<bool B, class T, class F>
using hb_conditional = typename _hb_conditional<B, T, F>::type;

template <typename From, typename To>
struct hb_is_convertible
{
  private:
  static constexpr bool   from_void = hb_is_same (void, hb_decay<From>);
  static constexpr bool     to_void = hb_is_same (void, hb_decay<To>  );
  static constexpr bool either_void = from_void || to_void;
  static constexpr bool   both_void = from_void && to_void;

  static hb_true_type impl2 (hb_conditional<to_void, int, To>);

  template <typename T>
  static auto impl (hb_priority<1>) -> decltype (impl2 (hb_declval (T)));
  template <typename T>
  static hb_false_type impl (hb_priority<0>);
  public:
  static constexpr bool value = both_void ||
		       (!either_void &&
			decltype (impl<hb_conditional<from_void, int, From>> (hb_prioritize))::value);
};
#define hb_is_convertible(From,To) hb_is_convertible<From, To>::value

template <typename Base, typename Derived>
using hb_is_base_of = hb_is_convertible<hb_decay<Derived> *, hb_decay<Base> *>;
#define hb_is_base_of(Base,Derived) hb_is_base_of<Base, Derived>::value

template <typename From, typename To>
using hb_is_cr_convertible = hb_bool_constant<
  hb_is_same (hb_decay<From>, hb_decay<To>) &&
  (!hb_is_const (From) || hb_is_const (To)) &&
  (!hb_is_reference (To) || hb_is_const (To) || hb_is_reference (To))
>;
#define hb_is_cr_convertible(From,To) hb_is_cr_convertible<From, To>::value

/* std::move and std::forward */

template <typename T>
static constexpr hb_remove_reference<T>&& hb_move (T&& t) { return (hb_remove_reference<T>&&) (t); }

template <typename T>
static constexpr T&& hb_forward (hb_remove_reference<T>& t) { return (T&&) t; }
template <typename T>
static constexpr T&& hb_forward (hb_remove_reference<T>&& t) { return (T&&) t; }

struct
{
  template <typename T> constexpr auto
  operator () (T&& v) const HB_AUTO_RETURN (hb_forward<T> (v))

  template <typename T> constexpr auto
  operator () (T *v) const HB_AUTO_RETURN (*v)
}
HB_FUNCOBJ (hb_deref);

struct
{
  template <typename T> constexpr auto
  operator () (T&& v) const HB_AUTO_RETURN (hb_forward<T> (v))

  template <typename T> constexpr auto
  operator () (T& v) const HB_AUTO_RETURN (hb_addressof (v))
}
HB_FUNCOBJ (hb_ref);

template <typename T>
struct hb_reference_wrapper
{
  hb_reference_wrapper (T v) : v (v) {}
  bool operator == (const hb_reference_wrapper& o) const { return v == o.v; }
  bool operator != (const hb_reference_wrapper& o) const { return v != o.v; }
  operator T () const { return v; }
  T get () const { return v; }
  T v;
};
template <typename T>
struct hb_reference_wrapper<T&>
{
  hb_reference_wrapper (T& v) : v (hb_addressof (v)) {}
  bool operator == (const hb_reference_wrapper& o) const { return v == o.v; }
  bool operator != (const hb_reference_wrapper& o) const { return v != o.v; }
  operator T& () const { return *v; }
  T& get () const { return *v; }
  T* v;
};

template <typename T>
using hb_is_integral = hb_bool_constant<
  hb_is_same (hb_decay<T>, char) ||
  hb_is_same (hb_decay<T>, signed char) ||
  hb_is_same (hb_decay<T>, unsigned char) ||
  hb_is_same (hb_decay<T>, signed int) ||
  hb_is_same (hb_decay<T>, unsigned int) ||
  hb_is_same (hb_decay<T>, signed short) ||
  hb_is_same (hb_decay<T>, unsigned short) ||
  hb_is_same (hb_decay<T>, signed long) ||
  hb_is_same (hb_decay<T>, unsigned long) ||
  hb_is_same (hb_decay<T>, signed long long) ||
  hb_is_same (hb_decay<T>, unsigned long long) ||
  false
>;
#define hb_is_integral(T) hb_is_integral<T>::value
template <typename T>
using hb_is_floating_point = hb_bool_constant<
  hb_is_same (hb_decay<T>, float) ||
  hb_is_same (hb_decay<T>, double) ||
  hb_is_same (hb_decay<T>, long double) ||
  false
>;
#define hb_is_floating_point(T) hb_is_floating_point<T>::value
template <typename T>
using hb_is_arithmetic = hb_bool_constant<
  hb_is_integral (T) ||
  hb_is_floating_point (T) ||
  false
>;
#define hb_is_arithmetic(T) hb_is_arithmetic<T>::value

template <typename T>
using hb_is_signed = hb_conditional<hb_is_arithmetic (T),
				    hb_bool_constant<(T) -1 < (T) 0>,
				    hb_false_type>;
#define hb_is_signed(T) hb_is_signed<T>::value
template <typename T>
using hb_is_unsigned = hb_conditional<hb_is_arithmetic (T),
				      hb_bool_constant<(T) 0 < (T) -1>,
				      hb_false_type>;
#define hb_is_unsigned(T) hb_is_unsigned<T>::value

template <typename T> struct hb_int_min;
template <> struct hb_int_min<char>			: hb_integral_constant<char,			CHAR_MIN>	{};
template <> struct hb_int_min<signed char>		: hb_integral_constant<signed char,		SCHAR_MIN>	{};
template <> struct hb_int_min<unsigned char>		: hb_integral_constant<unsigned char,		0>		{};
template <> struct hb_int_min<signed short>		: hb_integral_constant<signed short,		SHRT_MIN>	{};
template <> struct hb_int_min<unsigned short>		: hb_integral_constant<unsigned short,		0>		{};
template <> struct hb_int_min<signed int>		: hb_integral_constant<signed int,		INT_MIN>	{};
template <> struct hb_int_min<unsigned int>		: hb_integral_constant<unsigned int,		0>		{};
template <> struct hb_int_min<signed long>		: hb_integral_constant<signed long,		LONG_MIN>	{};
template <> struct hb_int_min<unsigned long>		: hb_integral_constant<unsigned long,		0>		{};
template <> struct hb_int_min<signed long long>		: hb_integral_constant<signed long long,	LLONG_MIN>	{};
template <> struct hb_int_min<unsigned long long>	: hb_integral_constant<unsigned long long,	0>		{};
#define hb_int_min(T) hb_int_min<T>::value
template <typename T> struct hb_int_max;
template <> struct hb_int_max<char>			: hb_integral_constant<char,			CHAR_MAX>	{};
template <> struct hb_int_max<signed char>		: hb_integral_constant<signed char,		SCHAR_MAX>	{};
template <> struct hb_int_max<unsigned char>		: hb_integral_constant<unsigned char,		UCHAR_MAX>	{};
template <> struct hb_int_max<signed short>		: hb_integral_constant<signed short,		SHRT_MAX>	{};
template <> struct hb_int_max<unsigned short>		: hb_integral_constant<unsigned short,		USHRT_MAX>	{};
template <> struct hb_int_max<signed int>		: hb_integral_constant<signed int,		INT_MAX>	{};
template <> struct hb_int_max<unsigned int>		: hb_integral_constant<unsigned int,		UINT_MAX>	{};
template <> struct hb_int_max<signed long>		: hb_integral_constant<signed long,		LONG_MAX>	{};
template <> struct hb_int_max<unsigned long>		: hb_integral_constant<unsigned long,		ULONG_MAX>	{};
template <> struct hb_int_max<signed long long>		: hb_integral_constant<signed long long,	LLONG_MAX>	{};
template <> struct hb_int_max<unsigned long long>	: hb_integral_constant<unsigned long long,	ULLONG_MAX>	{};
#define hb_int_max(T) hb_int_max<T>::value

template <typename T, typename>
struct _hb_is_destructible : hb_false_type {};
template <typename T>
struct _hb_is_destructible<T, hb_void_t<decltype (hb_declval (T).~T ())>> : hb_true_type {};
template <typename T>
using hb_is_destructible = _hb_is_destructible<T, void>;
#define hb_is_destructible(T) hb_is_destructible<T>::value

template <typename T, typename, typename ...Ts>
struct _hb_is_constructible : hb_false_type {};
template <typename T, typename ...Ts>
struct _hb_is_constructible<T, hb_void_t<decltype (T (hb_declval (Ts)...))>, Ts...> : hb_true_type {};
template <typename T, typename ...Ts>
using hb_is_constructible = _hb_is_constructible<T, void, Ts...>;
#define hb_is_constructible(...) hb_is_constructible<__VA_ARGS__>::value

template <typename T>
using hb_is_default_constructible = hb_is_constructible<T>;
#define hb_is_default_constructible(T) hb_is_default_constructible<T>::value

template <typename T>
using hb_is_copy_constructible = hb_is_constructible<T, hb_add_lvalue_reference<hb_add_const<T>>>;
#define hb_is_copy_constructible(T) hb_is_copy_constructible<T>::value

template <typename T>
using hb_is_move_constructible = hb_is_constructible<T, hb_add_rvalue_reference<hb_add_const<T>>>;
#define hb_is_move_constructible(T) hb_is_move_constructible<T>::value

template <typename T, typename U, typename>
struct _hb_is_assignable : hb_false_type {};
template <typename T, typename U>
struct _hb_is_assignable<T, U, hb_void_t<decltype (hb_declval (T) = hb_declval (U))>> : hb_true_type {};
template <typename T, typename U>
using hb_is_assignable = _hb_is_assignable<T, U, void>;
#define hb_is_assignable(T,U) hb_is_assignable<T, U>::value

template <typename T>
using hb_is_copy_assignable = hb_is_assignable<hb_add_lvalue_reference<T>,
					       hb_add_lvalue_reference<hb_add_const<T>>>;
#define hb_is_copy_assignable(T) hb_is_copy_assignable<T>::value

template <typename T>
using hb_is_move_assignable = hb_is_assignable<hb_add_lvalue_reference<T>,
					       hb_add_rvalue_reference<T>>;
#define hb_is_move_assignable(T) hb_is_move_assignable<T>::value

/* Trivial versions. */

template <typename T> union hb_trivial { T value; };

/* Don't know how to do the following. */
template <typename T>
using hb_is_trivially_destructible= hb_is_destructible<hb_trivial<T>>;
#define hb_is_trivially_destructible(T) hb_is_trivially_destructible<T>::value

/* Don't know how to do the following. */
//template <typename T, typename ...Ts>
//using hb_is_trivially_constructible= hb_is_constructible<hb_trivial<T>, hb_trivial<Ts>...>;
//#define hb_is_trivially_constructible(...) hb_is_trivially_constructible<__VA_ARGS__>::value

template <typename T>
using hb_is_trivially_default_constructible= hb_is_default_constructible<hb_trivial<T>>;
#define hb_is_trivially_default_constructible(T) hb_is_trivially_default_constructible<T>::value

template <typename T>
using hb_is_trivially_copy_constructible= hb_is_copy_constructible<hb_trivial<T>>;
#define hb_is_trivially_copy_constructible(T) hb_is_trivially_copy_constructible<T>::value

template <typename T>
using hb_is_trivially_move_constructible= hb_is_move_constructible<hb_trivial<T>>;
#define hb_is_trivially_move_constructible(T) hb_is_trivially_move_constructible<T>::value

/* Don't know how to do the following. */
//template <typename T, typename U>
//using hb_is_trivially_assignable= hb_is_assignable<hb_trivial<T>, hb_trivial<U>>;
//#define hb_is_trivially_assignable(T,U) hb_is_trivially_assignable<T, U>::value

template <typename T>
using hb_is_trivially_copy_assignable= hb_is_copy_assignable<hb_trivial<T>>;
#define hb_is_trivially_copy_assignable(T) hb_is_trivially_copy_assignable<T>::value

template <typename T>
using hb_is_trivially_move_assignable= hb_is_move_assignable<hb_trivial<T>>;
#define hb_is_trivially_move_assignable(T) hb_is_trivially_move_assignable<T>::value

template <typename T>
using hb_is_trivially_copyable= hb_bool_constant<
  hb_is_trivially_destructible (T) &&
  (!hb_is_move_assignable (T) || hb_is_trivially_move_assignable (T)) &&
  (!hb_is_move_constructible (T) || hb_is_trivially_move_constructible (T)) &&
  (!hb_is_copy_assignable (T) || hb_is_trivially_copy_assignable (T)) &&
  (!hb_is_copy_constructible (T) || hb_is_trivially_copy_constructible (T)) &&
  true
>;
#define hb_is_trivially_copyable(T) hb_is_trivially_copyable<T>::value

template <typename T>
using hb_is_trivial= hb_bool_constant<
  hb_is_trivially_copyable (T) &&
  hb_is_trivially_default_constructible (T)
>;
#define hb_is_trivial(T) hb_is_trivial<T>::value

/* hb_unwrap_type (T)
 * If T has no T::type, returns T. Otherwise calls itself on T::type recursively.
 */

template <typename T, typename>
struct _hb_unwrap_type : hb_type_identity_t<T> {};
template <typename T>
struct _hb_unwrap_type<T, hb_void_t<typename T::type>> : _hb_unwrap_type<typename T::type, void> {};
template <typename T>
using hb_unwrap_type = _hb_unwrap_type<T, void>;
#define hb_unwrap_type(T) typename hb_unwrap_type<T>::type

#endif /* HB_META_HH */


text:
#line 1 "hb-number-parser.rl"
/*
 * Copyright © 2019  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_NUMBER_PARSER_HH
#define HB_NUMBER_PARSER_HH

#include "hb.hh"

#line 35 "hb-number-parser.hh"
static const unsigned char _double_parser_trans_keys[] = {
	0u, 0u, 43u, 57u, 46u, 57u, 48u, 57u, 43u, 57u, 48u, 57u, 48u, 101u, 48u, 57u,
	46u, 101u, 0
};

static const char _double_parser_key_spans[] = {
	0, 15, 12, 10, 15, 10, 54, 10,
	56
};

static const unsigned char _double_parser_index_offsets[] = {
	0, 0, 16, 29, 40, 56, 67, 122,
	133
};

static const char _double_parser_indicies[] = {
	0, 1, 2, 3, 1, 4, 4,
	4, 4, 4, 4, 4, 4, 4, 4,
	1, 3, 1, 4, 4, 4, 4, 4,
	4, 4, 4, 4, 4, 1, 5, 5,
	5, 5, 5, 5, 5, 5, 5, 5,
	1, 6, 1, 7, 1, 1, 8, 8,
	8, 8, 8, 8, 8, 8, 8, 8,
	1, 8, 8, 8, 8, 8, 8, 8,
	8, 8, 8, 1, 5, 5, 5, 5,
	5, 5, 5, 5, 5, 5, 1, 1,
	1, 1, 1, 1, 1, 1, 1, 1,
	1, 9, 1, 1, 1, 1, 1, 1,
	1, 1, 1, 1, 1, 1, 1, 1,
	1, 1, 1, 1, 1, 1, 1, 1,
	1, 1, 1, 1, 1, 1, 1, 1,
	1, 9, 1, 8, 8, 8, 8, 8,
	8, 8, 8, 8, 8, 1, 3, 1,
	4, 4, 4, 4, 4, 4, 4, 4,
	4, 4, 1, 1, 1, 1, 1, 1,
	1, 1, 1, 1, 1, 9, 1, 1,
	1, 1, 1, 1, 1, 1, 1, 1,
	1, 1, 1, 1, 1, 1, 1, 1,
	1, 1, 1, 1, 1, 1, 1, 1,
	1, 1, 1, 1, 1, 9, 1, 0
};

static const char _double_parser_trans_targs[] = {
	2, 0, 2, 3, 8, 6, 5, 5,
	7, 4
};

static const char _double_parser_trans_actions[] = {
	0, 0, 1, 0, 2, 3, 0, 4,
	5, 0
};

static const int double_parser_start = 1;
static const int double_parser_first_final = 6;
static const int double_parser_error = 0;

static const int double_parser_en_main = 1;

#line 68 "hb-number-parser.rl"

/* Works only for n < 512 */
static inline double
_pow10 (unsigned exponent)
{
  static const double _powers_of_10[] =
  {
    1.0e+256,
    1.0e+128,
    1.0e+64,
    1.0e+32,
    1.0e+16,
    1.0e+8,
    10000.,
    100.,
    10.
  };
  unsigned mask = 1 << (ARRAY_LENGTH (_powers_of_10) - 1);
  double result = 1;
  for (const double *power = _powers_of_10; mask; ++power, mask >>= 1)
    if (exponent & mask) result *= *power;
  return result;
}

/* a variant of strtod that also gets end of buffer in its second argument */
static inline double
strtod_rl (const char *p, const char **end_ptr /* IN/OUT */)
{
  double value = 0;
  double frac = 0;
  double frac_count = 0;
  unsigned exp = 0;
  bool neg = false, exp_neg = false, exp_overflow = false;
  const unsigned long long MAX_FRACT = 0xFFFFFFFFFFFFFull; /* 2^52-1 */
  const unsigned MAX_EXP = 0x7FFu; /* 2^11-1 */

  const char *pe = *end_ptr;
  while (p < pe && ISSPACE (*p))
    p++;

  int cs;

#line 139 "hb-number-parser.hh"
	{
	cs = double_parser_start;
	}

#line 144 "hb-number-parser.hh"
	{
	int _slen;
	int _trans;
	const unsigned char *_keys;
	const char *_inds;
	if ( p == pe )
		goto _test_eof;
	if ( cs == 0 )
		goto _out;
_resume:
	_keys = _double_parser_trans_keys + (cs<<1);
	_inds = _double_parser_indicies + _double_parser_index_offsets[cs];

	_slen = _double_parser_key_spans[cs];
	_trans = _inds[ _slen > 0 && _keys[0] <=(*p) &&
		(*p) <= _keys[1] ?
		(*p) - _keys[0] : _slen ];

	cs = _double_parser_trans_targs[_trans];

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

	switch ( _double_parser_trans_actions[_trans] ) {
	case 1:
#line 37 "hb-number-parser.rl"
	{ neg = true; }
	break;
	case 4:
#line 38 "hb-number-parser.rl"
	{ exp_neg = true; }
	break;
	case 2:
#line 40 "hb-number-parser.rl"
	{
	value = value * 10. + ((*p) - '0');
}
	break;
	case 3:
#line 43 "hb-number-parser.rl"
	{
	if (likely (frac <= MAX_FRACT / 10))
	{
	  frac = frac * 10. + ((*p) - '0');
	  ++frac_count;
	}
}
	break;
	case 5:
#line 50 "hb-number-parser.rl"
	{
	if (likely (exp * 10 + ((*p) - '0') <= MAX_EXP))
	  exp = exp * 10 + ((*p) - '0');
	else
	  exp_overflow = true;
}
	break;
#line 202 "hb-number-parser.hh"
	}

_again:
	if ( cs == 0 )
		goto _out;
	if ( ++p != pe )
		goto _resume;
	_test_eof: {}
	_out: {}
	}

#line 113 "hb-number-parser.rl"

  *end_ptr = p;

  if (frac_count) value += frac / _pow10 (frac_count);
  if (neg) value *= -1.;

  if (unlikely (exp_overflow))
  {
    if (value == 0) return value;
    if (exp_neg)    return neg ? -DBL_MIN : DBL_MIN;
    else            return neg ? -DBL_MAX : DBL_MAX;
  }

  if (exp)
  {
    if (exp_neg) value /= _pow10 (exp);
    else         value *= _pow10 (exp);
  }

  return value;
}

#endif /* HB_NUMBER_PARSER_HH */


text:
/*
 * 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.
 *
 * Google Author(s): Behdad Esfahbod
 */

#include "hb.hh"

#ifndef HB_NO_BUFFER_SERIALIZE

#include "hb-buffer.hh"

static const char *serialize_formats[] = {
  "text",
  "json",
  nullptr
};

/**
 * hb_buffer_serialize_list_formats:
 *
 * Returns a list of supported buffer serialization formats.
 *
 * Return value: (transfer none):
 * A string array of buffer serialization formats. Should not be freed.
 *
 * Since: 0.9.7
 **/
const char **
hb_buffer_serialize_list_formats ()
{
  return serialize_formats;
}

/**
 * hb_buffer_serialize_format_from_string:
 * @str: (array length=len) (element-type uint8_t): a string to parse
 * @len: length of @str, or -1 if string is %NULL terminated
 *
 * Parses a string into an #hb_buffer_serialize_format_t. Does not check if
 * @str is a valid buffer serialization format, use
 * hb_buffer_serialize_list_formats() to get the list of supported formats.
 *
 * Return value:
 * The parsed #hb_buffer_serialize_format_t.
 *
 * Since: 0.9.7
 **/
hb_buffer_serialize_format_t
hb_buffer_serialize_format_from_string (const char *str, int len)
{
  /* Upper-case it. */
  return (hb_buffer_serialize_format_t) (hb_tag_from_string (str, len) & ~0x20202020u);
}

/**
 * hb_buffer_serialize_format_to_string:
 * @format: an #hb_buffer_serialize_format_t to convert.
 *
 * Converts @format to the string corresponding it, or %NULL if it is not a valid
 * #hb_buffer_serialize_format_t.
 *
 * Return value: (transfer none):
 * A %NULL terminated string corresponding to @format. Should not be freed.
 *
 * Since: 0.9.7
 **/
const char *
hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format)
{
  switch ((unsigned) format)
  {
    case HB_BUFFER_SERIALIZE_FORMAT_TEXT:	return serialize_formats[0];
    case HB_BUFFER_SERIALIZE_FORMAT_JSON:	return serialize_formats[1];
    default:
    case HB_BUFFER_SERIALIZE_FORMAT_INVALID:	return nullptr;
  }
}

static unsigned int
_hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer,
				  unsigned int start,
				  unsigned int end,
				  char *buf,
				  unsigned int buf_size,
				  unsigned int *buf_consumed,
				  hb_font_t *font,
				  hb_buffer_serialize_flags_t flags)
{
  hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, nullptr);
  hb_glyph_position_t *pos = (flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS) ?
			     nullptr : hb_buffer_get_glyph_positions (buffer, nullptr);

  *buf_consumed = 0;
  hb_position_t x = 0, y = 0;
  for (unsigned int i = start; i < end; i++)
  {
    char b[1024];
    char *p = b;

    /* In the following code, we know b is large enough that no overflow can happen. */

#define APPEND(s) HB_STMT_START { strcpy (p, s); p += strlen (s); } HB_STMT_END

    if (i)
      *p++ = ',';

    *p++ = '{';

    APPEND ("\"g\":");
    if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES))
    {
      char g[128];
      hb_font_glyph_to_string (font, info[i].codepoint, g, sizeof (g));
      *p++ = '"';
      for (char *q = g; *q; q++) {
	if (*q == '"')
	  *p++ = '\\';
	*p++ = *q;
      }
      *p++ = '"';
    }
    else
      p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint));

    if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
      p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"cl\":%u", info[i].cluster));
    }

    if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS))
    {
      p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"dx\":%d,\"dy\":%d",
			     x+pos[i].x_offset, y+pos[i].y_offset));
      if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES))
	p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"ax\":%d,\"ay\":%d",
			       pos[i].x_advance, pos[i].y_advance));
    }

    if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS)
    {
      if (info[i].mask & HB_GLYPH_FLAG_DEFINED)
	p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"fl\":%u", info[i].mask & HB_GLYPH_FLAG_DEFINED));
    }

    if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS)
    {
      hb_glyph_extents_t extents;
      hb_font_get_glyph_extents(font, info[i].codepoint, &extents);
      p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"xb\":%d,\"yb\":%d",
		extents.x_bearing, extents.y_bearing));
      p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"w\":%d,\"h\":%d",
		extents.width, extents.height));
    }

    *p++ = '}';

    unsigned int l = p - b;
    if (buf_size > l)
    {
      memcpy (buf, b, l);
      buf += l;
      buf_size -= l;
      *buf_consumed += l;
      *buf = '\0';
    } else
      return i - start;

    if (pos && (flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES))
    {
      x += pos[i].x_advance;
      y += pos[i].y_advance;
    }
  }

  return end - start;
}

static unsigned int
_hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer,
				  unsigned int start,
				  unsigned int end,
				  char *buf,
				  unsigned int buf_size,
				  unsigned int *buf_consumed,
				  hb_font_t *font,
				  hb_buffer_serialize_flags_t flags)
{
  hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, nullptr);
  hb_glyph_position_t *pos = (flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS) ?
			     nullptr : hb_buffer_get_glyph_positions (buffer, nullptr);

  *buf_consumed = 0;
  hb_position_t x = 0, y = 0;
  for (unsigned int i = start; i < end; i++)
  {
    char b[1024];
    char *p = b;

    /* In the following code, we know b is large enough that no overflow can happen. */

    if (i)
      *p++ = '|';

    if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES))
    {
      hb_font_glyph_to_string (font, info[i].codepoint, p, 128);
      p += strlen (p);
    }
    else
      p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint));

    if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
      p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "=%u", info[i].cluster));
    }

    if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS))
    {
      if (x+pos[i].x_offset || y+pos[i].y_offset)
	p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "@%d,%d", x+pos[i].x_offset, y+pos[i].y_offset));

      if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES))
      {
	*p++ = '+';
	p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%d", pos[i].x_advance));
	if (pos[i].y_advance)
	  p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance));
      }
    }

    if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS)
    {
      if (info[i].mask & HB_GLYPH_FLAG_DEFINED)
	p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "#%X", info[i].mask &HB_GLYPH_FLAG_DEFINED));
    }

    if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS)
    {
      hb_glyph_extents_t extents;
      hb_font_get_glyph_extents(font, info[i].codepoint, &extents);
      p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "<%d,%d,%d,%d>", extents.x_bearing, extents.y_bearing, extents.width, extents.height));
    }

    unsigned int l = p - b;
    if (buf_size > l)
    {
      memcpy (buf, b, l);
      buf += l;
      buf_size -= l;
      *buf_consumed += l;
      *buf = '\0';
    } else
      return i - start;

    if (pos && (flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES))
    {
      x += pos[i].x_advance;
      y += pos[i].y_advance;
    }
  }

  return end - start;
}

/**
 * hb_buffer_serialize_glyphs:
 * @buffer: an #hb_buffer_t buffer.
 * @start: the first item in @buffer to serialize.
 * @end: the last item in @buffer to serialize.
 * @buf: (out) (array length=buf_size) (element-type uint8_t): output string to
 *       write serialized buffer into.
 * @buf_size: the size of @buf.
 * @buf_consumed: (out) (allow-none): if not %NULL, will be set to the number of byes written into @buf.
 * @font: (allow-none): the #hb_font_t used to shape this buffer, needed to
 *        read glyph names and extents. If %NULL, and empty font will be used.
 * @format: the #hb_buffer_serialize_format_t to use for formatting the output.
 * @flags: the #hb_buffer_serialize_flags_t that control what glyph properties
 *         to serialize.
 *
 * Serializes @buffer into a textual representation of its glyph content,
 * useful for showing the contents of the buffer, for example during debugging.
 * There are currently two supported serialization formats:
 *
 * ## text
 * A human-readable, plain text format.
 * The serialized glyphs will look something like:
 *
 * ```
 * [uni0651=0@518,0+0|uni0628=0+1897]
 * ```
 * - The serialized glyphs are delimited with `[` and `]`.
 * - Glyphs are separated with `|`
 * - Each glyph starts with glyph name, or glyph index if
 *   #HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES flag is set. Then,
 *   - If #HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS is not set, `=` then #hb_glyph_info_t.cluster.
 *   - If #HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS is not set, the #hb_glyph_position_t in the format:
 *     - If both #hb_glyph_position_t.x_offset and #hb_glyph_position_t.y_offset are not 0, `@x_offset,y_offset`. Then,
 *     - `+x_advance`, then `,y_advance` if #hb_glyph_position_t.y_advance is not 0. Then,
 *   - If #HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS is set, the
 *     #hb_glyph_extents_t in the format
 *     `<x_bearing,y_bearing,width,height>`
 *
 * ## json
 * TODO.
 *
 * Return value:
 * The number of serialized items.
 *
 * Since: 0.9.7
 **/
unsigned int
hb_buffer_serialize_glyphs (hb_buffer_t *buffer,
			    unsigned int start,
			    unsigned int end,
			    char *buf,
			    unsigned int buf_size,
			    unsigned int *buf_consumed,
			    hb_font_t *font,
			    hb_buffer_serialize_format_t format,
			    hb_buffer_serialize_flags_t flags)
{
  assert (start <= end && end <= buffer->len);

  unsigned int sconsumed;
  if (!buf_consumed)
    buf_consumed = &sconsumed;
  *buf_consumed = 0;
  if (buf_size)
    *buf = '\0';

  assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) ||
	  buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);

  if (!buffer->have_positions)
    flags |= HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS;

  if (unlikely (start == end))
    return 0;

  if (!font)
    font = hb_font_get_empty ();

  switch (format)
  {
    case HB_BUFFER_SERIALIZE_FORMAT_TEXT:
      return _hb_buffer_serialize_glyphs_text (buffer, start, end,
					       buf, buf_size, buf_consumed,
					       font, flags);

    case HB_BUFFER_SERIALIZE_FORMAT_JSON:
      return _hb_buffer_serialize_glyphs_json (buffer, start, end,
					       buf, buf_size, buf_consumed,
					       font, flags);

    default:
    case HB_BUFFER_SERIALIZE_FORMAT_INVALID:
      return 0;

  }
}

static bool
parse_int (const char *pp, const char *end, int32_t *pv)
{
  int v;
  const char *p = pp;
  if (unlikely (!hb_parse_int (&p, end, &v, true/* whole buffer */)))
    return false;

  *pv = v;
  return true;
}

static bool
parse_uint (const char *pp, const char *end, uint32_t *pv)
{
  unsigned int v;
  const char *p = pp;
  if (unlikely (!hb_parse_uint (&p, end, &v, true/* whole buffer */)))
    return false;

  *pv = v;
  return true;
}

#include "hb-buffer-deserialize-json.hh"
#include "hb-buffer-deserialize-text.hh"

/**
 * hb_buffer_deserialize_glyphs:
 * @buffer: an #hb_buffer_t buffer.
 * @buf: (array length=buf_len):
 * @buf_len:
 * @end_ptr: (out):
 * @font:
 * @format:
 *
 *
 *
 * Return value:
 *
 * Since: 0.9.7
 **/
hb_bool_t
hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
			      const char *buf,
			      int buf_len, /* -1 means nul-terminated */
			      const char **end_ptr, /* May be NULL */
			      hb_font_t *font, /* May be NULL */
			      hb_buffer_serialize_format_t format)
{
  const char *end;
  if (!end_ptr)
    end_ptr = &end;
  *end_ptr = buf;

  assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) ||
	  buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);

  if (buf_len == -1)
    buf_len = strlen (buf);

  if (!buf_len)
  {
    *end_ptr = buf;
    return false;
  }

  hb_buffer_set_content_type (buffer, HB_BUFFER_CONTENT_TYPE_GLYPHS);

  if (!font)
    font = hb_font_get_empty ();

  switch (format)
  {
    case HB_BUFFER_SERIALIZE_FORMAT_TEXT:
      return _hb_buffer_deserialize_glyphs_text (buffer,
						 buf, buf_len, end_ptr,
						 font);

    case HB_BUFFER_SERIALIZE_FORMAT_JSON:
      return _hb_buffer_deserialize_glyphs_json (buffer,
						 buf, buf_len, end_ptr,
						 font);

    default:
    case HB_BUFFER_SERIALIZE_FORMAT_INVALID:
      return false;

  }
}

#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
 */

#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_WIN1256_HH

/*
 * The macros in the first part of this file are generic macros that can
 * be used to define the bytes for OpenType table data in code in a
 * readable manner.  We can move the macros to reside with their respective
 * struct types, but since we only use these to define one data table, the
 * Windows-1256 Arabic shaping table in this file, we keep them here.
 */

/* First we measure, then we cut. */
#ifndef OT_MEASURE
#define OT_MEASURE
#define OT_TABLE_START			static const struct TABLE_NAME {
#define OT_TABLE_END			}
#define OT_LABEL_START(Name)		unsigned char Name[
#define OT_LABEL_END			];
#define OT_UINT8(u8)			+1/*byte*/
#define OT_UINT16(u16)			+2/*bytes*/
#else
#undef  OT_MEASURE
#define OT_TABLE_START			TABLE_NAME = {
#define OT_TABLE_END			};
#define OT_LABEL_START(Name)		{
#define OT_LABEL_END			},
#define OT_UINT8(u8)			(u8),
#define OT_UINT16(u16)			(unsigned char)((u16)>>8), (unsigned char)((u16)&0xFFu),
#define OT_COUNT(Name, ItemSize)	((unsigned int) sizeof(((struct TABLE_NAME*)0)->Name) \
					 / (unsigned int)(ItemSize) \
					 /* OT_ASSERT it's divisible (and positive). */)
#define OT_DISTANCE(From,To)		((unsigned int) \
					 ((char*)(&((struct TABLE_NAME*)0)->To) - \
					  (char*)(&((struct TABLE_NAME*)0)->From)) \
					 /* OT_ASSERT it's positive. */)
#endif

#define OT_LABEL(Name) \
	OT_LABEL_END \
	OT_LABEL_START(Name)

/* Whenever we receive an argument that is a list, it will expand to
 * contain commas.  That cannot be passed to another macro because the
 * commas will throw off the preprocessor.  The solution is to wrap
 * the passed-in argument in OT_LIST() before passing to the next macro.
 * Unfortunately this trick requires vararg macros. */
#define OT_LIST(...) __VA_ARGS__

/*
 * Basic Types
 */

#define OT_TAG(a,b,c,d) \
	OT_UINT8(a) OT_UINT8(b) OT_UINT8(c) OT_UINT8(d)

#define OT_OFFSET(From, To) /* Offset from From to To in bytes */ \
	OT_UINT16(OT_DISTANCE(From, To))

#define OT_GLYPHID /* GlyphID */ \
	OT_UINT16

#define OT_UARRAY(Name, Items) \
	OT_LABEL_START(Name) \
	OT_UINT16(OT_COUNT(Name##Data, 2)) \
	OT_LABEL(Name##Data) \
	Items \
	OT_LABEL_END

#define OT_UHEADLESSARRAY(Name, Items) \
	OT_LABEL_START(Name) \
	OT_UINT16(OT_COUNT(Name##Data, 2) + 1) \
	OT_LABEL(Name##Data) \
	Items \
	OT_LABEL_END

/*
 * Common Types
 */

#define OT_LOOKUP_FLAG_IGNORE_MARKS	0x08u

#define OT_LOOKUP(Name, LookupType, LookupFlag, SubLookupOffsets) \
	OT_LABEL_START(Name) \
	OT_UINT16(LookupType) \
	OT_UINT16(LookupFlag) \
	OT_LABEL_END \
	OT_UARRAY(Name##SubLookupOffsetsArray, OT_LIST(SubLookupOffsets))

#define OT_SUBLOOKUP(Name, SubFormat, Items) \
	OT_LABEL_START(Name) \
	OT_UINT16(SubFormat) \
	Items

#define OT_COVERAGE1(Name, Items) \
	OT_LABEL_START(Name) \
	OT_UINT16(1) \
	OT_LABEL_END \
	OT_UARRAY(Name##Glyphs, OT_LIST(Items))

/*
 * GSUB
 */

#define OT_LOOKUP_TYPE_SUBST_SINGLE	1u
#define OT_LOOKUP_TYPE_SUBST_LIGATURE	4u

#define OT_SUBLOOKUP_SINGLE_SUBST_FORMAT2(Name, FromGlyphs, ToGlyphs) \
	OT_SUBLOOKUP(Name, 2, \
		OT_OFFSET(Name, Name##Coverage) \
		OT_LABEL_END \
		OT_UARRAY(Name##Substitute, OT_LIST(ToGlyphs)) \
	) \
	OT_COVERAGE1(Name##Coverage, OT_LIST(FromGlyphs)) \
	/* ASSERT_STATIC_EXPR_ZERO (len(FromGlyphs) == len(ToGlyphs)) */

#define OT_SUBLOOKUP_LIGATURE_SUBST_FORMAT1(Name, FirstGlyphs, LigatureSetOffsets) \
	OT_SUBLOOKUP(Name, 1, \
		OT_OFFSET(Name, Name##Coverage) \
		OT_LABEL_END \
		OT_UARRAY(Name##LigatureSetOffsetsArray, OT_LIST(LigatureSetOffsets)) \
	) \
	OT_COVERAGE1(Name##Coverage, OT_LIST(FirstGlyphs)) \
	/* ASSERT_STATIC_EXPR_ZERO (len(FirstGlyphs) == len(LigatureSetOffsets)) */

#define OT_LIGATURE_SET(Name, LigatureSetOffsets) \
	OT_UARRAY(Name, OT_LIST(LigatureSetOffsets))

#define OT_LIGATURE(Name, Components, LigGlyph) \
	OT_LABEL_START(Name) \
	LigGlyph \
	OT_LABEL_END \
	OT_UHEADLESSARRAY(Name##ComponentsArray, OT_LIST(Components))

/*
 *
 * Start of Windows-1256 shaping table.
 *
 */

/* Table name. */
#define TABLE_NAME arabic_win1256_gsub_lookups

/* Table manifest. */
#define MANIFEST(Items) \
	OT_LABEL_START(manifest) \
	OT_UINT16(OT_COUNT(manifestData, 6)) \
	OT_LABEL(manifestData) \
	Items \
	OT_LABEL_END

#define MANIFEST_LOOKUP(Tag, Name) \
	Tag \
	OT_OFFSET(manifest, Name)

/* Shorthand. */
#define G	OT_GLYPHID

/*
 * Table Start
 */
OT_TABLE_START

/*
 * Manifest
 */
MANIFEST(
	MANIFEST_LOOKUP(OT_TAG('r','l','i','g'), rligLookup)
	MANIFEST_LOOKUP(OT_TAG('i','n','i','t'), initLookup)
	MANIFEST_LOOKUP(OT_TAG('m','e','d','i'), mediLookup)
	MANIFEST_LOOKUP(OT_TAG('f','i','n','a'), finaLookup)
	MANIFEST_LOOKUP(OT_TAG('r','l','i','g'), rligMarksLookup)
)

/*
 * Lookups
 */
OT_LOOKUP(initLookup, OT_LOOKUP_TYPE_SUBST_SINGLE, OT_LOOKUP_FLAG_IGNORE_MARKS,
	OT_OFFSET(initLookup, initmediSubLookup)
	OT_OFFSET(initLookup, initSubLookup)
)
OT_LOOKUP(mediLookup, OT_LOOKUP_TYPE_SUBST_SINGLE, OT_LOOKUP_FLAG_IGNORE_MARKS,
	OT_OFFSET(mediLookup, initmediSubLookup)
	OT_OFFSET(mediLookup, mediSubLookup)
	OT_OFFSET(mediLookup, medifinaLamAlefSubLookup)
)
OT_LOOKUP(finaLookup, OT_LOOKUP_TYPE_SUBST_SINGLE, OT_LOOKUP_FLAG_IGNORE_MARKS,
	OT_OFFSET(finaLookup, finaSubLookup)
	/* We don't need this one currently as the sequence inherits masks
	 * from the first item.  Just in case we change that in the future
	 * to be smart about Arabic masks when ligating... */
	OT_OFFSET(finaLookup, medifinaLamAlefSubLookup)
)
OT_LOOKUP(rligLookup, OT_LOOKUP_TYPE_SUBST_LIGATURE, OT_LOOKUP_FLAG_IGNORE_MARKS,
	OT_OFFSET(rligLookup, lamAlefLigaturesSubLookup)
)
OT_LOOKUP(rligMarksLookup, OT_LOOKUP_TYPE_SUBST_LIGATURE, 0,
	OT_OFFSET(rligMarksLookup, shaddaLigaturesSubLookup)
)

/*
 * init/medi/fina forms
 */
OT_SUBLOOKUP_SINGLE_SUBST_FORMAT2(initmediSubLookup,
	G(198)	G(200)	G(201)	G(202)	G(203)	G(204)	G(205)	G(206)	G(211)
	G(212)	G(213)	G(214)	G(223)	G(225)	G(227)	G(228)	G(236)	G(237),
	G(162)	G(4)	G(5)	G(5)	G(6)	G(7)	G(9)	G(11)	G(13)
	G(14)	G(15)	G(26)	G(140)	G(141)	G(142)	G(143)	G(154)	G(154)
)
OT_SUBLOOKUP_SINGLE_SUBST_FORMAT2(initSubLookup,
	G(218)	G(219)	G(221)	G(222)	G(229),
	G(27)	G(30)	G(128)	G(131)	G(144)
)
OT_SUBLOOKUP_SINGLE_SUBST_FORMAT2(mediSubLookup,
	G(218)	G(219)	G(221)	G(222)	G(229),
	G(28)	G(31)	G(129)	G(138)	G(149)
)
OT_SUBLOOKUP_SINGLE_SUBST_FORMAT2(finaSubLookup,
	G(194)	G(195)	G(197)	G(198)	G(199)	G(201)	G(204)	G(205)	G(206)
	G(218)	G(219)	G(229)	G(236)	G(237),
	G(2)	G(1)	G(3)	G(181)	G(0)	G(159)	G(8)	G(10)	G(12)
	G(29)	G(127)	G(152) G(160)	G(156)
)
OT_SUBLOOKUP_SINGLE_SUBST_FORMAT2(medifinaLamAlefSubLookup,
	G(165)	G(178)	G(180)	G(252),
	G(170)	G(179)	G(185)	G(255)
)

/*
 * Lam+Alef ligatures
 */
OT_SUBLOOKUP_LIGATURE_SUBST_FORMAT1(lamAlefLigaturesSubLookup,
	G(225),
	OT_OFFSET(lamAlefLigaturesSubLookup, lamLigatureSet)
)
OT_LIGATURE_SET(lamLigatureSet,
	OT_OFFSET(lamLigatureSet, lamInitLigature1)
	OT_OFFSET(lamLigatureSet, lamInitLigature2)
	OT_OFFSET(lamLigatureSet, lamInitLigature3)
	OT_OFFSET(lamLigatureSet, lamInitLigature4)
)
OT_LIGATURE(lamInitLigature1, G(199), G(165))
OT_LIGATURE(lamInitLigature2, G(195), G(178))
OT_LIGATURE(lamInitLigature3, G(194), G(180))
OT_LIGATURE(lamInitLigature4, G(197), G(252))

/*
 * Shadda ligatures
 */
OT_SUBLOOKUP_LIGATURE_SUBST_FORMAT1(shaddaLigaturesSubLookup,
	G(248),
	OT_OFFSET(shaddaLigaturesSubLookup, shaddaLigatureSet)
)
OT_LIGATURE_SET(shaddaLigatureSet,
	OT_OFFSET(shaddaLigatureSet, shaddaLigature1)
	OT_OFFSET(shaddaLigatureSet, shaddaLigature2)
	OT_OFFSET(shaddaLigatureSet, shaddaLigature3)
)
OT_LIGATURE(shaddaLigature1, G(243), G(172))
OT_LIGATURE(shaddaLigature2, G(245), G(173))
OT_LIGATURE(shaddaLigature3, G(246), G(175))

/*
 * Table end
 */
OT_TABLE_END

/*
 * Clean up
 */
#undef OT_TABLE_START
#undef OT_TABLE_END
#undef OT_LABEL_START
#undef OT_LABEL_END
#undef OT_UINT8
#undef OT_UINT16
#undef OT_DISTANCE
#undef OT_COUNT

/*
 * Include a second time to get the table data...
 */
#if 0
#include "hb.hh" /* Make check-includes.sh happy. */
#endif
#ifdef OT_MEASURE
#include "hb-ot-shape-complex-arabic-win1256.hh"
#endif

#define HB_OT_SHAPE_COMPLEX_ARABIC_WIN1256_HH
#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_WIN1256_HH */


text:
/*
 * Copyright © 2010,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
 */

#include "hb.hh"

#ifndef HB_NO_OT_SHAPE

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

static bool
compose_hebrew (const hb_ot_shape_normalize_context_t *c,
		hb_codepoint_t  a,
		hb_codepoint_t  b,
		hb_codepoint_t *ab)
{
  /* Hebrew presentation-form shaping.
   * https://bugzilla.mozilla.org/show_bug.cgi?id=728866
   * Hebrew presentation forms with dagesh, for characters U+05D0..05EA;
   * Note that some letters do not have a dagesh presForm encoded.
   */
  static const hb_codepoint_t sDageshForms[0x05EAu - 0x05D0u + 1] = {
    0xFB30u, /* ALEF */
    0xFB31u, /* BET */
    0xFB32u, /* GIMEL */
    0xFB33u, /* DALET */
    0xFB34u, /* HE */
    0xFB35u, /* VAV */
    0xFB36u, /* ZAYIN */
    0x0000u, /* HET */
    0xFB38u, /* TET */
    0xFB39u, /* YOD */
    0xFB3Au, /* FINAL KAF */
    0xFB3Bu, /* KAF */
    0xFB3Cu, /* LAMED */
    0x0000u, /* FINAL MEM */
    0xFB3Eu, /* MEM */
    0x0000u, /* FINAL NUN */
    0xFB40u, /* NUN */
    0xFB41u, /* SAMEKH */
    0x0000u, /* AYIN */
    0xFB43u, /* FINAL PE */
    0xFB44u, /* PE */
    0x0000u, /* FINAL TSADI */
    0xFB46u, /* TSADI */
    0xFB47u, /* QOF */
    0xFB48u, /* RESH */
    0xFB49u, /* SHIN */
    0xFB4Au /* TAV */
  };

  bool found = (bool) c->unicode->compose (a, b, ab);

#ifdef HB_NO_OT_SHAPE_COMPLEX_HEBREW_FALLBACK
  return found;
#endif

  if (!found && !c->plan->has_gpos_mark)
  {
      /* Special-case Hebrew presentation forms that are excluded from
       * standard normalization, but wanted for old fonts. */
      switch (b) {
      case 0x05B4u: /* HIRIQ */
	  if (a == 0x05D9u) { /* YOD */
	      *ab = 0xFB1Du;
	      found = true;
	  }
	  break;
      case 0x05B7u: /* patah */
	  if (a == 0x05F2u) { /* YIDDISH YOD YOD */
	      *ab = 0xFB1Fu;
	      found = true;
	  } else if (a == 0x05D0u) { /* ALEF */
	      *ab = 0xFB2Eu;
	      found = true;
	  }
	  break;
      case 0x05B8u: /* QAMATS */
	  if (a == 0x05D0u) { /* ALEF */
	      *ab = 0xFB2Fu;
	      found = true;
	  }
	  break;
      case 0x05B9u: /* HOLAM */
	  if (a == 0x05D5u) { /* VAV */
	      *ab = 0xFB4Bu;
	      found = true;
	  }
	  break;
      case 0x05BCu: /* DAGESH */
	  if (a >= 0x05D0u && a <= 0x05EAu) {
	      *ab = sDageshForms[a - 0x05D0u];
	      found = (*ab != 0);
	  } else if (a == 0xFB2Au) { /* SHIN WITH SHIN DOT */
	      *ab = 0xFB2Cu;
	      found = true;
	  } else if (a == 0xFB2Bu) { /* SHIN WITH SIN DOT */
	      *ab = 0xFB2Du;
	      found = true;
	  }
	  break;
      case 0x05BFu: /* RAFE */
	  switch (a) {
	  case 0x05D1u: /* BET */
	      *ab = 0xFB4Cu;
	      found = true;
	      break;
	  case 0x05DBu: /* KAF */
	      *ab = 0xFB4Du;
	      found = true;
	      break;
	  case 0x05E4u: /* PE */
	      *ab = 0xFB4Eu;
	      found = true;
	      break;
	  }
	  break;
      case 0x05C1u: /* SHIN DOT */
	  if (a == 0x05E9u) { /* SHIN */
	      *ab = 0xFB2Au;
	      found = true;
	  } else if (a == 0xFB49u) { /* SHIN WITH DAGESH */
	      *ab = 0xFB2Cu;
	      found = true;
	  }
	  break;
      case 0x05C2u: /* SIN DOT */
	  if (a == 0x05E9u) { /* SHIN */
	      *ab = 0xFB2Bu;
	      found = true;
	  } else if (a == 0xFB49u) { /* SHIN WITH DAGESH */
	      *ab = 0xFB2Du;
	      found = true;
	  }
	  break;
      }
  }

  return found;
}

const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hebrew =
{
  nullptr, /* collect_features */
  nullptr, /* override_features */
  nullptr, /* data_create */
  nullptr, /* data_destroy */
  nullptr, /* preprocess_text */
  nullptr, /* postprocess_glyphs */
  HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
  nullptr, /* decompose */
  compose_hebrew,
  nullptr, /* setup_masks */
  HB_TAG ('h','e','b','r'), /* gpos_tag. https://github.com/harfbuzz/harfbuzz/issues/347#issuecomment-267838368 */
  nullptr, /* reorder_marks */
  HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
  true, /* fallback_position */
};

#endif


text:
/*
 * Copyright © 2007,2008,2009,2010  Red Hat, Inc.
 * Copyright © 2012,2018  Google, Inc.
 * Copyright © 2019  Facebook, 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
 * Facebook Author(s): Behdad Esfahbod
 */

#ifndef HB_SERIALIZE_HH
#define HB_SERIALIZE_HH

#include "hb.hh"
#include "hb-blob.hh"
#include "hb-map.hh"
#include "hb-pool.hh"

/*
 * Serialize
 */

struct hb_serialize_context_t
{
  typedef unsigned objidx_t;

  enum whence_t {
     Head,	/* Relative to the current object head (default). */
     Tail,	/* Relative to the current object tail after packed. */
     Absolute	/* Absolute: from the start of the serialize buffer. */
   };

  struct object_t
  {
    void fini () { links.fini (); }

    bool operator == (const object_t &o) const
    {
      return (tail - head == o.tail - o.head)
	  && (links.length == o.links.length)
	  && 0 == hb_memcmp (head, o.head, tail - head)
	  && links.as_bytes () == o.links.as_bytes ();
    }
    uint32_t hash () const
    {
      return hb_bytes_t (head, tail - head).hash () ^
	     links.as_bytes ().hash ();
    }

    struct link_t
    {
      bool is_wide: 1;
      bool is_signed: 1;
      unsigned whence: 2;
      unsigned position: 28;
      unsigned bias;
      objidx_t objidx;
    };

    char *head;
    char *tail;
    hb_vector_t<link_t> links;
    object_t *next;
  };

  struct snapshot_t
  {
    char *head;
    char *tail;
    object_t *current; // Just for sanity check
    unsigned num_links;
  };

  snapshot_t snapshot ()
  { return snapshot_t { head, tail, current, current->links.length }; }

  hb_serialize_context_t (void *start_, unsigned int size) :
    start ((char *) start_),
    end (start + size),
    current (nullptr)
  { reset (); }
  ~hb_serialize_context_t () { fini (); }

  void fini ()
  {
    for (object_t *_ : ++hb_iter (packed)) _->fini ();
    packed.fini ();
    this->packed_map.fini ();

    while (current)
    {
      auto *_ = current;
      current = current->next;
      _->fini ();
    }
    object_pool.fini ();
  }

  bool in_error () const { return !this->successful; }

  void reset ()
  {
    this->successful = true;
    this->ran_out_of_room = false;
    this->head = this->start;
    this->tail = this->end;
    this->debug_depth = 0;

    fini ();
    this->packed.push (nullptr);
  }

  bool check_success (bool success)
  { return this->successful && (success || (err_other_error (), false)); }

  template <typename T1, typename T2>
  bool check_equal (T1 &&v1, T2 &&v2)
  { return check_success ((long long) v1 == (long long) v2); }

  template <typename T1, typename T2>
  bool check_assign (T1 &v1, T2 &&v2)
  { return check_equal (v1 = v2, v2); }

  template <typename T> bool propagate_error (T &&obj)
  { return check_success (!hb_deref (obj).in_error ()); }

  template <typename T1, typename... Ts> bool propagate_error (T1 &&o1, Ts&&... os)
  { return propagate_error (hb_forward<T1> (o1)) &&
	   propagate_error (hb_forward<Ts> (os)...); }

  /* To be called around main operation. */
  template <typename Type>
  Type *start_serialize ()
  {
    DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, +1,
		     "start [%p..%p] (%lu bytes)",
		     this->start, this->end,
		     (unsigned long) (this->end - this->start));

    assert (!current);
    return push<Type> ();
  }
  void end_serialize ()
  {
    DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, -1,
		     "end [%p..%p] serialized %u bytes; %s",
		     this->start, this->end,
		     (unsigned) (this->head - this->start),
		     this->successful ? "successful" : "UNSUCCESSFUL");

    propagate_error (packed, packed_map);

    if (unlikely (!current)) return;
    assert (!current->next);

    /* Only "pack" if there exist other objects... Otherwise, don't bother.
     * Saves a move. */
    if (packed.length <= 1)
      return;

    pop_pack (false);

    resolve_links ();
  }

  template <typename Type = void>
  Type *push ()
  {
    object_t *obj = object_pool.alloc ();
    if (unlikely (!obj))
      check_success (false);
    else
    {
      obj->head = head;
      obj->tail = tail;
      obj->next = current;
      current = obj;
    }
    return start_embed<Type> ();
  }
  void pop_discard ()
  {
    object_t *obj = current;
    if (unlikely (!obj)) return;
    current = current->next;
    revert (obj->head, obj->tail);
    obj->fini ();
    object_pool.free (obj);
  }

  /* Set share to false when an object is unlikely sharable with others
   * so not worth an attempt, or a contiguous table is serialized as
   * multiple consecutive objects in the reverse order so can't be shared.
   */
  objidx_t pop_pack (bool share=true)
  {
    object_t *obj = current;
    if (unlikely (!obj)) return 0;
    current = current->next;
    obj->tail = head;
    obj->next = nullptr;
    unsigned len = obj->tail - obj->head;
    head = obj->head; /* Rewind head. */

    if (!len)
    {
      assert (!obj->links.length);
      return 0;
    }

    objidx_t objidx;
    if (share)
    {
      objidx = packed_map.get (obj);
      if (objidx)
      {
	obj->fini ();
	return objidx;
      }
    }

    tail -= len;
    memmove (tail, obj->head, len);

    obj->head = tail;
    obj->tail = tail + len;

    packed.push (obj);

    if (unlikely (packed.in_error ()))
      return 0;

    objidx = packed.length - 1;

    if (share) packed_map.set (obj, objidx);

    return objidx;
  }

  void revert (snapshot_t snap)
  {
    assert (snap.current == current);
    current->links.shrink (snap.num_links);
    revert (snap.head, snap.tail);
  }
  void revert (char *snap_head,
	       char *snap_tail)
  {
    assert (snap_head <= head);
    assert (tail <= snap_tail);
    head = snap_head;
    tail = snap_tail;
    discard_stale_objects ();
  }

  void discard_stale_objects ()
  {
    while (packed.length > 1 &&
	   packed.tail ()->head < tail)
    {
      packed_map.del (packed.tail ());
      assert (!packed.tail ()->next);
      packed.tail ()->fini ();
      packed.pop ();
    }
    if (packed.length > 1)
      assert (packed.tail ()->head == tail);
  }

  template <typename T>
  void add_link (T &ofs, objidx_t objidx,
		 whence_t whence = Head,
		 unsigned bias = 0)
  {
    static_assert (sizeof (T) == 2 || sizeof (T) == 4, "");

    if (!objidx)
      return;

    assert (current);
    assert (current->head <= (const char *) &ofs);

    auto& link = *current->links.push ();

    link.is_wide = sizeof (T) == 4;
    link.is_signed = hb_is_signed (hb_unwrap_type (T));
    link.whence = (unsigned) whence;
    link.position = (const char *) &ofs - current->head;
    link.bias = bias;
    link.objidx = objidx;
  }

  unsigned to_bias (const void *base) const
  {
    if (!base) return 0;
    assert (current);
    assert (current->head <= (const char *) base);
    return (const char *) base - current->head;
  }

  void resolve_links ()
  {
    if (unlikely (in_error ())) return;

    assert (!current);
    assert (packed.length > 1);

    for (const object_t* parent : ++hb_iter (packed))
      for (const object_t::link_t &link : parent->links)
      {
	const object_t* child = packed[link.objidx];
	if (unlikely (!child)) { err_other_error(); return; }
	unsigned offset = 0;
	switch ((whence_t) link.whence) {
	case Head:     offset = child->head - parent->head; break;
	case Tail:     offset = child->head - parent->tail; break;
	case Absolute: offset = (head - start) + (child->head - tail); break;
	}

	assert (offset >= link.bias);
	offset -= link.bias;
	if (link.is_signed)
	{
	  if (link.is_wide)
	    assign_offset<int32_t> (parent, link, offset);
	  else
	    assign_offset<int16_t> (parent, link, offset);
	}
	else
	{
	  if (link.is_wide)
	    assign_offset<uint32_t> (parent, link, offset);
	  else
	    assign_offset<uint16_t> (parent, link, offset);
	}
      }
  }

  unsigned int length () const { return this->head - current->head; }

  void align (unsigned int alignment)
  {
    unsigned int l = length () % alignment;
    if (l)
      allocate_size<void> (alignment - l);
  }

  template <typename Type = void>
  Type *start_embed (const Type *obj HB_UNUSED = nullptr) const
  { return reinterpret_cast<Type *> (this->head); }
  template <typename Type>
  Type *start_embed (const Type &obj) const
  { return start_embed (hb_addressof (obj)); }

  /* Following two functions exist to allow setting breakpoint on. */
  void err_ran_out_of_room () { this->ran_out_of_room = true; }
  void err_other_error () { this->successful = false; }

  template <typename Type>
  Type *allocate_size (unsigned int size)
  {
    if (unlikely (!this->successful)) return nullptr;

    if (this->tail - this->head < ptrdiff_t (size))
    {
      err_ran_out_of_room ();
      this->successful = false;
      return nullptr;
    }
    memset (this->head, 0, size);
    char *ret = this->head;
    this->head += size;
    return reinterpret_cast<Type *> (ret);
  }

  template <typename Type>
  Type *allocate_min ()
  { return this->allocate_size<Type> (Type::min_size); }

  template <typename Type>
  Type *embed (const Type *obj)
  {
    unsigned int size = obj->get_size ();
    Type *ret = this->allocate_size<Type> (size);
    if (unlikely (!ret)) return nullptr;
    memcpy (ret, obj, size);
    return ret;
  }
  template <typename Type>
  Type *embed (const Type &obj)
  { return embed (hb_addressof (obj)); }

  template <typename Type, typename ...Ts> auto
  _copy (const Type &src, hb_priority<1>, Ts&&... ds) HB_RETURN
  (Type *, src.copy (this, hb_forward<Ts> (ds)...))

  template <typename Type> auto
  _copy (const Type &src, hb_priority<0>) -> decltype (&(hb_declval<Type> () = src))
  {
    Type *ret = this->allocate_size<Type> (sizeof (Type));
    if (unlikely (!ret)) return nullptr;
    *ret = src;
    return ret;
  }

  /* Like embed, but active: calls obj.operator=() or obj.copy() to transfer data
   * instead of memcpy(). */
  template <typename Type, typename ...Ts>
  Type *copy (const Type &src, Ts&&... ds)
  { return _copy (src, hb_prioritize, hb_forward<Ts> (ds)...); }
  template <typename Type, typename ...Ts>
  Type *copy (const Type *src, Ts&&... ds)
  { return copy (*src, hb_forward<Ts> (ds)...); }

  template<typename Iterator,
	   hb_requires (hb_is_iterator (Iterator)),
	   typename ...Ts>
  void copy_all (Iterator it, Ts&&... ds)
  { for (decltype (*it) _ : it) copy (_, hb_forward<Ts> (ds)...); }

  template <typename Type>
  hb_serialize_context_t& operator << (const Type &obj) & { embed (obj); return *this; }

  template <typename Type>
  Type *extend_size (Type *obj, unsigned int size)
  {
    assert (this->start <= (char *) obj);
    assert ((char *) obj <= this->head);
    assert ((char *) obj + size >= this->head);
    if (unlikely (!this->allocate_size<Type> (((char *) obj) + size - this->head))) return nullptr;
    return reinterpret_cast<Type *> (obj);
  }
  template <typename Type>
  Type *extend_size (Type &obj, unsigned int size)
  { return extend_size (hb_addressof (obj), size); }

  template <typename Type>
  Type *extend_min (Type *obj) { return extend_size (obj, obj->min_size); }
  template <typename Type>
  Type *extend_min (Type &obj) { return extend_min (hb_addressof (obj)); }

  template <typename Type, typename ...Ts>
  Type *extend (Type *obj, Ts&&... ds)
  { return extend_size (obj, obj->get_size (hb_forward<Ts> (ds)...)); }
  template <typename Type, typename ...Ts>
  Type *extend (Type &obj, Ts&&... ds)
  { return extend (hb_addressof (obj), hb_forward<Ts> (ds)...); }

  /* Output routines. */
  hb_bytes_t copy_bytes () const
  {
    assert (this->successful);
    /* Copy both items from head side and tail side... */
    unsigned int len = (this->head - this->start)
		     + (this->end  - this->tail);

    char *p = (char *) malloc (len);
    if (unlikely (!p)) return hb_bytes_t ();

    memcpy (p, this->start, this->head - this->start);
    memcpy (p + (this->head - this->start), this->tail, this->end - this->tail);
    return hb_bytes_t (p, len);
  }
  template <typename Type>
  Type *copy () const
  { return reinterpret_cast<Type *> ((char *) copy_bytes ().arrayZ); }
  hb_blob_t *copy_blob () const
  {
    hb_bytes_t b = copy_bytes ();
    return hb_blob_create (b.arrayZ, b.length,
			   HB_MEMORY_MODE_WRITABLE,
			   (char *) b.arrayZ, free);
  }

  private:
  template <typename T>
  void assign_offset (const object_t* parent, const object_t::link_t &link, unsigned offset)
  {
    auto &off = * ((BEInt<T, sizeof (T)> *) (parent->head + link.position));
    assert (0 == off);
    check_assign (off, offset);
  }

  public: /* TODO Make private. */
  char *start, *head, *tail, *end;
  unsigned int debug_depth;
  bool successful;
  bool ran_out_of_room;

  private:

  /* Object memory pool. */
  hb_pool_t<object_t> object_pool;

  /* Stack of currently under construction objects. */
  object_t *current;

  /* Stack of packed objects.  Object 0 is always nil object. */
  hb_vector_t<object_t *> packed;

  /* Map view of packed objects. */
  hb_hashmap_t<const object_t *, objidx_t, nullptr, 0> packed_map;
};

#endif /* HB_SERIALIZE_HH */


text:
/*
 * Copyright © 2018  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_H_IN
#error "Include <hb-ot.h> instead."
#endif

#ifndef HB_OT_DEPRECATED_H
#define HB_OT_DEPRECATED_H

#include "hb.h"
#include "hb-ot-name.h"

HB_BEGIN_DECLS

#ifndef HB_DISABLE_DEPRECATED

/* https://github.com/harfbuzz/harfbuzz/issues/1734 */
#define HB_MATH_GLYPH_PART_FLAG_EXTENDER HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER

/* Like hb_ot_layout_table_find_script, but takes zero-terminated array of scripts to test */
HB_EXTERN HB_DEPRECATED_FOR (hb_ot_layout_table_select_script) hb_bool_t
hb_ot_layout_table_choose_script (hb_face_t      *face,
				  hb_tag_t        table_tag,
				  const hb_tag_t *script_tags,
				  unsigned int   *script_index,
				  hb_tag_t       *chosen_script);

HB_EXTERN HB_DEPRECATED_FOR (hb_ot_layout_script_select_language) hb_bool_t
hb_ot_layout_script_find_language (hb_face_t    *face,
				   hb_tag_t      table_tag,
				   unsigned int  script_index,
				   hb_tag_t      language_tag,
				   unsigned int *language_index);

HB_EXTERN HB_DEPRECATED_FOR (hb_ot_tags_from_script_and_language) void
hb_ot_tags_from_script (hb_script_t  script,
			hb_tag_t    *script_tag_1,
			hb_tag_t    *script_tag_2);

HB_EXTERN HB_DEPRECATED_FOR (hb_ot_tags_from_script_and_language) hb_tag_t
hb_ot_tag_from_language (hb_language_t language);

/**
 * HB_OT_VAR_NO_AXIS_INDEX:
 *
 * Since: 1.4.2
 * Deprecated: 2.2.0
 */
#define HB_OT_VAR_NO_AXIS_INDEX		0xFFFFFFFFu

/**
 * hb_ot_var_axis_t:
 *
 * Since: 1.4.2
 * Deprecated: 2.2.0
 */
typedef struct hb_ot_var_axis_t
{
  hb_tag_t tag;
  hb_ot_name_id_t name_id;
  float min_value;
  float default_value;
  float max_value;
} hb_ot_var_axis_t;

HB_EXTERN HB_DEPRECATED_FOR (hb_ot_var_get_axis_infos) unsigned int
hb_ot_var_get_axes (hb_face_t        *face,
		    unsigned int      start_offset,
		    unsigned int     *axes_count /* IN/OUT */,
		    hb_ot_var_axis_t *axes_array /* OUT */);

HB_EXTERN HB_DEPRECATED_FOR (hb_ot_var_find_axis_info) hb_bool_t
hb_ot_var_find_axis (hb_face_t        *face,
		     hb_tag_t          axis_tag,
		     unsigned int     *axis_index,
		     hb_ot_var_axis_t *axis_info);

#endif

HB_END_DECLS

#endif /* HB_OT_DEPRECATED_H */