diff options
Diffstat (limited to 'thirdparty/harfbuzz')
173 files changed, 14950 insertions, 12815 deletions
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS.hh new file mode 100644 index 0000000000..224d6b746b --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS.hh @@ -0,0 +1,165 @@ +#ifndef OT_LAYOUT_GPOS_HH +#define OT_LAYOUT_GPOS_HH + +#include "../../hb-ot-layout-common.hh" +#include "../../hb-ot-layout-gsubgpos.hh" +#include "GPOS/Common.hh" +#include "GPOS/PosLookup.hh" + +namespace OT { +namespace Layout { + +static void +propagate_attachment_offsets (hb_glyph_position_t *pos, + unsigned int len, + unsigned int i, + hb_direction_t direction, + unsigned nesting_level = HB_MAX_NESTING_LEVEL); + +/* + * GPOS -- Glyph Positioning + * https://docs.microsoft.com/en-us/typography/opentype/spec/gpos + */ + +struct GPOS : GSUBGPOS +{ + static constexpr hb_tag_t tableTag = HB_OT_TAG_GPOS; + + using Lookup = GPOS_impl::PosLookup; + + const GPOS_impl::PosLookup& get_lookup (unsigned int i) const + { return static_cast<const GPOS_impl::PosLookup &> (GSUBGPOS::get_lookup (i)); } + + static inline void position_start (hb_font_t *font, hb_buffer_t *buffer); + static inline void position_finish_advances (hb_font_t *font, hb_buffer_t *buffer); + static inline void position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer); + + bool subset (hb_subset_context_t *c) const + { + hb_subset_layout_context_t l (c, tableTag, c->plan->gpos_lookups, c->plan->gpos_langsys, c->plan->gpos_features); + return GSUBGPOS::subset<GPOS_impl::PosLookup> (&l); + } + + bool sanitize (hb_sanitize_context_t *c) const + { return GSUBGPOS::sanitize<GPOS_impl::PosLookup> (c); } + + HB_INTERNAL bool is_blocklisted (hb_blob_t *blob, + hb_face_t *face) const; + + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + for (unsigned i = 0; i < GSUBGPOS::get_lookup_count (); i++) + { + if (!c->gpos_lookups->has (i)) continue; + const GPOS_impl::PosLookup &l = get_lookup (i); + l.dispatch (c); + } + } + + void closure_lookups (hb_face_t *face, + const hb_set_t *glyphs, + hb_set_t *lookup_indexes /* IN/OUT */) const + { GSUBGPOS::closure_lookups<GPOS_impl::PosLookup> (face, glyphs, lookup_indexes); } + + typedef GSUBGPOS::accelerator_t<GPOS> accelerator_t; +}; + + +static void +propagate_attachment_offsets (hb_glyph_position_t *pos, + unsigned int len, + unsigned int i, + hb_direction_t direction, + unsigned nesting_level) +{ + /* Adjusts offsets of attached glyphs (both cursive and mark) to accumulate + * offset of glyph they are attached to. */ + int chain = pos[i].attach_chain(), type = pos[i].attach_type(); + if (likely (!chain)) + return; + + pos[i].attach_chain() = 0; + + unsigned int j = (int) i + chain; + + if (unlikely (j >= len)) + return; + + if (unlikely (!nesting_level)) + return; + + propagate_attachment_offsets (pos, len, j, direction, nesting_level - 1); + + assert (!!(type & GPOS_impl::ATTACH_TYPE_MARK) ^ !!(type & GPOS_impl::ATTACH_TYPE_CURSIVE)); + + if (type & GPOS_impl::ATTACH_TYPE_CURSIVE) + { + if (HB_DIRECTION_IS_HORIZONTAL (direction)) + pos[i].y_offset += pos[j].y_offset; + else + pos[i].x_offset += pos[j].x_offset; + } + else /*if (type & GPOS_impl::ATTACH_TYPE_MARK)*/ + { + pos[i].x_offset += pos[j].x_offset; + pos[i].y_offset += pos[j].y_offset; + + assert (j < i); + if (HB_DIRECTION_IS_FORWARD (direction)) + for (unsigned int k = j; k < i; k++) { + pos[i].x_offset -= pos[k].x_advance; + pos[i].y_offset -= pos[k].y_advance; + } + else + for (unsigned int k = j + 1; k < i + 1; k++) { + pos[i].x_offset += pos[k].x_advance; + pos[i].y_offset += pos[k].y_advance; + } + } +} + +void +GPOS::position_start (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer) +{ + unsigned int count = buffer->len; + for (unsigned int i = 0; i < count; i++) + buffer->pos[i].attach_chain() = buffer->pos[i].attach_type() = 0; +} + +void +GPOS::position_finish_advances (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer HB_UNUSED) +{ + //_hb_buffer_assert_gsubgpos_vars (buffer); +} + +void +GPOS::position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer) +{ + _hb_buffer_assert_gsubgpos_vars (buffer); + + unsigned int len; + hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len); + hb_direction_t direction = buffer->props.direction; + + /* Handle attachments */ + if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT) + for (unsigned i = 0; i < len; i++) + propagate_attachment_offsets (pos, len, i, direction); + + if (unlikely (font->slant)) + { + for (unsigned i = 0; i < len; i++) + if (unlikely (pos[i].y_offset)) + pos[i].x_offset += _hb_roundf (font->slant_xy * pos[i].y_offset); + } +} + +} + +struct GPOS_accelerator_t : Layout::GPOS::accelerator_t { + GPOS_accelerator_t (hb_face_t *face) : Layout::GPOS::accelerator_t (face) {} +}; + +} + +#endif /* OT_LAYOUT_GPOS_HH */ diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/Anchor.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/Anchor.hh new file mode 100644 index 0000000000..bfe6b36afd --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/Anchor.hh @@ -0,0 +1,84 @@ +#ifndef OT_LAYOUT_GPOS_ANCHOR_HH +#define OT_LAYOUT_GPOS_ANCHOR_HH + +#include "AnchorFormat1.hh" +#include "AnchorFormat2.hh" +#include "AnchorFormat3.hh" + +namespace OT { +namespace Layout { +namespace GPOS_impl { + +struct Anchor +{ + protected: + union { + HBUINT16 format; /* Format identifier */ + AnchorFormat1 format1; + AnchorFormat2 format2; + AnchorFormat3 format3; + } u; + public: + DEFINE_SIZE_UNION (2, format); + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + if (!u.format.sanitize (c)) return_trace (false); + switch (u.format) { + case 1: return_trace (u.format1.sanitize (c)); + case 2: return_trace (u.format2.sanitize (c)); + case 3: return_trace (u.format3.sanitize (c)); + default:return_trace (true); + } + } + + void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id, + float *x, float *y) const + { + *x = *y = 0; + switch (u.format) { + case 1: u.format1.get_anchor (c, glyph_id, x, y); return; + case 2: u.format2.get_anchor (c, glyph_id, x, y); return; + case 3: u.format3.get_anchor (c, glyph_id, x, y); return; + default: return; + } + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + switch (u.format) { + case 1: return_trace (bool (reinterpret_cast<Anchor *> (u.format1.copy (c->serializer)))); + case 2: + if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING) + { + // AnchorFormat 2 just containins extra hinting information, so + // if hints are being dropped convert to format 1. + return_trace (bool (reinterpret_cast<Anchor *> (u.format1.copy (c->serializer)))); + } + return_trace (bool (reinterpret_cast<Anchor *> (u.format2.copy (c->serializer)))); + case 3: return_trace (bool (reinterpret_cast<Anchor *> (u.format3.copy (c->serializer, + c->plan->layout_variation_idx_map)))); + default:return_trace (false); + } + } + + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + switch (u.format) { + case 1: case 2: + return; + case 3: + u.format3.collect_variation_indices (c); + return; + default: return; + } + } +}; + +} +} +} + +#endif // OT_LAYOUT_GPOS_ANCHOR_HH diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorFormat1.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorFormat1.hh new file mode 100644 index 0000000000..738cc31bbf --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorFormat1.hh @@ -0,0 +1,46 @@ +#ifndef OT_LAYOUT_GPOS_ANCHORFORMAT1_HH +#define OT_LAYOUT_GPOS_ANCHORFORMAT1_HH + +namespace OT { +namespace Layout { +namespace GPOS_impl { + +struct AnchorFormat1 +{ + protected: + HBUINT16 format; /* Format identifier--format = 1 */ + FWORD xCoordinate; /* Horizontal value--in design units */ + FWORD yCoordinate; /* Vertical value--in design units */ + public: + DEFINE_SIZE_STATIC (6); + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id HB_UNUSED, + float *x, float *y) const + { + hb_font_t *font = c->font; + *x = font->em_fscale_x (xCoordinate); + *y = font->em_fscale_y (yCoordinate); + } + + AnchorFormat1* copy (hb_serialize_context_t *c) const + { + TRACE_SERIALIZE (this); + AnchorFormat1* out = c->embed<AnchorFormat1> (this); + if (!out) return_trace (out); + out->format = 1; + return_trace (out); + } +}; + + +} +} +} + +#endif // OT_LAYOUT_GPOS_ANCHORFORMAT1_HH diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorFormat2.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorFormat2.hh new file mode 100644 index 0000000000..70b4d19f53 --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorFormat2.hh @@ -0,0 +1,58 @@ +#ifndef OT_LAYOUT_GPOS_ANCHORFORMAT2_HH +#define OT_LAYOUT_GPOS_ANCHORFORMAT2_HH + +namespace OT { +namespace Layout { +namespace GPOS_impl { + +struct AnchorFormat2 +{ + + protected: + HBUINT16 format; /* Format identifier--format = 2 */ + FWORD xCoordinate; /* Horizontal value--in design units */ + FWORD yCoordinate; /* Vertical value--in design units */ + HBUINT16 anchorPoint; /* Index to glyph contour point */ + public: + DEFINE_SIZE_STATIC (8); + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id, + float *x, float *y) const + { + hb_font_t *font = c->font; + +#ifdef HB_NO_HINTING + *x = font->em_fscale_x (xCoordinate); + *y = font->em_fscale_y (yCoordinate); + return; +#endif + + unsigned int x_ppem = font->x_ppem; + unsigned int y_ppem = font->y_ppem; + hb_position_t cx = 0, cy = 0; + bool ret; + + ret = (x_ppem || y_ppem) && + font->get_glyph_contour_point_for_origin (glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy); + *x = ret && x_ppem ? cx : font->em_fscale_x (xCoordinate); + *y = ret && y_ppem ? cy : font->em_fscale_y (yCoordinate); + } + + AnchorFormat2* copy (hb_serialize_context_t *c) const + { + TRACE_SERIALIZE (this); + return_trace (c->embed<AnchorFormat2> (this)); + } +}; + +} +} +} + +#endif // OT_LAYOUT_GPOS_ANCHORFORMAT2_HH diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorFormat3.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorFormat3.hh new file mode 100644 index 0000000000..d77b4699be --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorFormat3.hh @@ -0,0 +1,70 @@ +#ifndef OT_LAYOUT_GPOS_ANCHORFORMAT3_HH +#define OT_LAYOUT_GPOS_ANCHORFORMAT3_HH + +namespace OT { +namespace Layout { +namespace GPOS_impl { + +struct AnchorFormat3 +{ + protected: + HBUINT16 format; /* Format identifier--format = 3 */ + FWORD xCoordinate; /* Horizontal value--in design units */ + FWORD yCoordinate; /* Vertical value--in design units */ + Offset16To<Device> + xDeviceTable; /* Offset to Device table for X + * coordinate-- from beginning of + * Anchor table (may be NULL) */ + Offset16To<Device> + yDeviceTable; /* Offset to Device table for Y + * coordinate-- from beginning of + * Anchor table (may be NULL) */ + public: + DEFINE_SIZE_STATIC (10); + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this)); + } + + void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id HB_UNUSED, + float *x, float *y) const + { + hb_font_t *font = c->font; + *x = font->em_fscale_x (xCoordinate); + *y = font->em_fscale_y (yCoordinate); + + if (font->x_ppem || font->num_coords) + *x += (this+xDeviceTable).get_x_delta (font, c->var_store, c->var_store_cache); + if (font->y_ppem || font->num_coords) + *y += (this+yDeviceTable).get_y_delta (font, c->var_store, c->var_store_cache); + } + + AnchorFormat3* copy (hb_serialize_context_t *c, + const hb_map_t *layout_variation_idx_map) const + { + TRACE_SERIALIZE (this); + if (!layout_variation_idx_map) return_trace (nullptr); + + auto *out = c->embed<AnchorFormat3> (this); + if (unlikely (!out)) return_trace (nullptr); + + out->xDeviceTable.serialize_copy (c, xDeviceTable, this, 0, hb_serialize_context_t::Head, layout_variation_idx_map); + out->yDeviceTable.serialize_copy (c, yDeviceTable, this, 0, hb_serialize_context_t::Head, layout_variation_idx_map); + return_trace (out); + } + + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + (this+xDeviceTable).collect_variation_indices (c->layout_variation_indices); + (this+yDeviceTable).collect_variation_indices (c->layout_variation_indices); + } +}; + + +} +} +} + +#endif // OT_LAYOUT_GPOS_ANCHORFORMAT3_HH diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorMatrix.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorMatrix.hh new file mode 100644 index 0000000000..c442efa1ea --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorMatrix.hh @@ -0,0 +1,77 @@ +#ifndef OT_LAYOUT_GPOS_ANCHORMATRIX_HH +#define OT_LAYOUT_GPOS_ANCHORMATRIX_HH + +namespace OT { +namespace Layout { +namespace GPOS_impl { + +struct AnchorMatrix +{ + HBUINT16 rows; /* Number of rows */ + UnsizedArrayOf<Offset16To<Anchor>> + matrixZ; /* Matrix of offsets to Anchor tables-- + * from beginning of AnchorMatrix table */ + public: + DEFINE_SIZE_ARRAY (2, matrixZ); + + bool sanitize (hb_sanitize_context_t *c, unsigned int cols) const + { + TRACE_SANITIZE (this); + if (!c->check_struct (this)) return_trace (false); + if (unlikely (hb_unsigned_mul_overflows (rows, cols))) return_trace (false); + unsigned int count = rows * cols; + if (!c->check_array (matrixZ.arrayZ, count)) return_trace (false); + for (unsigned int i = 0; i < count; i++) + if (!matrixZ[i].sanitize (c, this)) return_trace (false); + return_trace (true); + } + + const Anchor& get_anchor (unsigned int row, unsigned int col, + unsigned int cols, bool *found) const + { + *found = false; + if (unlikely (row >= rows || col >= cols)) return Null (Anchor); + *found = !matrixZ[row * cols + col].is_null (); + return this+matrixZ[row * cols + col]; + } + + template <typename Iterator, + hb_requires (hb_is_iterator (Iterator))> + void collect_variation_indices (hb_collect_variation_indices_context_t *c, + Iterator index_iter) const + { + for (unsigned i : index_iter) + (this+matrixZ[i]).collect_variation_indices (c); + } + + template <typename Iterator, + hb_requires (hb_is_iterator (Iterator))> + bool subset (hb_subset_context_t *c, + unsigned num_rows, + Iterator index_iter) const + { + TRACE_SUBSET (this); + + auto *out = c->serializer->start_embed (this); + + if (!index_iter) return_trace (false); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + + out->rows = num_rows; + for (const unsigned i : index_iter) + { + auto *offset = c->serializer->embed (matrixZ[i]); + if (!offset) return_trace (false); + offset->serialize_subset (c, matrixZ[i], this); + } + + return_trace (true); + } +}; + + +} +} +} + +#endif /* OT_LAYOUT_GPOS_ANCHORMATRIX_HH */ diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/ChainContextPos.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/ChainContextPos.hh new file mode 100644 index 0000000000..d551ac2a2b --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/ChainContextPos.hh @@ -0,0 +1,14 @@ +#ifndef OT_LAYOUT_GPOS_CHAINCONTEXTPOS_HH +#define OT_LAYOUT_GPOS_CHAINCONTEXTPOS_HH + +namespace OT { +namespace Layout { +namespace GPOS_impl { + +struct ChainContextPos : ChainContext {}; + +} +} +} + +#endif /* OT_LAYOUT_GPOS_CHAINCONTEXTPOS_HH */ diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/Common.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/Common.hh new file mode 100644 index 0000000000..e16c06729d --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/Common.hh @@ -0,0 +1,32 @@ +#ifndef OT_LAYOUT_GPOS_COMMON_HH +#define OT_LAYOUT_GPOS_COMMON_HH + +namespace OT { +namespace Layout { +namespace GPOS_impl { + +enum attach_type_t { + ATTACH_TYPE_NONE = 0X00, + + /* Each attachment should be either a mark or a cursive; can't be both. */ + ATTACH_TYPE_MARK = 0X01, + ATTACH_TYPE_CURSIVE = 0X02, +}; + +/* buffer **position** var allocations */ +#define attach_chain() var.i16[0] /* glyph to which this attaches to, relative to current glyphs; negative for going back, positive for forward. */ +#define attach_type() var.u8[2] /* attachment type */ +/* Note! if attach_chain() is zero, the value of attach_type() is irrelevant. */ + +template<typename Iterator, typename SrcLookup> +static void SinglePos_serialize (hb_serialize_context_t *c, + const SrcLookup *src, + Iterator it, + const hb_map_t *layout_variation_idx_map); + + +} +} +} + +#endif // OT_LAYOUT_GPOS_COMMON_HH diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/ContextPos.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/ContextPos.hh new file mode 100644 index 0000000000..2a01eaa3a6 --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/ContextPos.hh @@ -0,0 +1,14 @@ +#ifndef OT_LAYOUT_GPOS_CONTEXTPOS_HH +#define OT_LAYOUT_GPOS_CONTEXTPOS_HH + +namespace OT { +namespace Layout { +namespace GPOS_impl { + +struct ContextPos : Context {}; + +} +} +} + +#endif /* OT_LAYOUT_GPOS_CONTEXTPOS_HH */ diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/CursivePos.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/CursivePos.hh new file mode 100644 index 0000000000..c105cfb091 --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/CursivePos.hh @@ -0,0 +1,35 @@ +#ifndef OT_LAYOUT_GPOS_CURSIVEPOS_HH +#define OT_LAYOUT_GPOS_CURSIVEPOS_HH + +#include "CursivePosFormat1.hh" + +namespace OT { +namespace Layout { +namespace GPOS_impl { + +struct CursivePos +{ + protected: + union { + HBUINT16 format; /* Format identifier */ + CursivePosFormat1 format1; + } u; + + public: + template <typename context_t, typename ...Ts> + typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const + { + TRACE_DISPATCH (this, u.format); + if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); + switch (u.format) { + case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...)); + default:return_trace (c->default_return_value ()); + } + } +}; + +} +} +} + +#endif /* OT_LAYOUT_GPOS_CURSIVEPOS_HH */ diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/CursivePosFormat1.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/CursivePosFormat1.hh new file mode 100644 index 0000000000..e212fab976 --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/CursivePosFormat1.hh @@ -0,0 +1,281 @@ +#ifndef OT_LAYOUT_GPOS_CURSIVEPOSFORMAT1_HH +#define OT_LAYOUT_GPOS_CURSIVEPOSFORMAT1_HH + +#include "Anchor.hh" + +namespace OT { +namespace Layout { +namespace GPOS_impl { + +struct EntryExitRecord +{ + friend struct CursivePosFormat1; + + bool sanitize (hb_sanitize_context_t *c, const void *base) const + { + TRACE_SANITIZE (this); + return_trace (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base)); + } + + void collect_variation_indices (hb_collect_variation_indices_context_t *c, + const void *src_base) const + { + (src_base+entryAnchor).collect_variation_indices (c); + (src_base+exitAnchor).collect_variation_indices (c); + } + + EntryExitRecord* subset (hb_subset_context_t *c, + const void *src_base) const + { + TRACE_SERIALIZE (this); + auto *out = c->serializer->embed (this); + if (unlikely (!out)) return_trace (nullptr); + + out->entryAnchor.serialize_subset (c, entryAnchor, src_base); + out->exitAnchor.serialize_subset (c, exitAnchor, src_base); + return_trace (out); + } + + protected: + Offset16To<Anchor> + entryAnchor; /* Offset to EntryAnchor table--from + * beginning of CursivePos + * subtable--may be NULL */ + Offset16To<Anchor> + exitAnchor; /* Offset to ExitAnchor table--from + * beginning of CursivePos + * subtable--may be NULL */ + public: + DEFINE_SIZE_STATIC (4); +}; + +static void +reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent) { + int chain = pos[i].attach_chain(), type = pos[i].attach_type(); + if (likely (!chain || 0 == (type & ATTACH_TYPE_CURSIVE))) + return; + + pos[i].attach_chain() = 0; + + unsigned int j = (int) i + chain; + + /* Stop if we see new parent in the chain. */ + if (j == new_parent) + return; + + reverse_cursive_minor_offset (pos, j, direction, new_parent); + + if (HB_DIRECTION_IS_HORIZONTAL (direction)) + pos[j].y_offset = -pos[i].y_offset; + else + pos[j].x_offset = -pos[i].x_offset; + + pos[j].attach_chain() = -chain; + pos[j].attach_type() = type; +} + + +struct CursivePosFormat1 +{ + protected: + HBUINT16 format; /* Format identifier--format = 1 */ + Offset16To<Coverage> + coverage; /* Offset to Coverage table--from + * beginning of subtable */ + Array16Of<EntryExitRecord> + entryExitRecord; /* Array of EntryExit records--in + * Coverage Index order */ + public: + DEFINE_SIZE_ARRAY (6, entryExitRecord); + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this)); + } + + bool intersects (const hb_set_t *glyphs) const + { return (this+coverage).intersects (glyphs); } + + void closure_lookups (hb_closure_lookups_context_t *c) const {} + + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + + hb_zip (this+coverage, entryExitRecord) + | hb_filter (c->glyph_set, hb_first) + | hb_map (hb_second) + | hb_apply ([&] (const EntryExitRecord& record) { record.collect_variation_indices (c, this); }) + ; + } + + void collect_glyphs (hb_collect_glyphs_context_t *c) const + { if (unlikely (!(this+coverage).collect_coverage (c->input))) return; } + + const Coverage &get_coverage () const { return this+coverage; } + + bool apply (hb_ot_apply_context_t *c) const + { + TRACE_APPLY (this); + hb_buffer_t *buffer = c->buffer; + + const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage (buffer->cur().codepoint)]; + if (!this_record.entryAnchor) return_trace (false); + + hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; + skippy_iter.reset (buffer->idx, 1); + unsigned unsafe_from; + if (!skippy_iter.prev (&unsafe_from)) + { + buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1); + return_trace (false); + } + + const EntryExitRecord &prev_record = entryExitRecord[(this+coverage).get_coverage (buffer->info[skippy_iter.idx].codepoint)]; + if (!prev_record.exitAnchor) + { + buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); + return_trace (false); + } + + unsigned int i = skippy_iter.idx; + unsigned int j = buffer->idx; + + buffer->unsafe_to_break (i, j); + float entry_x, entry_y, exit_x, exit_y; + (this+prev_record.exitAnchor).get_anchor (c, buffer->info[i].codepoint, &exit_x, &exit_y); + (this+this_record.entryAnchor).get_anchor (c, buffer->info[j].codepoint, &entry_x, &entry_y); + + hb_glyph_position_t *pos = buffer->pos; + + hb_position_t d; + /* Main-direction adjustment */ + switch (c->direction) { + case HB_DIRECTION_LTR: + pos[i].x_advance = roundf (exit_x) + pos[i].x_offset; + + d = roundf (entry_x) + pos[j].x_offset; + pos[j].x_advance -= d; + pos[j].x_offset -= d; + break; + case HB_DIRECTION_RTL: + d = roundf (exit_x) + pos[i].x_offset; + pos[i].x_advance -= d; + pos[i].x_offset -= d; + + pos[j].x_advance = roundf (entry_x) + pos[j].x_offset; + break; + case HB_DIRECTION_TTB: + pos[i].y_advance = roundf (exit_y) + pos[i].y_offset; + + d = roundf (entry_y) + pos[j].y_offset; + pos[j].y_advance -= d; + pos[j].y_offset -= d; + break; + case HB_DIRECTION_BTT: + d = roundf (exit_y) + pos[i].y_offset; + pos[i].y_advance -= d; + pos[i].y_offset -= d; + + pos[j].y_advance = roundf (entry_y); + break; + case HB_DIRECTION_INVALID: + default: + break; + } + + /* Cross-direction adjustment */ + + /* We attach child to parent (think graph theory and rooted trees whereas + * the root stays on baseline and each node aligns itself against its + * parent. + * + * Optimize things for the case of RightToLeft, as that's most common in + * Arabic. */ + unsigned int child = i; + unsigned int parent = j; + hb_position_t x_offset = entry_x - exit_x; + hb_position_t y_offset = entry_y - exit_y; + if (!(c->lookup_props & LookupFlag::RightToLeft)) + { + unsigned int k = child; + child = parent; + parent = k; + x_offset = -x_offset; + y_offset = -y_offset; + } + + /* If child was already connected to someone else, walk through its old + * chain and reverse the link direction, such that the whole tree of its + * previous connection now attaches to new parent. Watch out for case + * where new parent is on the path from old chain... + */ + reverse_cursive_minor_offset (pos, child, c->direction, parent); + + pos[child].attach_type() = ATTACH_TYPE_CURSIVE; + pos[child].attach_chain() = (int) parent - (int) child; + buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT; + if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction))) + pos[child].y_offset = y_offset; + else + pos[child].x_offset = x_offset; + + /* If parent was attached to child, separate them. + * https://github.com/harfbuzz/harfbuzz/issues/2469 + */ + if (unlikely (pos[parent].attach_chain() == -pos[child].attach_chain())) + pos[parent].attach_chain() = 0; + + buffer->idx++; + return_trace (true); + } + + template <typename Iterator, + hb_requires (hb_is_iterator (Iterator))> + void serialize (hb_subset_context_t *c, + Iterator it, + const void *src_base) + { + if (unlikely (!c->serializer->extend_min ((*this)))) return; + this->format = 1; + this->entryExitRecord.len = it.len (); + + for (const EntryExitRecord& entry_record : + it + | hb_map (hb_second)) + entry_record.subset (c, src_base); + + auto glyphs = + + it + | hb_map_retains_sorting (hb_first) + ; + + coverage.serialize_serialize (c->serializer, glyphs); + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + const hb_set_t &glyphset = *c->plan->glyphset_gsub (); + const hb_map_t &glyph_map = *c->plan->glyph_map; + + auto *out = c->serializer->start_embed (*this); + if (unlikely (!out)) return_trace (false); + + auto it = + + hb_zip (this+coverage, entryExitRecord) + | hb_filter (glyphset, hb_first) + | hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, const EntryExitRecord&> p) -> hb_pair_t<hb_codepoint_t, const EntryExitRecord&> + { return hb_pair (glyph_map[p.first], p.second);}) + ; + + bool ret = bool (it); + out->serialize (c, it, this); + return_trace (ret); + } +}; + + +} +} +} + +#endif /* OT_LAYOUT_GPOS_CURSIVEPOSFORMAT1_HH */ diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/ExtensionPos.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/ExtensionPos.hh new file mode 100644 index 0000000000..d1808adab4 --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/ExtensionPos.hh @@ -0,0 +1,17 @@ +#ifndef OT_LAYOUT_GPOS_EXTENSIONPOS_HH +#define OT_LAYOUT_GPOS_EXTENSIONPOS_HH + +namespace OT { +namespace Layout { +namespace GPOS_impl { + +struct ExtensionPos : Extension<ExtensionPos> +{ + typedef struct PosLookupSubTable SubTable; +}; + +} +} +} + +#endif /* OT_LAYOUT_GPOS_EXTENSIONPOS_HH */ diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkArray.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkArray.hh new file mode 100644 index 0000000000..f8cddd1991 --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkArray.hh @@ -0,0 +1,113 @@ +#ifndef OT_LAYOUT_GPOS_MARKARRAY_HH +#define OT_LAYOUT_GPOS_MARKARRAY_HH + +#include "AnchorMatrix.hh" +#include "MarkRecord.hh" + +namespace OT { +namespace Layout { +namespace GPOS_impl { + +struct MarkArray : Array16Of<MarkRecord> /* Array of MarkRecords--in Coverage order */ +{ + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (Array16Of<MarkRecord>::sanitize (c, this)); + } + + bool apply (hb_ot_apply_context_t *c, + unsigned int mark_index, unsigned int glyph_index, + const AnchorMatrix &anchors, unsigned int class_count, + unsigned int glyph_pos) const + { + TRACE_APPLY (this); + hb_buffer_t *buffer = c->buffer; + const MarkRecord &record = Array16Of<MarkRecord>::operator[](mark_index); + unsigned int mark_class = record.klass; + + const Anchor& mark_anchor = this + record.markAnchor; + bool found; + const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count, &found); + /* If this subtable doesn't have an anchor for this base and this class, + * return false such that the subsequent subtables have a chance at it. */ + if (unlikely (!found)) return_trace (false); + + float mark_x, mark_y, base_x, base_y; + + buffer->unsafe_to_break (glyph_pos, buffer->idx + 1); + mark_anchor.get_anchor (c, buffer->cur().codepoint, &mark_x, &mark_y); + glyph_anchor.get_anchor (c, buffer->info[glyph_pos].codepoint, &base_x, &base_y); + + hb_glyph_position_t &o = buffer->cur_pos(); + o.x_offset = roundf (base_x - mark_x); + o.y_offset = roundf (base_y - mark_y); + o.attach_type() = ATTACH_TYPE_MARK; + o.attach_chain() = (int) glyph_pos - (int) buffer->idx; + buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT; + + buffer->idx++; + return_trace (true); + } + + template <typename Iterator, + hb_requires (hb_is_iterator (Iterator))> + bool subset (hb_subset_context_t *c, + Iterator coverage, + const hb_map_t *klass_mapping) const + { + TRACE_SUBSET (this); + const hb_set_t &glyphset = *c->plan->glyphset_gsub (); + + auto* out = c->serializer->start_embed (this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + + auto mark_iter = + + hb_zip (coverage, this->iter ()) + | hb_filter (glyphset, hb_first) + | hb_map (hb_second) + ; + + unsigned new_length = 0; + for (const auto& mark_record : mark_iter) { + if (unlikely (!mark_record.subset (c, this, klass_mapping))) + return_trace (false); + new_length++; + } + + if (unlikely (!c->serializer->check_assign (out->len, new_length, + HB_SERIALIZE_ERROR_ARRAY_OVERFLOW))) + return_trace (false); + + return_trace (true); + } +}; + +static void Markclass_closure_and_remap_indexes (const Coverage &mark_coverage, + const MarkArray &mark_array, + const hb_set_t &glyphset, + hb_map_t* klass_mapping /* INOUT */) +{ + hb_set_t orig_classes; + + + hb_zip (mark_coverage, mark_array) + | hb_filter (glyphset, hb_first) + | hb_map (hb_second) + | hb_map (&MarkRecord::get_class) + | hb_sink (orig_classes) + ; + + unsigned idx = 0; + for (auto klass : orig_classes.iter ()) + { + if (klass_mapping->has (klass)) continue; + klass_mapping->set (klass, idx); + idx++; + } +} + +} +} +} + +#endif /* OT_LAYOUT_GPOS_MARKARRAY_HH */ diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkBasePos.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkBasePos.hh new file mode 100644 index 0000000000..e99e13ff84 --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkBasePos.hh @@ -0,0 +1,35 @@ +#ifndef OT_LAYOUT_GPOS_MARKBASEPOS_HH +#define OT_LAYOUT_GPOS_MARKBASEPOS_HH + +#include "MarkBasePosFormat1.hh" + +namespace OT { +namespace Layout { +namespace GPOS_impl { + +struct MarkBasePos +{ + protected: + union { + HBUINT16 format; /* Format identifier */ + MarkBasePosFormat1 format1; + } u; + + public: + template <typename context_t, typename ...Ts> + typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const + { + TRACE_DISPATCH (this, u.format); + if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); + switch (u.format) { + case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...)); + default:return_trace (c->default_return_value ()); + } + } +}; + +} +} +} + +#endif /* OT_LAYOUT_GPOS_MARKBASEPOS_HH */ diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkBasePosFormat1.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkBasePosFormat1.hh new file mode 100644 index 0000000000..a10b806fe5 --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkBasePosFormat1.hh @@ -0,0 +1,217 @@ +#ifndef OT_LAYOUT_GPOS_MARKBASEPOSFORMAT1_HH +#define OT_LAYOUT_GPOS_MARKBASEPOSFORMAT1_HH + +#include "MarkArray.hh" + +namespace OT { +namespace Layout { +namespace GPOS_impl { + +typedef AnchorMatrix BaseArray; /* base-major-- + * in order of BaseCoverage Index--, + * mark-minor-- + * ordered by class--zero-based. */ + +struct MarkBasePosFormat1 +{ + protected: + HBUINT16 format; /* Format identifier--format = 1 */ + Offset16To<Coverage> + markCoverage; /* Offset to MarkCoverage table--from + * beginning of MarkBasePos subtable */ + Offset16To<Coverage> + baseCoverage; /* Offset to BaseCoverage table--from + * beginning of MarkBasePos subtable */ + HBUINT16 classCount; /* Number of classes defined for marks */ + Offset16To<MarkArray> + markArray; /* Offset to MarkArray table--from + * beginning of MarkBasePos subtable */ + Offset16To<BaseArray> + baseArray; /* Offset to BaseArray table--from + * beginning of MarkBasePos subtable */ + + public: + DEFINE_SIZE_STATIC (12); + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + markCoverage.sanitize (c, this) && + baseCoverage.sanitize (c, this) && + markArray.sanitize (c, this) && + baseArray.sanitize (c, this, (unsigned int) classCount)); + } + + bool intersects (const hb_set_t *glyphs) const + { + return (this+markCoverage).intersects (glyphs) && + (this+baseCoverage).intersects (glyphs); + } + + void closure_lookups (hb_closure_lookups_context_t *c) const {} + + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + + hb_zip (this+markCoverage, this+markArray) + | hb_filter (c->glyph_set, hb_first) + | hb_map (hb_second) + | hb_apply ([&] (const MarkRecord& record) { record.collect_variation_indices (c, &(this+markArray)); }) + ; + + hb_map_t klass_mapping; + Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, *c->glyph_set, &klass_mapping); + + unsigned basecount = (this+baseArray).rows; + auto base_iter = + + hb_zip (this+baseCoverage, hb_range (basecount)) + | hb_filter (c->glyph_set, hb_first) + | hb_map (hb_second) + ; + + hb_sorted_vector_t<unsigned> base_indexes; + for (const unsigned row : base_iter) + { + + hb_range ((unsigned) classCount) + | hb_filter (klass_mapping) + | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; }) + | hb_sink (base_indexes) + ; + } + (this+baseArray).collect_variation_indices (c, base_indexes.iter ()); + } + + void collect_glyphs (hb_collect_glyphs_context_t *c) const + { + if (unlikely (!(this+markCoverage).collect_coverage (c->input))) return; + if (unlikely (!(this+baseCoverage).collect_coverage (c->input))) return; + } + + const Coverage &get_coverage () const { return this+markCoverage; } + + bool apply (hb_ot_apply_context_t *c) const + { + TRACE_APPLY (this); + hb_buffer_t *buffer = c->buffer; + unsigned int mark_index = (this+markCoverage).get_coverage (buffer->cur().codepoint); + if (likely (mark_index == NOT_COVERED)) return_trace (false); + + /* Now we search backwards for a non-mark glyph */ + hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; + skippy_iter.reset (buffer->idx, 1); + skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks); + do { + unsigned unsafe_from; + if (!skippy_iter.prev (&unsafe_from)) + { + buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1); + return_trace (false); + } + + /* We only want to attach to the first of a MultipleSubst sequence. + * https://github.com/harfbuzz/harfbuzz/issues/740 + * Reject others... + * ...but stop if we find a mark in the MultipleSubst sequence: + * https://github.com/harfbuzz/harfbuzz/issues/1020 */ + if (!_hb_glyph_info_multiplied (&buffer->info[skippy_iter.idx]) || + 0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) || + (skippy_iter.idx == 0 || + _hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx - 1]) || + _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]) != + _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx - 1]) || + _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) != + _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx - 1]) + 1 + )) + break; + skippy_iter.reject (); + } while (true); + + /* Checking that matched glyph is actually a base glyph by GDEF is too strong; disabled */ + //if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { return_trace (false); } + + unsigned int base_index = (this+baseCoverage).get_coverage (buffer->info[skippy_iter.idx].codepoint); + if (base_index == NOT_COVERED) + { + buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); + return_trace (false); + } + + return_trace ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx)); + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + const hb_set_t &glyphset = *c->plan->glyphset_gsub (); + const hb_map_t &glyph_map = *c->plan->glyph_map; + + auto *out = c->serializer->start_embed (*this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + out->format = format; + + hb_map_t klass_mapping; + Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, glyphset, &klass_mapping); + + if (!klass_mapping.get_population ()) return_trace (false); + out->classCount = klass_mapping.get_population (); + + auto mark_iter = + + hb_zip (this+markCoverage, this+markArray) + | hb_filter (glyphset, hb_first) + ; + + hb_sorted_vector_t<hb_codepoint_t> new_coverage; + + mark_iter + | hb_map (hb_first) + | hb_map (glyph_map) + | hb_sink (new_coverage) + ; + + if (!out->markCoverage.serialize_serialize (c->serializer, new_coverage.iter ())) + return_trace (false); + + out->markArray.serialize_subset (c, markArray, this, + (this+markCoverage).iter (), + &klass_mapping); + + unsigned basecount = (this+baseArray).rows; + auto base_iter = + + hb_zip (this+baseCoverage, hb_range (basecount)) + | hb_filter (glyphset, hb_first) + ; + + new_coverage.reset (); + + base_iter + | hb_map (hb_first) + | hb_map (glyph_map) + | hb_sink (new_coverage) + ; + + if (!out->baseCoverage.serialize_serialize (c->serializer, new_coverage.iter ())) + return_trace (false); + + hb_sorted_vector_t<unsigned> base_indexes; + for (const unsigned row : + base_iter + | hb_map (hb_second)) + { + + hb_range ((unsigned) classCount) + | hb_filter (klass_mapping) + | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; }) + | hb_sink (base_indexes) + ; + } + + out->baseArray.serialize_subset (c, baseArray, this, + base_iter.len (), + base_indexes.iter ()); + + return_trace (true); + } +}; + + +} +} +} + +#endif /* OT_LAYOUT_GPOS_MARKBASEPOSFORMAT1_HH */ diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkLigPos.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkLigPos.hh new file mode 100644 index 0000000000..7e74aa73e0 --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkLigPos.hh @@ -0,0 +1,35 @@ +#ifndef OT_LAYOUT_GPOS_MARKLIGPOS_HH +#define OT_LAYOUT_GPOS_MARKLIGPOS_HH + +#include "MarkLigPosFormat1.hh" + +namespace OT { +namespace Layout { +namespace GPOS_impl { + +struct MarkLigPos +{ + protected: + union { + HBUINT16 format; /* Format identifier */ + MarkLigPosFormat1 format1; + } u; + + public: + template <typename context_t, typename ...Ts> + typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const + { + TRACE_DISPATCH (this, u.format); + if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); + switch (u.format) { + case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...)); + default:return_trace (c->default_return_value ()); + } + } +}; + +} +} +} + +#endif /* OT_LAYOUT_GPOS_MARKLIGPOS_HH */ diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkLigPosFormat1.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkLigPosFormat1.hh new file mode 100644 index 0000000000..4382aa6c6c --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkLigPosFormat1.hh @@ -0,0 +1,244 @@ +#ifndef OT_LAYOUT_GPOS_MARKLIGPOSFORMAT1_HH +#define OT_LAYOUT_GPOS_MARKLIGPOSFORMAT1_HH + +namespace OT { +namespace Layout { +namespace GPOS_impl { + +typedef AnchorMatrix LigatureAttach; /* component-major-- + * in order of writing direction--, + * mark-minor-- + * ordered by class--zero-based. */ + +/* Array of LigatureAttach tables ordered by LigatureCoverage Index */ +struct LigatureArray : List16OfOffset16To<LigatureAttach> +{ + template <typename Iterator, + hb_requires (hb_is_iterator (Iterator))> + bool subset (hb_subset_context_t *c, + Iterator coverage, + unsigned class_count, + const hb_map_t *klass_mapping) const + { + TRACE_SUBSET (this); + const hb_set_t &glyphset = *c->plan->glyphset_gsub (); + + auto *out = c->serializer->start_embed (this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + + for (const auto _ : + hb_zip (coverage, *this) + | hb_filter (glyphset, hb_first)) + { + auto *matrix = out->serialize_append (c->serializer); + if (unlikely (!matrix)) return_trace (false); + + const LigatureAttach& src = (this + _.second); + auto indexes = + + hb_range (src.rows * class_count) + | hb_filter ([=] (unsigned index) { return klass_mapping->has (index % class_count); }) + ; + matrix->serialize_subset (c, + _.second, + this, + src.rows, + indexes); + } + return_trace (this->len); + } +}; + +struct MarkLigPosFormat1 +{ + protected: + HBUINT16 format; /* Format identifier--format = 1 */ + Offset16To<Coverage> + markCoverage; /* Offset to Mark Coverage table--from + * beginning of MarkLigPos subtable */ + Offset16To<Coverage> + ligatureCoverage; /* Offset to Ligature Coverage + * table--from beginning of MarkLigPos + * subtable */ + HBUINT16 classCount; /* Number of defined mark classes */ + Offset16To<MarkArray> + markArray; /* Offset to MarkArray table--from + * beginning of MarkLigPos subtable */ + Offset16To<LigatureArray> + ligatureArray; /* Offset to LigatureArray table--from + * beginning of MarkLigPos subtable */ + public: + DEFINE_SIZE_STATIC (12); + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + markCoverage.sanitize (c, this) && + ligatureCoverage.sanitize (c, this) && + markArray.sanitize (c, this) && + ligatureArray.sanitize (c, this, (unsigned int) classCount)); + } + + bool intersects (const hb_set_t *glyphs) const + { + return (this+markCoverage).intersects (glyphs) && + (this+ligatureCoverage).intersects (glyphs); + } + + void closure_lookups (hb_closure_lookups_context_t *c) const {} + + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + + hb_zip (this+markCoverage, this+markArray) + | hb_filter (c->glyph_set, hb_first) + | hb_map (hb_second) + | hb_apply ([&] (const MarkRecord& record) { record.collect_variation_indices (c, &(this+markArray)); }) + ; + + hb_map_t klass_mapping; + Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, *c->glyph_set, &klass_mapping); + + unsigned ligcount = (this+ligatureArray).len; + auto lig_iter = + + hb_zip (this+ligatureCoverage, hb_range (ligcount)) + | hb_filter (c->glyph_set, hb_first) + | hb_map (hb_second) + ; + + const LigatureArray& lig_array = this+ligatureArray; + for (const unsigned i : lig_iter) + { + hb_sorted_vector_t<unsigned> lig_indexes; + unsigned row_count = lig_array[i].rows; + for (unsigned row : + hb_range (row_count)) + { + + hb_range ((unsigned) classCount) + | hb_filter (klass_mapping) + | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; }) + | hb_sink (lig_indexes) + ; + } + + lig_array[i].collect_variation_indices (c, lig_indexes.iter ()); + } + } + + void collect_glyphs (hb_collect_glyphs_context_t *c) const + { + if (unlikely (!(this+markCoverage).collect_coverage (c->input))) return; + if (unlikely (!(this+ligatureCoverage).collect_coverage (c->input))) return; + } + + const Coverage &get_coverage () const { return this+markCoverage; } + + bool apply (hb_ot_apply_context_t *c) const + { + TRACE_APPLY (this); + hb_buffer_t *buffer = c->buffer; + unsigned int mark_index = (this+markCoverage).get_coverage (buffer->cur().codepoint); + if (likely (mark_index == NOT_COVERED)) return_trace (false); + + /* Now we search backwards for a non-mark glyph */ + hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; + skippy_iter.reset (buffer->idx, 1); + skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks); + unsigned unsafe_from; + if (!skippy_iter.prev (&unsafe_from)) + { + buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1); + return_trace (false); + } + + /* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */ + //if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { return_trace (false); } + + unsigned int j = skippy_iter.idx; + unsigned int lig_index = (this+ligatureCoverage).get_coverage (buffer->info[j].codepoint); + if (lig_index == NOT_COVERED) + { + buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); + return_trace (false); + } + + const LigatureArray& lig_array = this+ligatureArray; + const LigatureAttach& lig_attach = lig_array[lig_index]; + + /* Find component to attach to */ + unsigned int comp_count = lig_attach.rows; + if (unlikely (!comp_count)) + { + buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); + return_trace (false); + } + + /* We must now check whether the ligature ID of the current mark glyph + * is identical to the ligature ID of the found ligature. If yes, we + * can directly use the component index. If not, we attach the mark + * glyph to the last component of the ligature. */ + unsigned int comp_index; + unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[j]); + unsigned int mark_id = _hb_glyph_info_get_lig_id (&buffer->cur()); + unsigned int mark_comp = _hb_glyph_info_get_lig_comp (&buffer->cur()); + if (lig_id && lig_id == mark_id && mark_comp > 0) + comp_index = hb_min (comp_count, _hb_glyph_info_get_lig_comp (&buffer->cur())) - 1; + else + comp_index = comp_count - 1; + + return_trace ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j)); + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + const hb_set_t &glyphset = *c->plan->glyphset_gsub (); + const hb_map_t &glyph_map = *c->plan->glyph_map; + + auto *out = c->serializer->start_embed (*this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + out->format = format; + + hb_map_t klass_mapping; + Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, glyphset, &klass_mapping); + + if (!klass_mapping.get_population ()) return_trace (false); + out->classCount = klass_mapping.get_population (); + + auto mark_iter = + + hb_zip (this+markCoverage, this+markArray) + | hb_filter (glyphset, hb_first) + ; + + auto new_mark_coverage = + + mark_iter + | hb_map_retains_sorting (hb_first) + | hb_map_retains_sorting (glyph_map) + ; + + if (!out->markCoverage.serialize_serialize (c->serializer, new_mark_coverage)) + return_trace (false); + + out->markArray.serialize_subset (c, markArray, this, + (this+markCoverage).iter (), + &klass_mapping); + + auto new_ligature_coverage = + + hb_iter (this + ligatureCoverage) + | hb_filter (glyphset) + | hb_map_retains_sorting (glyph_map) + ; + + if (!out->ligatureCoverage.serialize_serialize (c->serializer, new_ligature_coverage)) + return_trace (false); + + out->ligatureArray.serialize_subset (c, ligatureArray, this, + hb_iter (this+ligatureCoverage), classCount, &klass_mapping); + + return_trace (true); + } + +}; + +} +} +} + +#endif /* OT_LAYOUT_GPOS_MARKLIGPOSFORMAT1_HH */ diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkMarkPos.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkMarkPos.hh new file mode 100644 index 0000000000..c0eee6d54c --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkMarkPos.hh @@ -0,0 +1,36 @@ +#ifndef OT_LAYOUT_GPOS_MARKMARKPOS_HH +#define OT_LAYOUT_GPOS_MARKMARKPOS_HH + +#include "MarkMarkPosFormat1.hh" + +namespace OT { +namespace Layout { +namespace GPOS_impl { + +struct MarkMarkPos +{ + protected: + union { + HBUINT16 format; /* Format identifier */ + MarkMarkPosFormat1 format1; + } u; + + public: + template <typename context_t, typename ...Ts> + typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const + { + TRACE_DISPATCH (this, u.format); + if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); + switch (u.format) { + case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...)); + default:return_trace (c->default_return_value ()); + } + } +}; + + +} +} +} + +#endif /* OT_LAYOUT_GPOS_MARKMARKPOS_HH */ diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh new file mode 100644 index 0000000000..c48a74f773 --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh @@ -0,0 +1,227 @@ +#ifndef OT_LAYOUT_GPOS_MARKMARKPOSFORMAT1_HH +#define OT_LAYOUT_GPOS_MARKMARKPOSFORMAT1_HH + +#include "MarkMarkPosFormat1.hh" + +namespace OT { +namespace Layout { +namespace GPOS_impl { + +typedef AnchorMatrix Mark2Array; /* mark2-major-- + * in order of Mark2Coverage Index--, + * mark1-minor-- + * ordered by class--zero-based. */ + +struct MarkMarkPosFormat1 +{ + protected: + HBUINT16 format; /* Format identifier--format = 1 */ + Offset16To<Coverage> + mark1Coverage; /* Offset to Combining Mark1 Coverage + * table--from beginning of MarkMarkPos + * subtable */ + Offset16To<Coverage> + mark2Coverage; /* Offset to Combining Mark2 Coverage + * table--from beginning of MarkMarkPos + * subtable */ + HBUINT16 classCount; /* Number of defined mark classes */ + Offset16To<MarkArray> + mark1Array; /* Offset to Mark1Array table--from + * beginning of MarkMarkPos subtable */ + Offset16To<Mark2Array> + mark2Array; /* Offset to Mark2Array table--from + * beginning of MarkMarkPos subtable */ + public: + DEFINE_SIZE_STATIC (12); + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + mark1Coverage.sanitize (c, this) && + mark2Coverage.sanitize (c, this) && + mark1Array.sanitize (c, this) && + mark2Array.sanitize (c, this, (unsigned int) classCount)); + } + + bool intersects (const hb_set_t *glyphs) const + { + return (this+mark1Coverage).intersects (glyphs) && + (this+mark2Coverage).intersects (glyphs); + } + + void closure_lookups (hb_closure_lookups_context_t *c) const {} + + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + + hb_zip (this+mark1Coverage, this+mark1Array) + | hb_filter (c->glyph_set, hb_first) + | hb_map (hb_second) + | hb_apply ([&] (const MarkRecord& record) { record.collect_variation_indices (c, &(this+mark1Array)); }) + ; + + hb_map_t klass_mapping; + Markclass_closure_and_remap_indexes (this+mark1Coverage, this+mark1Array, *c->glyph_set, &klass_mapping); + + unsigned mark2_count = (this+mark2Array).rows; + auto mark2_iter = + + hb_zip (this+mark2Coverage, hb_range (mark2_count)) + | hb_filter (c->glyph_set, hb_first) + | hb_map (hb_second) + ; + + hb_sorted_vector_t<unsigned> mark2_indexes; + for (const unsigned row : mark2_iter) + { + + hb_range ((unsigned) classCount) + | hb_filter (klass_mapping) + | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; }) + | hb_sink (mark2_indexes) + ; + } + (this+mark2Array).collect_variation_indices (c, mark2_indexes.iter ()); + } + + void collect_glyphs (hb_collect_glyphs_context_t *c) const + { + if (unlikely (!(this+mark1Coverage).collect_coverage (c->input))) return; + if (unlikely (!(this+mark2Coverage).collect_coverage (c->input))) return; + } + + const Coverage &get_coverage () const { return this+mark1Coverage; } + + bool apply (hb_ot_apply_context_t *c) const + { + TRACE_APPLY (this); + hb_buffer_t *buffer = c->buffer; + unsigned int mark1_index = (this+mark1Coverage).get_coverage (buffer->cur().codepoint); + if (likely (mark1_index == NOT_COVERED)) return_trace (false); + + /* now we search backwards for a suitable mark glyph until a non-mark glyph */ + hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; + skippy_iter.reset (buffer->idx, 1); + skippy_iter.set_lookup_props (c->lookup_props & ~LookupFlag::IgnoreFlags); + unsigned unsafe_from; + if (!skippy_iter.prev (&unsafe_from)) + { + buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1); + return_trace (false); + } + + if (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx])) + { + buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); + return_trace (false); + } + + unsigned int j = skippy_iter.idx; + + unsigned int id1 = _hb_glyph_info_get_lig_id (&buffer->cur()); + unsigned int id2 = _hb_glyph_info_get_lig_id (&buffer->info[j]); + unsigned int comp1 = _hb_glyph_info_get_lig_comp (&buffer->cur()); + unsigned int comp2 = _hb_glyph_info_get_lig_comp (&buffer->info[j]); + + if (likely (id1 == id2)) + { + if (id1 == 0) /* Marks belonging to the same base. */ + goto good; + else if (comp1 == comp2) /* Marks belonging to the same ligature component. */ + goto good; + } + else + { + /* If ligature ids don't match, it may be the case that one of the marks + * itself is a ligature. In which case match. */ + if ((id1 > 0 && !comp1) || (id2 > 0 && !comp2)) + goto good; + } + + /* Didn't match. */ + buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); + return_trace (false); + + good: + unsigned int mark2_index = (this+mark2Coverage).get_coverage (buffer->info[j].codepoint); + if (mark2_index == NOT_COVERED) + { + buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); + return_trace (false); + } + + return_trace ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j)); + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + const hb_set_t &glyphset = *c->plan->glyphset_gsub (); + const hb_map_t &glyph_map = *c->plan->glyph_map; + + auto *out = c->serializer->start_embed (*this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + out->format = format; + + hb_map_t klass_mapping; + Markclass_closure_and_remap_indexes (this+mark1Coverage, this+mark1Array, glyphset, &klass_mapping); + + if (!klass_mapping.get_population ()) return_trace (false); + out->classCount = klass_mapping.get_population (); + + auto mark1_iter = + + hb_zip (this+mark1Coverage, this+mark1Array) + | hb_filter (glyphset, hb_first) + ; + + hb_sorted_vector_t<hb_codepoint_t> new_coverage; + + mark1_iter + | hb_map (hb_first) + | hb_map (glyph_map) + | hb_sink (new_coverage) + ; + + if (!out->mark1Coverage.serialize_serialize (c->serializer, new_coverage.iter ())) + return_trace (false); + + out->mark1Array.serialize_subset (c, mark1Array, this, + (this+mark1Coverage).iter (), + &klass_mapping); + + unsigned mark2count = (this+mark2Array).rows; + auto mark2_iter = + + hb_zip (this+mark2Coverage, hb_range (mark2count)) + | hb_filter (glyphset, hb_first) + ; + + new_coverage.reset (); + + mark2_iter + | hb_map (hb_first) + | hb_map (glyph_map) + | hb_sink (new_coverage) + ; + + if (!out->mark2Coverage.serialize_serialize (c->serializer, new_coverage.iter ())) + return_trace (false); + + hb_sorted_vector_t<unsigned> mark2_indexes; + for (const unsigned row : + mark2_iter + | hb_map (hb_second)) + { + + hb_range ((unsigned) classCount) + | hb_filter (klass_mapping) + | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; }) + | hb_sink (mark2_indexes) + ; + } + + out->mark2Array.serialize_subset (c, mark2Array, this, mark2_iter.len (), mark2_indexes.iter ()); + + return_trace (true); + } +}; + + +} +} +} + +#endif /* OT_LAYOUT_GPOS_MARKMARKPOSFORMAT1_HH */ diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkRecord.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkRecord.hh new file mode 100644 index 0000000000..7a514453ae --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkRecord.hh @@ -0,0 +1,52 @@ +#ifndef OT_LAYOUT_GPOS_MARKRECORD_HH +#define OT_LAYOUT_GPOS_MARKRECORD_HH + +namespace OT { +namespace Layout { +namespace GPOS_impl { + +struct MarkRecord +{ + friend struct MarkArray; + + protected: + HBUINT16 klass; /* Class defined for this mark */ + Offset16To<Anchor> + markAnchor; /* Offset to Anchor table--from + * beginning of MarkArray table */ + public: + DEFINE_SIZE_STATIC (4); + + unsigned get_class () const { return (unsigned) klass; } + bool sanitize (hb_sanitize_context_t *c, const void *base) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && markAnchor.sanitize (c, base)); + } + + MarkRecord *subset (hb_subset_context_t *c, + const void *src_base, + const hb_map_t *klass_mapping) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (this); + if (unlikely (!out)) return_trace (nullptr); + + out->klass = klass_mapping->get (klass); + out->markAnchor.serialize_subset (c, markAnchor, src_base); + return_trace (out); + } + + void collect_variation_indices (hb_collect_variation_indices_context_t *c, + const void *src_base) const + { + (src_base+markAnchor).collect_variation_indices (c); + } +}; + + +} +} +} + +#endif /* OT_LAYOUT_GPOS_MARKRECORD_HH */ diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPos.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPos.hh new file mode 100644 index 0000000000..8479178d38 --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPos.hh @@ -0,0 +1,38 @@ +#ifndef OT_LAYOUT_GPOS_PAIRPOS_HH +#define OT_LAYOUT_GPOS_PAIRPOS_HH + +#include "PairPosFormat1.hh" +#include "PairPosFormat2.hh" + +namespace OT { +namespace Layout { +namespace GPOS_impl { + +struct PairPos +{ + protected: + union { + HBUINT16 format; /* Format identifier */ + PairPosFormat1 format1; + PairPosFormat2 format2; + } u; + + public: + template <typename context_t, typename ...Ts> + typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const + { + TRACE_DISPATCH (this, u.format); + if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); + switch (u.format) { + case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...)); + case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...)); + default:return_trace (c->default_return_value ()); + } + } +}; + +} +} +} + +#endif // OT_LAYOUT_GPOS_PAIRPOS_HH diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat1.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat1.hh new file mode 100644 index 0000000000..35a2db2d45 --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat1.hh @@ -0,0 +1,420 @@ +#ifndef OT_LAYOUT_GPOS_PAIRPOSFORMAT1_HH +#define OT_LAYOUT_GPOS_PAIRPOSFORMAT1_HH + +namespace OT { +namespace Layout { +namespace GPOS_impl { + +struct PairValueRecord +{ + friend struct PairSet; + + int cmp (hb_codepoint_t k) const + { return secondGlyph.cmp (k); } + + struct context_t + { + const void *base; + const ValueFormat *valueFormats; + const ValueFormat *newFormats; + unsigned len1; /* valueFormats[0].get_len() */ + const hb_map_t *glyph_map; + const hb_map_t *layout_variation_idx_map; + }; + + bool subset (hb_subset_context_t *c, + context_t *closure) const + { + TRACE_SERIALIZE (this); + auto *s = c->serializer; + auto *out = s->start_embed (*this); + if (unlikely (!s->extend_min (out))) return_trace (false); + + out->secondGlyph = (*closure->glyph_map)[secondGlyph]; + + closure->valueFormats[0].copy_values (s, + closure->newFormats[0], + closure->base, &values[0], + closure->layout_variation_idx_map); + closure->valueFormats[1].copy_values (s, + closure->newFormats[1], + closure->base, + &values[closure->len1], + closure->layout_variation_idx_map); + + return_trace (true); + } + + void collect_variation_indices (hb_collect_variation_indices_context_t *c, + const ValueFormat *valueFormats, + const void *base) const + { + unsigned record1_len = valueFormats[0].get_len (); + unsigned record2_len = valueFormats[1].get_len (); + const hb_array_t<const Value> values_array = values.as_array (record1_len + record2_len); + + if (valueFormats[0].has_device ()) + valueFormats[0].collect_variation_indices (c, base, values_array.sub_array (0, record1_len)); + + if (valueFormats[1].has_device ()) + valueFormats[1].collect_variation_indices (c, base, values_array.sub_array (record1_len, record2_len)); + } + + bool intersects (const hb_set_t& glyphset) const + { + return glyphset.has(secondGlyph); + } + + const Value* get_values_1 () const + { + return &values[0]; + } + + const Value* get_values_2 (ValueFormat format1) const + { + return &values[format1.get_len ()]; + } + + protected: + HBGlyphID16 secondGlyph; /* GlyphID of second glyph in the + * pair--first glyph is listed in the + * Coverage table */ + ValueRecord values; /* Positioning data for the first glyph + * followed by for second glyph */ + public: + DEFINE_SIZE_ARRAY (2, values); +}; + +struct PairSet +{ + friend struct PairPosFormat1; + + bool intersects (const hb_set_t *glyphs, + const ValueFormat *valueFormats) const + { + unsigned int len1 = valueFormats[0].get_len (); + unsigned int len2 = valueFormats[1].get_len (); + unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2); + + const PairValueRecord *record = &firstPairValueRecord; + unsigned int count = len; + for (unsigned int i = 0; i < count; i++) + { + if (glyphs->has (record->secondGlyph)) + return true; + record = &StructAtOffset<const PairValueRecord> (record, record_size); + } + return false; + } + + void collect_glyphs (hb_collect_glyphs_context_t *c, + const ValueFormat *valueFormats) const + { + unsigned int len1 = valueFormats[0].get_len (); + unsigned int len2 = valueFormats[1].get_len (); + unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2); + + const PairValueRecord *record = &firstPairValueRecord; + c->input->add_array (&record->secondGlyph, len, record_size); + } + + void collect_variation_indices (hb_collect_variation_indices_context_t *c, + const ValueFormat *valueFormats) const + { + unsigned len1 = valueFormats[0].get_len (); + unsigned len2 = valueFormats[1].get_len (); + unsigned record_size = HBUINT16::static_size * (1 + len1 + len2); + + const PairValueRecord *record = &firstPairValueRecord; + unsigned count = len; + for (unsigned i = 0; i < count; i++) + { + if (c->glyph_set->has (record->secondGlyph)) + { record->collect_variation_indices (c, valueFormats, this); } + + record = &StructAtOffset<const PairValueRecord> (record, record_size); + } + } + + bool apply (hb_ot_apply_context_t *c, + const ValueFormat *valueFormats, + unsigned int pos) const + { + TRACE_APPLY (this); + hb_buffer_t *buffer = c->buffer; + unsigned int len1 = valueFormats[0].get_len (); + unsigned int len2 = valueFormats[1].get_len (); + unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2); + + const PairValueRecord *record = hb_bsearch (buffer->info[pos].codepoint, + &firstPairValueRecord, + len, + record_size); + if (record) + { + bool applied_first = valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos()); + bool applied_second = valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]); + if (applied_first || applied_second) + buffer->unsafe_to_break (buffer->idx, pos + 1); + if (len2) + pos++; + buffer->idx = pos; + return_trace (true); + } + buffer->unsafe_to_concat (buffer->idx, pos + 1); + return_trace (false); + } + + bool subset (hb_subset_context_t *c, + const ValueFormat valueFormats[2], + const ValueFormat newFormats[2]) const + { + TRACE_SUBSET (this); + auto snap = c->serializer->snapshot (); + + auto *out = c->serializer->start_embed (*this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + out->len = 0; + + const hb_set_t &glyphset = *c->plan->glyphset_gsub (); + const hb_map_t &glyph_map = *c->plan->glyph_map; + + unsigned len1 = valueFormats[0].get_len (); + unsigned len2 = valueFormats[1].get_len (); + unsigned record_size = HBUINT16::static_size + Value::static_size * (len1 + len2); + + PairValueRecord::context_t context = + { + this, + valueFormats, + newFormats, + len1, + &glyph_map, + c->plan->layout_variation_idx_map + }; + + const PairValueRecord *record = &firstPairValueRecord; + unsigned count = len, num = 0; + for (unsigned i = 0; i < count; i++) + { + if (glyphset.has (record->secondGlyph) + && record->subset (c, &context)) num++; + record = &StructAtOffset<const PairValueRecord> (record, record_size); + } + + out->len = num; + if (!num) c->serializer->revert (snap); + return_trace (num); + } + + struct sanitize_closure_t + { + const ValueFormat *valueFormats; + unsigned int len1; /* valueFormats[0].get_len() */ + unsigned int stride; /* 1 + len1 + len2 */ + }; + + bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const + { + TRACE_SANITIZE (this); + if (!(c->check_struct (this) + && c->check_range (&firstPairValueRecord, + len, + HBUINT16::static_size, + closure->stride))) return_trace (false); + + unsigned int count = len; + const PairValueRecord *record = &firstPairValueRecord; + return_trace (closure->valueFormats[0].sanitize_values_stride_unsafe (c, this, &record->values[0], count, closure->stride) && + closure->valueFormats[1].sanitize_values_stride_unsafe (c, this, &record->values[closure->len1], count, closure->stride)); + } + + protected: + HBUINT16 len; /* Number of PairValueRecords */ + PairValueRecord firstPairValueRecord; + /* Array of PairValueRecords--ordered + * by GlyphID of the second glyph */ + public: + DEFINE_SIZE_MIN (2); +}; + +struct PairPosFormat1 +{ + protected: + HBUINT16 format; /* Format identifier--format = 1 */ + Offset16To<Coverage> + coverage; /* Offset to Coverage table--from + * beginning of subtable */ + ValueFormat valueFormat[2]; /* [0] Defines the types of data in + * ValueRecord1--for the first glyph + * in the pair--may be zero (0) */ + /* [1] Defines the types of data in + * ValueRecord2--for the second glyph + * in the pair--may be zero (0) */ + Array16OfOffset16To<PairSet> + pairSet; /* Array of PairSet tables + * ordered by Coverage Index */ + public: + DEFINE_SIZE_ARRAY (10, pairSet); + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + + if (!c->check_struct (this)) return_trace (false); + + unsigned int len1 = valueFormat[0].get_len (); + unsigned int len2 = valueFormat[1].get_len (); + PairSet::sanitize_closure_t closure = + { + valueFormat, + len1, + 1 + len1 + len2 + }; + + return_trace (coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure)); + } + + + bool intersects (const hb_set_t *glyphs) const + { + return + + hb_zip (this+coverage, pairSet) + | hb_filter (*glyphs, hb_first) + | hb_map (hb_second) + | hb_map ([glyphs, this] (const Offset16To<PairSet> &_) + { return (this+_).intersects (glyphs, valueFormat); }) + | hb_any + ; + } + + void closure_lookups (hb_closure_lookups_context_t *c) const {} + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + if ((!valueFormat[0].has_device ()) && (!valueFormat[1].has_device ())) return; + + auto it = + + hb_zip (this+coverage, pairSet) + | hb_filter (c->glyph_set, hb_first) + | hb_map (hb_second) + ; + + if (!it) return; + + it + | hb_map (hb_add (this)) + | hb_apply ([&] (const PairSet& _) { _.collect_variation_indices (c, valueFormat); }) + ; + } + + void collect_glyphs (hb_collect_glyphs_context_t *c) const + { + if (unlikely (!(this+coverage).collect_coverage (c->input))) return; + unsigned int count = pairSet.len; + for (unsigned int i = 0; i < count; i++) + (this+pairSet[i]).collect_glyphs (c, valueFormat); + } + + const Coverage &get_coverage () const { return this+coverage; } + + bool apply (hb_ot_apply_context_t *c) const + { + TRACE_APPLY (this); + hb_buffer_t *buffer = c->buffer; + unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint); + if (likely (index == NOT_COVERED)) return_trace (false); + + hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; + skippy_iter.reset (buffer->idx, 1); + unsigned unsafe_to; + if (!skippy_iter.next (&unsafe_to)) + { + buffer->unsafe_to_concat (buffer->idx, unsafe_to); + return_trace (false); + } + + return_trace ((this+pairSet[index]).apply (c, valueFormat, skippy_iter.idx)); + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + + const hb_set_t &glyphset = *c->plan->glyphset_gsub (); + const hb_map_t &glyph_map = *c->plan->glyph_map; + + auto *out = c->serializer->start_embed (*this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + out->format = format; + out->valueFormat[0] = valueFormat[0]; + out->valueFormat[1] = valueFormat[1]; + if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING) + { + hb_pair_t<unsigned, unsigned> newFormats = compute_effective_value_formats (glyphset); + out->valueFormat[0] = newFormats.first; + out->valueFormat[1] = newFormats.second; + } + + hb_sorted_vector_t<hb_codepoint_t> new_coverage; + + + hb_zip (this+coverage, pairSet) + | hb_filter (glyphset, hb_first) + | hb_filter ([this, c, out] (const Offset16To<PairSet>& _) + { + auto snap = c->serializer->snapshot (); + auto *o = out->pairSet.serialize_append (c->serializer); + if (unlikely (!o)) return false; + bool ret = o->serialize_subset (c, _, this, valueFormat, out->valueFormat); + if (!ret) + { + out->pairSet.pop (); + c->serializer->revert (snap); + } + return ret; + }, + hb_second) + | hb_map (hb_first) + | hb_map (glyph_map) + | hb_sink (new_coverage) + ; + + out->coverage.serialize_serialize (c->serializer, new_coverage.iter ()); + + return_trace (bool (new_coverage)); + } + + + hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_set_t& glyphset) const + { + unsigned len1 = valueFormat[0].get_len (); + unsigned len2 = valueFormat[1].get_len (); + unsigned record_size = HBUINT16::static_size + Value::static_size * (len1 + len2); + + unsigned format1 = 0; + unsigned format2 = 0; + for (const Offset16To<PairSet>& _ : + + hb_zip (this+coverage, pairSet) | hb_filter (glyphset, hb_first) | hb_map (hb_second)) + { + const PairSet& set = (this + _); + const PairValueRecord *record = &set.firstPairValueRecord; + + for (unsigned i = 0; i < set.len; i++) + { + if (record->intersects (glyphset)) + { + format1 = format1 | valueFormat[0].get_effective_format (record->get_values_1 ()); + format2 = format2 | valueFormat[1].get_effective_format (record->get_values_2 (valueFormat[0])); + } + record = &StructAtOffset<const PairValueRecord> (record, record_size); + } + } + + return hb_pair (format1, format2); + } +}; + + +} +} +} + +#endif // OT_LAYOUT_GPOS_PAIRPOSFORMAT1_HH diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat2.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat2.hh new file mode 100644 index 0000000000..3f5f9959c4 --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat2.hh @@ -0,0 +1,314 @@ +#ifndef OT_LAYOUT_GPOS_PAIRPOSFORMAT2_HH +#define OT_LAYOUT_GPOS_PAIRPOSFORMAT2_HH + +#include "ValueFormat.hh" + +namespace OT { +namespace Layout { +namespace GPOS_impl { + +struct PairPosFormat2 +{ + protected: + HBUINT16 format; /* Format identifier--format = 2 */ + Offset16To<Coverage> + coverage; /* Offset to Coverage table--from + * beginning of subtable */ + ValueFormat valueFormat1; /* ValueRecord definition--for the + * first glyph of the pair--may be zero + * (0) */ + ValueFormat valueFormat2; /* ValueRecord definition--for the + * second glyph of the pair--may be + * zero (0) */ + Offset16To<ClassDef> + classDef1; /* Offset to ClassDef table--from + * beginning of PairPos subtable--for + * the first glyph of the pair */ + Offset16To<ClassDef> + classDef2; /* Offset to ClassDef table--from + * beginning of PairPos subtable--for + * the second glyph of the pair */ + HBUINT16 class1Count; /* Number of classes in ClassDef1 + * table--includes Class0 */ + HBUINT16 class2Count; /* Number of classes in ClassDef2 + * table--includes Class0 */ + ValueRecord values; /* Matrix of value pairs: + * class1-major, class2-minor, + * Each entry has value1 and value2 */ + public: + DEFINE_SIZE_ARRAY (16, values); + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + if (!(c->check_struct (this) + && coverage.sanitize (c, this) + && classDef1.sanitize (c, this) + && classDef2.sanitize (c, this))) return_trace (false); + + unsigned int len1 = valueFormat1.get_len (); + unsigned int len2 = valueFormat2.get_len (); + unsigned int stride = len1 + len2; + unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size (); + unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count; + return_trace (c->check_range ((const void *) values, + count, + record_size) && + valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) && + valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride)); + } + + bool intersects (const hb_set_t *glyphs) const + { + return (this+coverage).intersects (glyphs) && + (this+classDef2).intersects (glyphs); + } + + void closure_lookups (hb_closure_lookups_context_t *c) const {} + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + if (!intersects (c->glyph_set)) return; + if ((!valueFormat1.has_device ()) && (!valueFormat2.has_device ())) return; + + hb_set_t klass1_glyphs, klass2_glyphs; + if (!(this+classDef1).collect_coverage (&klass1_glyphs)) return; + if (!(this+classDef2).collect_coverage (&klass2_glyphs)) return; + + hb_set_t class1_set, class2_set; + for (const unsigned cp : + c->glyph_set->iter () | hb_filter (this + coverage)) + { + if (!klass1_glyphs.has (cp)) class1_set.add (0); + else + { + unsigned klass1 = (this+classDef1).get (cp); + class1_set.add (klass1); + } + } + + class2_set.add (0); + for (const unsigned cp : + c->glyph_set->iter () | hb_filter (klass2_glyphs)) + { + unsigned klass2 = (this+classDef2).get (cp); + class2_set.add (klass2); + } + + if (class1_set.is_empty () + || class2_set.is_empty () + || (class2_set.get_population() == 1 && class2_set.has(0))) + return; + + unsigned len1 = valueFormat1.get_len (); + unsigned len2 = valueFormat2.get_len (); + const hb_array_t<const Value> values_array = values.as_array ((unsigned)class1Count * (unsigned) class2Count * (len1 + len2)); + for (const unsigned class1_idx : class1_set.iter ()) + { + for (const unsigned class2_idx : class2_set.iter ()) + { + unsigned start_offset = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2); + if (valueFormat1.has_device ()) + valueFormat1.collect_variation_indices (c, this, values_array.sub_array (start_offset, len1)); + + if (valueFormat2.has_device ()) + valueFormat2.collect_variation_indices (c, this, values_array.sub_array (start_offset+len1, len2)); + } + } + } + + void collect_glyphs (hb_collect_glyphs_context_t *c) const + { + if (unlikely (!(this+coverage).collect_coverage (c->input))) return; + if (unlikely (!(this+classDef2).collect_coverage (c->input))) return; + } + + const Coverage &get_coverage () const { return this+coverage; } + + bool apply (hb_ot_apply_context_t *c) const + { + TRACE_APPLY (this); + hb_buffer_t *buffer = c->buffer; + unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint); + if (likely (index == NOT_COVERED)) return_trace (false); + + hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; + skippy_iter.reset (buffer->idx, 1); + unsigned unsafe_to; + if (!skippy_iter.next (&unsafe_to)) + { + buffer->unsafe_to_concat (buffer->idx, unsafe_to); + return_trace (false); + } + + unsigned int len1 = valueFormat1.get_len (); + unsigned int len2 = valueFormat2.get_len (); + unsigned int record_len = len1 + len2; + + unsigned int klass1 = (this+classDef1).get_class (buffer->cur().codepoint); + unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint); + if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) + { + buffer->unsafe_to_concat (buffer->idx, skippy_iter.idx + 1); + return_trace (false); + } + + const Value *v = &values[record_len * (klass1 * class2Count + klass2)]; + + bool applied_first = false, applied_second = false; + + + /* Isolate simple kerning and apply it half to each side. + * Results in better cursor positinoing / underline drawing. + * + * Disabled, because causes issues... :-( + * https://github.com/harfbuzz/harfbuzz/issues/3408 + * https://github.com/harfbuzz/harfbuzz/pull/3235#issuecomment-1029814978 + */ +#ifndef HB_SPLIT_KERN + if (0) +#endif + { + if (!len2) + { + const hb_direction_t dir = buffer->props.direction; + const bool horizontal = HB_DIRECTION_IS_HORIZONTAL (dir); + const bool backward = HB_DIRECTION_IS_BACKWARD (dir); + unsigned mask = horizontal ? ValueFormat::xAdvance : ValueFormat::yAdvance; + if (backward) + mask |= mask >> 2; /* Add eg. xPlacement in RTL. */ + /* Add Devices. */ + mask |= mask << 4; + + if (valueFormat1 & ~mask) + goto bail; + + /* Is simple kern. Apply value on an empty position slot, + * then split it between sides. */ + + hb_glyph_position_t pos{}; + if (valueFormat1.apply_value (c, this, v, pos)) + { + hb_position_t *src = &pos.x_advance; + hb_position_t *dst1 = &buffer->cur_pos().x_advance; + hb_position_t *dst2 = &buffer->pos[skippy_iter.idx].x_advance; + unsigned i = horizontal ? 0 : 1; + + hb_position_t kern = src[i]; + hb_position_t kern1 = kern >> 1; + hb_position_t kern2 = kern - kern1; + + if (!backward) + { + dst1[i] += kern1; + dst2[i] += kern2; + dst2[i + 2] += kern2; + } + else + { + dst1[i] += kern1; + dst1[i + 2] += src[i + 2] - kern2; + dst2[i] += kern2; + } + + applied_first = applied_second = kern != 0; + goto success; + } + goto boring; + } + } + bail: + + + applied_first = valueFormat1.apply_value (c, this, v, buffer->cur_pos()); + applied_second = valueFormat2.apply_value (c, this, v + len1, buffer->pos[skippy_iter.idx]); + + success: + if (applied_first || applied_second) + buffer->unsafe_to_break (buffer->idx, skippy_iter.idx + 1); + else + boring: + buffer->unsafe_to_concat (buffer->idx, skippy_iter.idx + 1); + + + buffer->idx = skippy_iter.idx; + if (len2) + buffer->idx++; + + return_trace (true); + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->start_embed (*this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + out->format = format; + + hb_map_t klass1_map; + out->classDef1.serialize_subset (c, classDef1, this, &klass1_map, true, true, &(this + coverage)); + out->class1Count = klass1_map.get_population (); + + hb_map_t klass2_map; + out->classDef2.serialize_subset (c, classDef2, this, &klass2_map, true, false); + out->class2Count = klass2_map.get_population (); + + unsigned len1 = valueFormat1.get_len (); + unsigned len2 = valueFormat2.get_len (); + + hb_pair_t<unsigned, unsigned> newFormats = hb_pair (valueFormat1, valueFormat2); + if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING) + newFormats = compute_effective_value_formats (klass1_map, klass2_map); + + out->valueFormat1 = newFormats.first; + out->valueFormat2 = newFormats.second; + + for (unsigned class1_idx : + hb_range ((unsigned) class1Count) | hb_filter (klass1_map)) + { + for (unsigned class2_idx : + hb_range ((unsigned) class2Count) | hb_filter (klass2_map)) + { + unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2); + valueFormat1.copy_values (c->serializer, newFormats.first, this, &values[idx], c->plan->layout_variation_idx_map); + valueFormat2.copy_values (c->serializer, newFormats.second, this, &values[idx + len1], c->plan->layout_variation_idx_map); + } + } + + const hb_set_t &glyphset = *c->plan->glyphset_gsub (); + const hb_map_t &glyph_map = *c->plan->glyph_map; + + auto it = + + hb_iter (this+coverage) + | hb_filter (glyphset) + | hb_map_retains_sorting (glyph_map) + ; + + out->coverage.serialize_serialize (c->serializer, it); + return_trace (out->class1Count && out->class2Count && bool (it)); + } + + + hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_map_t& klass1_map, + const hb_map_t& klass2_map) const + { + unsigned len1 = valueFormat1.get_len (); + unsigned len2 = valueFormat2.get_len (); + + unsigned format1 = 0; + unsigned format2 = 0; + + for (unsigned class1_idx : + hb_range ((unsigned) class1Count) | hb_filter (klass1_map)) + { + for (unsigned class2_idx : + hb_range ((unsigned) class2Count) | hb_filter (klass2_map)) + { + unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2); + format1 = format1 | valueFormat1.get_effective_format (&values[idx]); + format2 = format2 | valueFormat2.get_effective_format (&values[idx + len1]); + } + } + + return hb_pair (format1, format2); + } +}; + +} +} +} + +#endif // OT_LAYOUT_GPOS_PAIRPOSFORMAT2_HH diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/PosLookup.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PosLookup.hh new file mode 100644 index 0000000000..c4e57bb543 --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PosLookup.hh @@ -0,0 +1,79 @@ +#ifndef OT_LAYOUT_GPOS_POSLOOKUP_HH +#define OT_LAYOUT_GPOS_POSLOOKUP_HH + +#include "PosLookupSubTable.hh" +#include "../../../hb-ot-layout-common.hh" + +namespace OT { +namespace Layout { +namespace GPOS_impl { + +struct PosLookup : Lookup +{ + using SubTable = PosLookupSubTable; + + const SubTable& get_subtable (unsigned int i) const + { return Lookup::get_subtable<SubTable> (i); } + + bool is_reverse () const + { + return false; + } + + bool apply (hb_ot_apply_context_t *c) const + { + TRACE_APPLY (this); + return_trace (dispatch (c)); + } + + bool intersects (const hb_set_t *glyphs) const + { + hb_intersects_context_t c (glyphs); + return dispatch (&c); + } + + hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const + { return dispatch (c); } + + hb_closure_lookups_context_t::return_t closure_lookups (hb_closure_lookups_context_t *c, unsigned this_index) const + { + if (c->is_lookup_visited (this_index)) + return hb_closure_lookups_context_t::default_return_value (); + + c->set_lookup_visited (this_index); + if (!intersects (c->glyphs)) + { + c->set_lookup_inactive (this_index); + return hb_closure_lookups_context_t::default_return_value (); + } + + hb_closure_lookups_context_t::return_t ret = dispatch (c); + return ret; + } + + template <typename set_t> + void collect_coverage (set_t *glyphs) const + { + hb_collect_coverage_context_t<set_t> c (glyphs); + dispatch (&c); + } + + template <typename context_t> + static typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index); + + template <typename context_t, typename ...Ts> + typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const + { return Lookup::dispatch<SubTable> (c, std::forward<Ts> (ds)...); } + + bool subset (hb_subset_context_t *c) const + { return Lookup::subset<SubTable> (c); } + + bool sanitize (hb_sanitize_context_t *c) const + { return Lookup::sanitize<SubTable> (c); } +}; + +} +} +} + +#endif /* OT_LAYOUT_GPOS_POSLOOKUP_HH */ diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/PosLookupSubTable.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PosLookupSubTable.hh new file mode 100644 index 0000000000..c19fbc323f --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PosLookupSubTable.hh @@ -0,0 +1,79 @@ +#ifndef OT_LAYOUT_GPOS_POSLOOKUPSUBTABLE_HH +#define OT_LAYOUT_GPOS_POSLOOKUPSUBTABLE_HH + +#include "SinglePos.hh" +#include "PairPos.hh" +#include "CursivePos.hh" +#include "MarkBasePos.hh" +#include "MarkLigPos.hh" +#include "MarkMarkPos.hh" +#include "ContextPos.hh" +#include "ChainContextPos.hh" +#include "ExtensionPos.hh" + +namespace OT { +namespace Layout { +namespace GPOS_impl { + +struct PosLookupSubTable +{ + friend struct ::OT::Lookup; + friend struct PosLookup; + + enum Type { + Single = 1, + Pair = 2, + Cursive = 3, + MarkBase = 4, + MarkLig = 5, + MarkMark = 6, + Context = 7, + ChainContext = 8, + Extension = 9 + }; + + template <typename context_t, typename ...Ts> + typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type, Ts&&... ds) const + { + TRACE_DISPATCH (this, lookup_type); + switch (lookup_type) { + case Single: return_trace (u.single.dispatch (c, std::forward<Ts> (ds)...)); + case Pair: return_trace (u.pair.dispatch (c, std::forward<Ts> (ds)...)); + case Cursive: return_trace (u.cursive.dispatch (c, std::forward<Ts> (ds)...)); + case MarkBase: return_trace (u.markBase.dispatch (c, std::forward<Ts> (ds)...)); + case MarkLig: return_trace (u.markLig.dispatch (c, std::forward<Ts> (ds)...)); + case MarkMark: return_trace (u.markMark.dispatch (c, std::forward<Ts> (ds)...)); + case Context: return_trace (u.context.dispatch (c, std::forward<Ts> (ds)...)); + case ChainContext: return_trace (u.chainContext.dispatch (c, std::forward<Ts> (ds)...)); + case Extension: return_trace (u.extension.dispatch (c, std::forward<Ts> (ds)...)); + default: return_trace (c->default_return_value ()); + } + } + + bool intersects (const hb_set_t *glyphs, unsigned int lookup_type) const + { + hb_intersects_context_t c (glyphs); + return dispatch (&c, lookup_type); + } + + protected: + union { + SinglePos single; + PairPos pair; + CursivePos cursive; + MarkBasePos markBase; + MarkLigPos markLig; + MarkMarkPos markMark; + ContextPos context; + ChainContextPos chainContext; + ExtensionPos extension; + } u; + public: + DEFINE_SIZE_MIN (0); +}; + +} +} +} + +#endif /* HB_OT_LAYOUT_GPOS_POSLOOKUPSUBTABLE_HH */ diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePos.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePos.hh new file mode 100644 index 0000000000..57e146befd --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePos.hh @@ -0,0 +1,98 @@ +#ifndef OT_LAYOUT_GPOS_SINGLEPOS_HH +#define OT_LAYOUT_GPOS_SINGLEPOS_HH + +#include "SinglePosFormat1.hh" +#include "SinglePosFormat2.hh" + +namespace OT { +namespace Layout { +namespace GPOS_impl { + +struct SinglePos +{ + protected: + union { + HBUINT16 format; /* Format identifier */ + SinglePosFormat1 format1; + SinglePosFormat2 format2; + } u; + + public: + template<typename Iterator, + hb_requires (hb_is_iterator (Iterator))> + unsigned get_format (Iterator glyph_val_iter_pairs) + { + hb_array_t<const Value> first_val_iter = hb_second (*glyph_val_iter_pairs); + + for (const auto iter : glyph_val_iter_pairs) + for (const auto _ : hb_zip (iter.second, first_val_iter)) + if (_.first != _.second) + return 2; + + return 1; + } + + template<typename Iterator, + typename SrcLookup, + hb_requires (hb_is_iterator (Iterator))> + void serialize (hb_serialize_context_t *c, + const SrcLookup* src, + Iterator glyph_val_iter_pairs, + const hb_map_t *layout_variation_idx_map) + { + if (unlikely (!c->extend_min (u.format))) return; + unsigned format = 2; + ValueFormat new_format = src->get_value_format (); + + if (glyph_val_iter_pairs) + { + format = get_format (glyph_val_iter_pairs); + new_format = src->get_value_format ().get_effective_format (+ glyph_val_iter_pairs | hb_map (hb_second)); + } + + u.format = format; + switch (u.format) { + case 1: u.format1.serialize (c, + src, + glyph_val_iter_pairs, + new_format, + layout_variation_idx_map); + return; + case 2: u.format2.serialize (c, + src, + glyph_val_iter_pairs, + new_format, + layout_variation_idx_map); + return; + default:return; + } + } + + template <typename context_t, typename ...Ts> + typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const + { + TRACE_DISPATCH (this, u.format); + if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); + switch (u.format) { + case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...)); + case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...)); + default:return_trace (c->default_return_value ()); + } + } +}; + + +template<typename Iterator, typename SrcLookup> +static void +SinglePos_serialize (hb_serialize_context_t *c, + const SrcLookup *src, + Iterator it, + const hb_map_t *layout_variation_idx_map) +{ c->start_embed<SinglePos> ()->serialize (c, src, it, layout_variation_idx_map); } + + +} +} +} + +#endif /* OT_LAYOUT_GPOS_SINGLEPOS_HH */ diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat1.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat1.hh new file mode 100644 index 0000000000..8b7840ed0e --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat1.hh @@ -0,0 +1,124 @@ +#ifndef OT_LAYOUT_GPOS_SINGLEPOSFORMAT1_HH +#define OT_LAYOUT_GPOS_SINGLEPOSFORMAT1_HH + +#include "Common.hh" +#include "ValueFormat.hh" + +namespace OT { +namespace Layout { +namespace GPOS_impl { + +struct SinglePosFormat1 +{ + protected: + HBUINT16 format; /* Format identifier--format = 1 */ + Offset16To<Coverage> + coverage; /* Offset to Coverage table--from + * beginning of subtable */ + ValueFormat valueFormat; /* Defines the types of data in the + * ValueRecord */ + ValueRecord values; /* Defines positioning + * value(s)--applied to all glyphs in + * the Coverage table */ + public: + DEFINE_SIZE_ARRAY (6, values); + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + coverage.sanitize (c, this) && + valueFormat.sanitize_value (c, this, values)); + } + + bool intersects (const hb_set_t *glyphs) const + { return (this+coverage).intersects (glyphs); } + + void closure_lookups (hb_closure_lookups_context_t *c) const {} + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + if (!valueFormat.has_device ()) return; + + auto it = + + hb_iter (this+coverage) + | hb_filter (c->glyph_set) + ; + + if (!it) return; + valueFormat.collect_variation_indices (c, this, values.as_array (valueFormat.get_len ())); + } + + void collect_glyphs (hb_collect_glyphs_context_t *c) const + { if (unlikely (!(this+coverage).collect_coverage (c->input))) return; } + + const Coverage &get_coverage () const { return this+coverage; } + + ValueFormat get_value_format () const { return valueFormat; } + + bool apply (hb_ot_apply_context_t *c) const + { + TRACE_APPLY (this); + hb_buffer_t *buffer = c->buffer; + unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint); + if (likely (index == NOT_COVERED)) return_trace (false); + + valueFormat.apply_value (c, this, values, buffer->cur_pos()); + + buffer->idx++; + return_trace (true); + } + + template<typename Iterator, + typename SrcLookup, + hb_requires (hb_is_iterator (Iterator))> + void serialize (hb_serialize_context_t *c, + const SrcLookup *src, + Iterator it, + ValueFormat newFormat, + const hb_map_t *layout_variation_idx_map) + { + if (unlikely (!c->extend_min (this))) return; + if (unlikely (!c->check_assign (valueFormat, + newFormat, + HB_SERIALIZE_ERROR_INT_OVERFLOW))) return; + + for (const hb_array_t<const Value>& _ : + it | hb_map (hb_second)) + { + src->get_value_format ().copy_values (c, newFormat, src, &_, layout_variation_idx_map); + // Only serialize the first entry in the iterator, the rest are assumed to + // be the same. + break; + } + + auto glyphs = + + it + | hb_map_retains_sorting (hb_first) + ; + + coverage.serialize_serialize (c, glyphs); + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + const hb_set_t &glyphset = *c->plan->glyphset_gsub (); + const hb_map_t &glyph_map = *c->plan->glyph_map; + + auto it = + + hb_iter (this+coverage) + | hb_filter (glyphset) + | hb_map_retains_sorting (glyph_map) + | hb_zip (hb_repeat (values.as_array (valueFormat.get_len ()))) + ; + + bool ret = bool (it); + SinglePos_serialize (c->serializer, this, it, c->plan->layout_variation_idx_map); + return_trace (ret); + } +}; + +} +} +} + +#endif /* OT_LAYOUT_GPOS_SINGLEPOSFORMAT1_HH */ diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat2.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat2.hh new file mode 100644 index 0000000000..0d038b4422 --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat2.hh @@ -0,0 +1,140 @@ +#ifndef OT_LAYOUT_GPOS_SINGLEPOSFORMAT2_HH +#define OT_LAYOUT_GPOS_SINGLEPOSFORMAT2_HH + +#include "Common.hh" + +namespace OT { +namespace Layout { +namespace GPOS_impl { + +struct SinglePosFormat2 +{ + protected: + HBUINT16 format; /* Format identifier--format = 2 */ + Offset16To<Coverage> + coverage; /* Offset to Coverage table--from + * beginning of subtable */ + ValueFormat valueFormat; /* Defines the types of data in the + * ValueRecord */ + HBUINT16 valueCount; /* Number of ValueRecords */ + ValueRecord values; /* Array of ValueRecords--positioning + * values applied to glyphs */ + public: + DEFINE_SIZE_ARRAY (8, values); + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + coverage.sanitize (c, this) && + valueFormat.sanitize_values (c, this, values, valueCount)); + } + + bool intersects (const hb_set_t *glyphs) const + { return (this+coverage).intersects (glyphs); } + + void closure_lookups (hb_closure_lookups_context_t *c) const {} + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + if (!valueFormat.has_device ()) return; + + auto it = + + hb_zip (this+coverage, hb_range ((unsigned) valueCount)) + | hb_filter (c->glyph_set, hb_first) + ; + + if (!it) return; + + unsigned sub_length = valueFormat.get_len (); + const hb_array_t<const Value> values_array = values.as_array (valueCount * sub_length); + + for (unsigned i : + it + | hb_map (hb_second)) + valueFormat.collect_variation_indices (c, this, values_array.sub_array (i * sub_length, sub_length)); + + } + + void collect_glyphs (hb_collect_glyphs_context_t *c) const + { if (unlikely (!(this+coverage).collect_coverage (c->input))) return; } + + const Coverage &get_coverage () const { return this+coverage; } + + ValueFormat get_value_format () const { return valueFormat; } + + bool apply (hb_ot_apply_context_t *c) const + { + TRACE_APPLY (this); + hb_buffer_t *buffer = c->buffer; + unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint); + if (likely (index == NOT_COVERED)) return_trace (false); + + if (likely (index >= valueCount)) return_trace (false); + + valueFormat.apply_value (c, this, + &values[index * valueFormat.get_len ()], + buffer->cur_pos()); + + buffer->idx++; + return_trace (true); + } + + template<typename Iterator, + typename SrcLookup, + hb_requires (hb_is_iterator (Iterator))> + void serialize (hb_serialize_context_t *c, + const SrcLookup *src, + Iterator it, + ValueFormat newFormat, + const hb_map_t *layout_variation_idx_map) + { + auto out = c->extend_min (this); + if (unlikely (!out)) return; + if (unlikely (!c->check_assign (valueFormat, newFormat, HB_SERIALIZE_ERROR_INT_OVERFLOW))) return; + if (unlikely (!c->check_assign (valueCount, it.len (), HB_SERIALIZE_ERROR_ARRAY_OVERFLOW))) return; + + + it + | hb_map (hb_second) + | hb_apply ([&] (hb_array_t<const Value> _) + { src->get_value_format ().copy_values (c, newFormat, src, &_, layout_variation_idx_map); }) + ; + + auto glyphs = + + it + | hb_map_retains_sorting (hb_first) + ; + + coverage.serialize_serialize (c, glyphs); + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + const hb_set_t &glyphset = *c->plan->glyphset_gsub (); + const hb_map_t &glyph_map = *c->plan->glyph_map; + + unsigned sub_length = valueFormat.get_len (); + auto values_array = values.as_array (valueCount * sub_length); + + auto it = + + hb_zip (this+coverage, hb_range ((unsigned) valueCount)) + | hb_filter (glyphset, hb_first) + | hb_map_retains_sorting ([&] (const hb_pair_t<hb_codepoint_t, unsigned>& _) + { + return hb_pair (glyph_map[_.first], + values_array.sub_array (_.second * sub_length, + sub_length)); + }) + ; + + bool ret = bool (it); + SinglePos_serialize (c->serializer, this, it, c->plan->layout_variation_idx_map); + return_trace (ret); + } +}; + + +} +} +} + +#endif /* OT_LAYOUT_GPOS_SINGLEPOSFORMAT2_HH */ diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/ValueFormat.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/ValueFormat.hh new file mode 100644 index 0000000000..b29f287bce --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/ValueFormat.hh @@ -0,0 +1,329 @@ +#ifndef OT_LAYOUT_GPOS_VALUEFORMAT_HH +#define OT_LAYOUT_GPOS_VALUEFORMAT_HH + +#include "../../../hb-ot-layout-gsubgpos.hh" + +namespace OT { +namespace Layout { +namespace GPOS_impl { + +typedef HBUINT16 Value; + +typedef UnsizedArrayOf<Value> ValueRecord; + +struct ValueFormat : HBUINT16 +{ + enum Flags { + xPlacement = 0x0001u, /* Includes horizontal adjustment for placement */ + yPlacement = 0x0002u, /* Includes vertical adjustment for placement */ + xAdvance = 0x0004u, /* Includes horizontal adjustment for advance */ + yAdvance = 0x0008u, /* Includes vertical adjustment for advance */ + xPlaDevice = 0x0010u, /* Includes horizontal Device table for placement */ + yPlaDevice = 0x0020u, /* Includes vertical Device table for placement */ + xAdvDevice = 0x0040u, /* Includes horizontal Device table for advance */ + yAdvDevice = 0x0080u, /* Includes vertical Device table for advance */ + ignored = 0x0F00u, /* Was used in TrueType Open for MM fonts */ + reserved = 0xF000u, /* For future use */ + + devices = 0x00F0u /* Mask for having any Device table */ + }; + +/* All fields are options. Only those available advance the value pointer. */ +#if 0 + HBINT16 xPlacement; /* Horizontal adjustment for + * placement--in design units */ + HBINT16 yPlacement; /* Vertical adjustment for + * placement--in design units */ + HBINT16 xAdvance; /* Horizontal adjustment for + * advance--in design units (only used + * for horizontal writing) */ + HBINT16 yAdvance; /* Vertical adjustment for advance--in + * design units (only used for vertical + * writing) */ + Offset16To<Device> xPlaDevice; /* Offset to Device table for + * horizontal placement--measured from + * beginning of PosTable (may be NULL) */ + Offset16To<Device> yPlaDevice; /* Offset to Device table for vertical + * placement--measured from beginning + * of PosTable (may be NULL) */ + Offset16To<Device> xAdvDevice; /* Offset to Device table for + * horizontal advance--measured from + * beginning of PosTable (may be NULL) */ + Offset16To<Device> yAdvDevice; /* Offset to Device table for vertical + * advance--measured from beginning of + * PosTable (may be NULL) */ +#endif + + IntType& operator = (uint16_t i) { v = i; return *this; } + + unsigned int get_len () const { return hb_popcount ((unsigned int) *this); } + unsigned int get_size () const { return get_len () * Value::static_size; } + + bool apply_value (hb_ot_apply_context_t *c, + const void *base, + const Value *values, + hb_glyph_position_t &glyph_pos) const + { + bool ret = false; + unsigned int format = *this; + if (!format) return ret; + + hb_font_t *font = c->font; + bool horizontal = +#ifndef HB_NO_VERTICAL + HB_DIRECTION_IS_HORIZONTAL (c->direction) +#else + true +#endif + ; + + if (format & xPlacement) glyph_pos.x_offset += font->em_scale_x (get_short (values++, &ret)); + if (format & yPlacement) glyph_pos.y_offset += font->em_scale_y (get_short (values++, &ret)); + if (format & xAdvance) { + if (likely (horizontal)) glyph_pos.x_advance += font->em_scale_x (get_short (values, &ret)); + values++; + } + /* y_advance values grow downward but font-space grows upward, hence negation */ + if (format & yAdvance) { + if (unlikely (!horizontal)) glyph_pos.y_advance -= font->em_scale_y (get_short (values, &ret)); + values++; + } + + if (!has_device ()) return ret; + + bool use_x_device = font->x_ppem || font->num_coords; + bool use_y_device = font->y_ppem || font->num_coords; + + if (!use_x_device && !use_y_device) return ret; + + const VariationStore &store = c->var_store; + auto *cache = c->var_store_cache; + + /* pixel -> fractional pixel */ + if (format & xPlaDevice) { + if (use_x_device) glyph_pos.x_offset += (base + get_device (values, &ret)).get_x_delta (font, store, cache); + values++; + } + if (format & yPlaDevice) { + if (use_y_device) glyph_pos.y_offset += (base + get_device (values, &ret)).get_y_delta (font, store, cache); + values++; + } + if (format & xAdvDevice) { + if (horizontal && use_x_device) glyph_pos.x_advance += (base + get_device (values, &ret)).get_x_delta (font, store, cache); + values++; + } + if (format & yAdvDevice) { + /* y_advance values grow downward but font-space grows upward, hence negation */ + if (!horizontal && use_y_device) glyph_pos.y_advance -= (base + get_device (values, &ret)).get_y_delta (font, store, cache); + values++; + } + return ret; + } + + unsigned int get_effective_format (const Value *values) const + { + unsigned int format = *this; + for (unsigned flag = xPlacement; flag <= yAdvDevice; flag = flag << 1) { + if (format & flag) should_drop (*values++, (Flags) flag, &format); + } + + return format; + } + + template<typename Iterator, + hb_requires (hb_is_iterator (Iterator))> + unsigned int get_effective_format (Iterator it) const { + unsigned int new_format = 0; + + for (const hb_array_t<const Value>& values : it) + new_format = new_format | get_effective_format (&values); + + return new_format; + } + + void copy_values (hb_serialize_context_t *c, + unsigned int new_format, + const void *base, + const Value *values, + const hb_map_t *layout_variation_idx_map) const + { + unsigned int format = *this; + if (!format) return; + + if (format & xPlacement) copy_value (c, new_format, xPlacement, *values++); + if (format & yPlacement) copy_value (c, new_format, yPlacement, *values++); + if (format & xAdvance) copy_value (c, new_format, xAdvance, *values++); + if (format & yAdvance) copy_value (c, new_format, yAdvance, *values++); + + if (format & xPlaDevice) copy_device (c, base, values++, layout_variation_idx_map); + if (format & yPlaDevice) copy_device (c, base, values++, layout_variation_idx_map); + if (format & xAdvDevice) copy_device (c, base, values++, layout_variation_idx_map); + if (format & yAdvDevice) copy_device (c, base, values++, layout_variation_idx_map); + } + + void copy_value (hb_serialize_context_t *c, + unsigned int new_format, + Flags flag, + Value value) const + { + // Filter by new format. + if (!(new_format & flag)) return; + c->copy (value); + } + + void collect_variation_indices (hb_collect_variation_indices_context_t *c, + const void *base, + const hb_array_t<const Value>& values) const + { + unsigned format = *this; + unsigned i = 0; + if (format & xPlacement) i++; + if (format & yPlacement) i++; + if (format & xAdvance) i++; + if (format & yAdvance) i++; + if (format & xPlaDevice) + { + (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices); + i++; + } + + if (format & ValueFormat::yPlaDevice) + { + (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices); + i++; + } + + if (format & ValueFormat::xAdvDevice) + { + + (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices); + i++; + } + + if (format & ValueFormat::yAdvDevice) + { + + (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices); + i++; + } + } + + private: + bool sanitize_value_devices (hb_sanitize_context_t *c, const void *base, const Value *values) const + { + unsigned int format = *this; + + if (format & xPlacement) values++; + if (format & yPlacement) values++; + if (format & xAdvance) values++; + if (format & yAdvance) values++; + + if ((format & xPlaDevice) && !get_device (values++).sanitize (c, base)) return false; + if ((format & yPlaDevice) && !get_device (values++).sanitize (c, base)) return false; + if ((format & xAdvDevice) && !get_device (values++).sanitize (c, base)) return false; + if ((format & yAdvDevice) && !get_device (values++).sanitize (c, base)) return false; + + return true; + } + + static inline Offset16To<Device>& get_device (Value* value) + { + return *static_cast<Offset16To<Device> *> (value); + } + static inline const Offset16To<Device>& get_device (const Value* value, bool *worked=nullptr) + { + if (worked) *worked |= bool (*value); + return *static_cast<const Offset16To<Device> *> (value); + } + + bool copy_device (hb_serialize_context_t *c, const void *base, + const Value *src_value, const hb_map_t *layout_variation_idx_map) const + { + Value *dst_value = c->copy (*src_value); + + if (!dst_value) return false; + if (*dst_value == 0) return true; + + *dst_value = 0; + c->push (); + if ((base + get_device (src_value)).copy (c, layout_variation_idx_map)) + { + c->add_link (*dst_value, c->pop_pack ()); + return true; + } + else + { + c->pop_discard (); + return false; + } + } + + static inline const HBINT16& get_short (const Value* value, bool *worked=nullptr) + { + if (worked) *worked |= bool (*value); + return *reinterpret_cast<const HBINT16 *> (value); + } + + public: + + bool has_device () const + { + unsigned int format = *this; + return (format & devices) != 0; + } + + bool sanitize_value (hb_sanitize_context_t *c, const void *base, const Value *values) const + { + TRACE_SANITIZE (this); + return_trace (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values))); + } + + bool sanitize_values (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count) const + { + TRACE_SANITIZE (this); + unsigned int len = get_len (); + + if (!c->check_range (values, count, get_size ())) return_trace (false); + + if (!has_device ()) return_trace (true); + + for (unsigned int i = 0; i < count; i++) { + if (!sanitize_value_devices (c, base, values)) + return_trace (false); + values += len; + } + + return_trace (true); + } + + /* Just sanitize referenced Device tables. Doesn't check the values themselves. */ + bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count, unsigned int stride) const + { + TRACE_SANITIZE (this); + + if (!has_device ()) return_trace (true); + + for (unsigned int i = 0; i < count; i++) { + if (!sanitize_value_devices (c, base, values)) + return_trace (false); + values += stride; + } + + return_trace (true); + } + + private: + + void should_drop (Value value, Flags flag, unsigned int* format) const + { + if (value) return; + *format = *format & ~flag; + } + +}; + +} +} +} + +#endif // #ifndef OT_LAYOUT_GPOS_VALUEFORMAT_HH diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/GSUB.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/GSUB.hh index ad153ce8d7..3f0c4b2ad9 100644 --- a/thirdparty/harfbuzz/src/OT/Layout/GSUB/GSUB.hh +++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/GSUB.hh @@ -19,6 +19,8 @@ namespace GSUB { struct GSUB : GSUBGPOS { + using Lookup = SubstLookup; + static constexpr hb_tag_t tableTag = HB_OT_TAG_GSUB; const SubstLookup& get_lookup (unsigned int i) const diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/SubstLookup.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/SubstLookup.hh index 3419b5a734..8fb3b55097 100644 --- a/thirdparty/harfbuzz/src/OT/Layout/GSUB/SubstLookup.hh +++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/SubstLookup.hh @@ -10,7 +10,7 @@ namespace GSUB { struct SubstLookup : Lookup { - typedef SubstLookupSubTable SubTable; + using SubTable = SubstLookupSubTable; bool sanitize (hb_sanitize_context_t *c) const { return Lookup::sanitize<SubTable> (c); } @@ -73,8 +73,6 @@ struct SubstLookup : Lookup return hb_closure_lookups_context_t::default_return_value (); } - c->set_recurse_func (dispatch_closure_lookups_recurse_func); - hb_closure_lookups_context_t::return_t ret = dispatch (c); return ret; } @@ -100,8 +98,6 @@ struct SubstLookup : Lookup return dispatch (c); } - static inline bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index); - bool serialize_single (hb_serialize_context_t *c, uint32_t lookup_props, hb_sorted_array_t<const HBGlyphID16> glyphs, @@ -206,8 +202,6 @@ struct SubstLookup : Lookup return ret; } - HB_INTERNAL static hb_closure_lookups_context_t::return_t dispatch_closure_lookups_recurse_func (hb_closure_lookups_context_t *c, unsigned lookup_index); - template <typename context_t, typename ...Ts> typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { return Lookup::dispatch<SubTable> (c, std::forward<Ts> (ds)...); } diff --git a/thirdparty/harfbuzz/src/OT/glyf/CompositeGlyph.hh b/thirdparty/harfbuzz/src/OT/glyf/CompositeGlyph.hh new file mode 100644 index 0000000000..c145beaa49 --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/glyf/CompositeGlyph.hh @@ -0,0 +1,258 @@ +#ifndef OT_GLYF_COMPOSITEGLYPH_HH +#define OT_GLYF_COMPOSITEGLYPH_HH + + +#include "../../hb-open-type.hh" + + +namespace OT { +namespace glyf_impl { + + +struct CompositeGlyphRecord +{ + protected: + enum composite_glyph_flag_t + { + ARG_1_AND_2_ARE_WORDS = 0x0001, + ARGS_ARE_XY_VALUES = 0x0002, + ROUND_XY_TO_GRID = 0x0004, + WE_HAVE_A_SCALE = 0x0008, + MORE_COMPONENTS = 0x0020, + WE_HAVE_AN_X_AND_Y_SCALE = 0x0040, + WE_HAVE_A_TWO_BY_TWO = 0x0080, + WE_HAVE_INSTRUCTIONS = 0x0100, + USE_MY_METRICS = 0x0200, + OVERLAP_COMPOUND = 0x0400, + SCALED_COMPONENT_OFFSET = 0x0800, + UNSCALED_COMPONENT_OFFSET = 0x1000 + }; + + public: + unsigned int get_size () const + { + unsigned int size = min_size; + /* arg1 and 2 are int16 */ + if (flags & ARG_1_AND_2_ARE_WORDS) size += 4; + /* arg1 and 2 are int8 */ + else size += 2; + + /* One x 16 bit (scale) */ + if (flags & WE_HAVE_A_SCALE) size += 2; + /* Two x 16 bit (xscale, yscale) */ + else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) size += 4; + /* Four x 16 bit (xscale, scale01, scale10, yscale) */ + else if (flags & WE_HAVE_A_TWO_BY_TWO) size += 8; + + return size; + } + + void drop_instructions_flag () { flags = (uint16_t) flags & ~WE_HAVE_INSTRUCTIONS; } + void set_overlaps_flag () + { + flags = (uint16_t) flags | OVERLAP_COMPOUND; + } + + bool has_instructions () const { return flags & WE_HAVE_INSTRUCTIONS; } + + bool has_more () const { return flags & MORE_COMPONENTS; } + bool is_use_my_metrics () const { return flags & USE_MY_METRICS; } + bool is_anchored () const { return !(flags & ARGS_ARE_XY_VALUES); } + void get_anchor_points (unsigned int &point1, unsigned int &point2) const + { + const HBUINT8 *p = &StructAfter<const HBUINT8> (glyphIndex); + if (flags & ARG_1_AND_2_ARE_WORDS) + { + point1 = ((const HBUINT16 *) p)[0]; + point2 = ((const HBUINT16 *) p)[1]; + } + else + { + point1 = p[0]; + point2 = p[1]; + } + } + + void transform_points (contour_point_vector_t &points) const + { + float matrix[4]; + contour_point_t trans; + if (get_transformation (matrix, trans)) + { + if (scaled_offsets ()) + { + points.translate (trans); + points.transform (matrix); + } + else + { + points.transform (matrix); + points.translate (trans); + } + } + } + + protected: + bool scaled_offsets () const + { return (flags & (SCALED_COMPONENT_OFFSET | UNSCALED_COMPONENT_OFFSET)) == SCALED_COMPONENT_OFFSET; } + + bool get_transformation (float (&matrix)[4], contour_point_t &trans) const + { + matrix[0] = matrix[3] = 1.f; + matrix[1] = matrix[2] = 0.f; + + int tx, ty; + const HBINT8 *p = &StructAfter<const HBINT8> (glyphIndex); + if (flags & ARG_1_AND_2_ARE_WORDS) + { + tx = *(const HBINT16 *) p; + p += HBINT16::static_size; + ty = *(const HBINT16 *) p; + p += HBINT16::static_size; + } + else + { + tx = *p++; + ty = *p++; + } + if (is_anchored ()) tx = ty = 0; + + trans.init ((float) tx, (float) ty); + + { + const F2DOT14 *points = (const F2DOT14 *) p; + if (flags & WE_HAVE_A_SCALE) + { + matrix[0] = matrix[3] = points[0].to_float (); + return true; + } + else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) + { + matrix[0] = points[0].to_float (); + matrix[3] = points[1].to_float (); + return true; + } + else if (flags & WE_HAVE_A_TWO_BY_TWO) + { + matrix[0] = points[0].to_float (); + matrix[1] = points[1].to_float (); + matrix[2] = points[2].to_float (); + matrix[3] = points[3].to_float (); + return true; + } + } + return tx || ty; + } + + public: + HBUINT16 flags; + HBGlyphID16 glyphIndex; + public: + DEFINE_SIZE_MIN (4); +}; + +struct composite_iter_t : hb_iter_with_fallback_t<composite_iter_t, const CompositeGlyphRecord &> +{ + typedef const CompositeGlyphRecord *__item_t__; + composite_iter_t (hb_bytes_t glyph_, __item_t__ current_) : + glyph (glyph_), current (nullptr), current_size (0) + { + set_current (current_); + } + + composite_iter_t () : glyph (hb_bytes_t ()), current (nullptr), current_size (0) {} + + item_t __item__ () const { return *current; } + bool __more__ () const { return current; } + void __next__ () + { + if (!current->has_more ()) { current = nullptr; return; } + + set_current (&StructAtOffset<CompositeGlyphRecord> (current, current_size)); + } + composite_iter_t __end__ () const { return composite_iter_t (); } + bool operator != (const composite_iter_t& o) const + { return current != o.current; } + + + void set_current (__item_t__ current_) + { + if (!glyph.check_range (current_, CompositeGlyphRecord::min_size)) + { + current = nullptr; + current_size = 0; + return; + } + unsigned size = current_->get_size (); + if (!glyph.check_range (current_, size)) + { + current = nullptr; + current_size = 0; + return; + } + + current = current_; + current_size = size; + } + + private: + hb_bytes_t glyph; + __item_t__ current; + unsigned current_size; +}; + +struct CompositeGlyph +{ + const GlyphHeader &header; + hb_bytes_t bytes; + CompositeGlyph (const GlyphHeader &header_, hb_bytes_t bytes_) : + header (header_), bytes (bytes_) {} + + composite_iter_t iter () const + { return composite_iter_t (bytes, &StructAfter<CompositeGlyphRecord, GlyphHeader> (header)); } + + unsigned int instructions_length (hb_bytes_t bytes) const + { + unsigned int start = bytes.length; + unsigned int end = bytes.length; + const CompositeGlyphRecord *last = nullptr; + for (auto &item : iter ()) + last = &item; + if (unlikely (!last)) return 0; + + if (last->has_instructions ()) + start = (char *) last - &bytes + last->get_size (); + if (unlikely (start > end)) return 0; + return end - start; + } + + /* Trimming for composites not implemented. + * If removing hints it falls out of that. */ + const hb_bytes_t trim_padding () const { return bytes; } + + void drop_hints () + { + for (const auto &_ : iter ()) + const_cast<CompositeGlyphRecord &> (_).drop_instructions_flag (); + } + + /* Chop instructions off the end */ + void drop_hints_bytes (hb_bytes_t &dest_start) const + { dest_start = bytes.sub_array (0, bytes.length - instructions_length (bytes)); } + + void set_overlaps_flag () + { + CompositeGlyphRecord& glyph_chain = const_cast<CompositeGlyphRecord &> ( + StructAfter<CompositeGlyphRecord, GlyphHeader> (header)); + if (!bytes.check_range(&glyph_chain, CompositeGlyphRecord::min_size)) + return; + glyph_chain.set_overlaps_flag (); + } +}; + + +} /* namespace glyf_impl */ +} /* namespace OT */ + + +#endif /* OT_GLYF_COMPOSITEGLYPH_HH */ diff --git a/thirdparty/harfbuzz/src/OT/glyf/Glyph.hh b/thirdparty/harfbuzz/src/OT/glyf/Glyph.hh new file mode 100644 index 0000000000..2199d2c48b --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/glyf/Glyph.hh @@ -0,0 +1,233 @@ +#ifndef OT_GLYF_GLYPH_HH +#define OT_GLYF_GLYPH_HH + + +#include "../../hb-open-type.hh" + +#include "GlyphHeader.hh" +#include "SimpleGlyph.hh" +#include "CompositeGlyph.hh" + + +namespace OT { + +struct glyf_accelerator_t; + +namespace glyf_impl { + + +enum phantom_point_index_t +{ + PHANTOM_LEFT = 0, + PHANTOM_RIGHT = 1, + PHANTOM_TOP = 2, + PHANTOM_BOTTOM = 3, + PHANTOM_COUNT = 4 +}; + +struct Glyph +{ + enum glyph_type_t { EMPTY, SIMPLE, COMPOSITE }; + + public: + composite_iter_t get_composite_iterator () const + { + if (type != COMPOSITE) return composite_iter_t (); + return CompositeGlyph (*header, bytes).iter (); + } + + const hb_bytes_t trim_padding () const + { + switch (type) { + case COMPOSITE: return CompositeGlyph (*header, bytes).trim_padding (); + case SIMPLE: return SimpleGlyph (*header, bytes).trim_padding (); + default: return bytes; + } + } + + void drop_hints () + { + switch (type) { + case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints (); return; + case SIMPLE: SimpleGlyph (*header, bytes).drop_hints (); return; + default: return; + } + } + + void set_overlaps_flag () + { + switch (type) { + case COMPOSITE: CompositeGlyph (*header, bytes).set_overlaps_flag (); return; + case SIMPLE: SimpleGlyph (*header, bytes).set_overlaps_flag (); return; + default: return; + } + } + + void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const + { + switch (type) { + case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints_bytes (dest_start); return; + case SIMPLE: SimpleGlyph (*header, bytes).drop_hints_bytes (dest_start, dest_end); return; + default: return; + } + } + + /* Note: Recursively calls itself. + * all_points includes phantom points + */ + template <typename accelerator_t> + bool get_points (hb_font_t *font, const accelerator_t &glyf_accelerator, + contour_point_vector_t &all_points /* OUT */, + bool phantom_only = false, + unsigned int depth = 0) const + { + if (unlikely (depth > HB_MAX_NESTING_LEVEL)) return false; + contour_point_vector_t stack_points; + bool inplace = type == SIMPLE && all_points.length == 0; + /* Load into all_points if it's empty, as an optimization. */ + contour_point_vector_t &points = inplace ? all_points : stack_points; + + switch (type) { + case COMPOSITE: + { + /* pseudo component points for each component in composite glyph */ + unsigned num_points = hb_len (CompositeGlyph (*header, bytes).iter ()); + if (unlikely (!points.resize (num_points))) return false; + break; + } + case SIMPLE: + if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (points, phantom_only))) + return false; + break; + } + + /* Init phantom points */ + if (unlikely (!points.resize (points.length + PHANTOM_COUNT))) return false; + hb_array_t<contour_point_t> phantoms = points.sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT); + { + int h_delta = (int) header->xMin - + glyf_accelerator.hmtx->get_side_bearing (gid); + int v_orig = (int) header->yMax + +#ifndef HB_NO_VERTICAL + glyf_accelerator.vmtx->get_side_bearing (gid) +#else + 0 +#endif + ; + unsigned h_adv = glyf_accelerator.hmtx->get_advance (gid); + unsigned v_adv = +#ifndef HB_NO_VERTICAL + glyf_accelerator.vmtx->get_advance (gid) +#else + - font->face->get_upem () +#endif + ; + phantoms[PHANTOM_LEFT].x = h_delta; + phantoms[PHANTOM_RIGHT].x = h_adv + h_delta; + phantoms[PHANTOM_TOP].y = v_orig; + phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv; + } + +#ifndef HB_NO_VAR + glyf_accelerator.gvar->apply_deltas_to_points (gid, font, points.as_array ()); +#endif + + switch (type) { + case SIMPLE: + if (!inplace) + all_points.extend (points.as_array ()); + break; + case COMPOSITE: + { + contour_point_vector_t comp_points; + unsigned int comp_index = 0; + for (auto &item : get_composite_iterator ()) + { + comp_points.reset (); + if (unlikely (!glyf_accelerator.glyph_for_gid (item.glyphIndex) + .get_points (font, glyf_accelerator, comp_points, + phantom_only, depth + 1))) + return false; + + /* Copy phantom points from component if USE_MY_METRICS flag set */ + if (item.is_use_my_metrics ()) + for (unsigned int i = 0; i < PHANTOM_COUNT; i++) + phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i]; + + /* Apply component transformation & translation */ + item.transform_points (comp_points); + + /* Apply translation from gvar */ + comp_points.translate (points[comp_index]); + + if (item.is_anchored ()) + { + unsigned int p1, p2; + item.get_anchor_points (p1, p2); + if (likely (p1 < all_points.length && p2 < comp_points.length)) + { + contour_point_t delta; + delta.init (all_points[p1].x - comp_points[p2].x, + all_points[p1].y - comp_points[p2].y); + + comp_points.translate (delta); + } + } + + all_points.extend (comp_points.sub_array (0, comp_points.length - PHANTOM_COUNT)); + + comp_index++; + } + + all_points.extend (phantoms); + } break; + default: + all_points.extend (phantoms); + } + + if (depth == 0) /* Apply at top level */ + { + /* Undocumented rasterizer behavior: + * Shift points horizontally by the updated left side bearing + */ + contour_point_t delta; + delta.init (-phantoms[PHANTOM_LEFT].x, 0.f); + if (delta.x) all_points.translate (delta); + } + + return !all_points.in_error (); + } + + bool get_extents (hb_font_t *font, const glyf_accelerator_t &glyf_accelerator, + hb_glyph_extents_t *extents) const + { + if (type == EMPTY) return true; /* Empty glyph; zero extents. */ + return header->get_extents (font, glyf_accelerator, gid, extents); + } + + hb_bytes_t get_bytes () const { return bytes; } + + Glyph (hb_bytes_t bytes_ = hb_bytes_t (), + hb_codepoint_t gid_ = (hb_codepoint_t) -1) : bytes (bytes_), + header (bytes.as<GlyphHeader> ()), + gid (gid_) + { + int num_contours = header->numberOfContours; + if (unlikely (num_contours == 0)) type = EMPTY; + else if (num_contours > 0) type = SIMPLE; + else type = COMPOSITE; /* negative numbers */ + } + + protected: + hb_bytes_t bytes; + const GlyphHeader *header; + hb_codepoint_t gid; + unsigned type; +}; + + +} /* namespace glyf_impl */ +} /* namespace OT */ + + +#endif /* OT_GLYF_GLYPH_HH */ diff --git a/thirdparty/harfbuzz/src/OT/glyf/GlyphHeader.hh b/thirdparty/harfbuzz/src/OT/glyf/GlyphHeader.hh new file mode 100644 index 0000000000..792bd5478f --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/glyf/GlyphHeader.hh @@ -0,0 +1,48 @@ +#ifndef OT_GLYF_GLYPHHEADER_HH +#define OT_GLYF_GLYPHHEADER_HH + + +#include "../../hb-open-type.hh" + + +namespace OT { +namespace glyf_impl { + + +struct GlyphHeader +{ + bool has_data () const { return numberOfContours; } + + template <typename accelerator_t> + bool get_extents (hb_font_t *font, const accelerator_t &glyf_accelerator, + hb_codepoint_t gid, hb_glyph_extents_t *extents) const + { + /* Undocumented rasterizer behavior: shift glyph to the left by (lsb - xMin), i.e., xMin = lsb */ + /* extents->x_bearing = hb_min (glyph_header.xMin, glyph_header.xMax); */ + extents->x_bearing = font->em_scale_x (glyf_accelerator.hmtx->get_side_bearing (gid)); + extents->y_bearing = font->em_scale_y (hb_max (yMin, yMax)); + extents->width = font->em_scale_x (hb_max (xMin, xMax) - hb_min (xMin, xMax)); + extents->height = font->em_scale_y (hb_min (yMin, yMax) - hb_max (yMin, yMax)); + + return true; + } + + HBINT16 numberOfContours; + /* If the number of contours is + * greater than or equal to zero, + * this is a simple glyph; if negative, + * this is a composite glyph. */ + FWORD xMin; /* Minimum x for coordinate data. */ + FWORD yMin; /* Minimum y for coordinate data. */ + FWORD xMax; /* Maximum x for coordinate data. */ + FWORD yMax; /* Maximum y for coordinate data. */ + public: + DEFINE_SIZE_STATIC (10); +}; + + +} /* namespace glyf_impl */ +} /* namespace OT */ + + +#endif /* OT_GLYF_GLYPHHEADER_HH */ diff --git a/thirdparty/harfbuzz/src/OT/glyf/SimpleGlyph.hh b/thirdparty/harfbuzz/src/OT/glyf/SimpleGlyph.hh new file mode 100644 index 0000000000..6df978cf13 --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/glyf/SimpleGlyph.hh @@ -0,0 +1,216 @@ +#ifndef OT_GLYF_SIMPLEGLYPH_HH +#define OT_GLYF_SIMPLEGLYPH_HH + + +#include "../../hb-open-type.hh" + + +namespace OT { +namespace glyf_impl { + + +struct SimpleGlyph +{ + enum simple_glyph_flag_t + { + FLAG_ON_CURVE = 0x01, + FLAG_X_SHORT = 0x02, + FLAG_Y_SHORT = 0x04, + FLAG_REPEAT = 0x08, + FLAG_X_SAME = 0x10, + FLAG_Y_SAME = 0x20, + FLAG_OVERLAP_SIMPLE = 0x40, + FLAG_RESERVED2 = 0x80 + }; + + const GlyphHeader &header; + hb_bytes_t bytes; + SimpleGlyph (const GlyphHeader &header_, hb_bytes_t bytes_) : + header (header_), bytes (bytes_) {} + + unsigned int instruction_len_offset () const + { return GlyphHeader::static_size + 2 * header.numberOfContours; } + + unsigned int length (unsigned int instruction_len) const + { return instruction_len_offset () + 2 + instruction_len; } + + unsigned int instructions_length () const + { + unsigned int instruction_length_offset = instruction_len_offset (); + if (unlikely (instruction_length_offset + 2 > bytes.length)) return 0; + + const HBUINT16 &instructionLength = StructAtOffset<HBUINT16> (&bytes, instruction_length_offset); + /* Out of bounds of the current glyph */ + if (unlikely (length (instructionLength) > bytes.length)) return 0; + return instructionLength; + } + + const hb_bytes_t trim_padding () const + { + /* based on FontTools _g_l_y_f.py::trim */ + const uint8_t *glyph = (uint8_t*) bytes.arrayZ; + const uint8_t *glyph_end = glyph + bytes.length; + /* simple glyph w/contours, possibly trimmable */ + glyph += instruction_len_offset (); + + if (unlikely (glyph + 2 >= glyph_end)) return hb_bytes_t (); + unsigned int num_coordinates = StructAtOffset<HBUINT16> (glyph - 2, 0) + 1; + unsigned int num_instructions = StructAtOffset<HBUINT16> (glyph, 0); + + glyph += 2 + num_instructions; + + unsigned int coord_bytes = 0; + unsigned int coords_with_flags = 0; + while (glyph < glyph_end) + { + uint8_t flag = *glyph; + glyph++; + + unsigned int repeat = 1; + if (flag & FLAG_REPEAT) + { + if (unlikely (glyph >= glyph_end)) return hb_bytes_t (); + repeat = *glyph + 1; + glyph++; + } + + unsigned int xBytes, yBytes; + xBytes = yBytes = 0; + if (flag & FLAG_X_SHORT) xBytes = 1; + else if ((flag & FLAG_X_SAME) == 0) xBytes = 2; + + if (flag & FLAG_Y_SHORT) yBytes = 1; + else if ((flag & FLAG_Y_SAME) == 0) yBytes = 2; + + coord_bytes += (xBytes + yBytes) * repeat; + coords_with_flags += repeat; + if (coords_with_flags >= num_coordinates) break; + } + + if (unlikely (coords_with_flags != num_coordinates)) return hb_bytes_t (); + return bytes.sub_array (0, bytes.length + coord_bytes - (glyph_end - glyph)); + } + + /* zero instruction length */ + void drop_hints () + { + GlyphHeader &glyph_header = const_cast<GlyphHeader &> (header); + (HBUINT16 &) StructAtOffset<HBUINT16> (&glyph_header, instruction_len_offset ()) = 0; + } + + void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const + { + unsigned int instructions_len = instructions_length (); + unsigned int glyph_length = length (instructions_len); + dest_start = bytes.sub_array (0, glyph_length - instructions_len); + dest_end = bytes.sub_array (glyph_length, bytes.length - glyph_length); + } + + void set_overlaps_flag () + { + if (unlikely (!header.numberOfContours)) return; + + unsigned flags_offset = length (instructions_length ()); + if (unlikely (flags_offset + 1 > bytes.length)) return; + + HBUINT8 &first_flag = (HBUINT8 &) StructAtOffset<HBUINT16> (&bytes, flags_offset); + first_flag = (uint8_t) first_flag | FLAG_OVERLAP_SIMPLE; + } + + static bool read_flags (const HBUINT8 *&p /* IN/OUT */, + contour_point_vector_t &points_ /* IN/OUT */, + const HBUINT8 *end) + { + unsigned count = points_.length; + for (unsigned int i = 0; i < count;) + { + if (unlikely (p + 1 > end)) return false; + uint8_t flag = *p++; + points_.arrayZ[i++].flag = flag; + if (flag & FLAG_REPEAT) + { + if (unlikely (p + 1 > end)) return false; + unsigned int repeat_count = *p++; + unsigned stop = hb_min (i + repeat_count, count); + for (; i < stop;) + points_.arrayZ[i++].flag = flag; + } + } + return true; + } + + static bool read_points (const HBUINT8 *&p /* IN/OUT */, + contour_point_vector_t &points_ /* IN/OUT */, + const HBUINT8 *end, + float contour_point_t::*m, + const simple_glyph_flag_t short_flag, + const simple_glyph_flag_t same_flag) + { + int v = 0; + + unsigned count = points_.length; + for (unsigned i = 0; i < count; i++) + { + unsigned flag = points_[i].flag; + if (flag & short_flag) + { + if (unlikely (p + 1 > end)) return false; + if (flag & same_flag) + v += *p++; + else + v -= *p++; + } + else + { + if (!(flag & same_flag)) + { + if (unlikely (p + HBINT16::static_size > end)) return false; + v += *(const HBINT16 *) p; + p += HBINT16::static_size; + } + } + points_.arrayZ[i].*m = v; + } + return true; + } + + bool get_contour_points (contour_point_vector_t &points_ /* OUT */, + bool phantom_only = false) const + { + const HBUINT16 *endPtsOfContours = &StructAfter<HBUINT16> (header); + int num_contours = header.numberOfContours; + assert (num_contours); + /* One extra item at the end, for the instruction-count below. */ + if (unlikely (!bytes.check_range (&endPtsOfContours[num_contours]))) return false; + unsigned int num_points = endPtsOfContours[num_contours - 1] + 1; + + points_.alloc (num_points + 4); // Allocate for phantom points, to avoid a possible copy + if (!points_.resize (num_points)) return false; + if (phantom_only) return true; + + for (int i = 0; i < num_contours; i++) + points_[endPtsOfContours[i]].is_end_point = true; + + /* Skip instructions */ + const HBUINT8 *p = &StructAtOffset<HBUINT8> (&endPtsOfContours[num_contours + 1], + endPtsOfContours[num_contours]); + + if (unlikely ((const char *) p < bytes.arrayZ)) return false; /* Unlikely overflow */ + const HBUINT8 *end = (const HBUINT8 *) (bytes.arrayZ + bytes.length); + if (unlikely (p >= end)) return false; + + /* Read x & y coordinates */ + return read_flags (p, points_, end) + && read_points (p, points_, end, &contour_point_t::x, + FLAG_X_SHORT, FLAG_X_SAME) + && read_points (p, points_, end, &contour_point_t::y, + FLAG_Y_SHORT, FLAG_Y_SAME); + } +}; + + +} /* namespace glyf_impl */ +} /* namespace OT */ + + +#endif /* OT_GLYF_SIMPLEGLYPH_HH */ diff --git a/thirdparty/harfbuzz/src/OT/glyf/SubsetGlyph.hh b/thirdparty/harfbuzz/src/OT/glyf/SubsetGlyph.hh new file mode 100644 index 0000000000..ebe4372047 --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/glyf/SubsetGlyph.hh @@ -0,0 +1,72 @@ +#ifndef OT_GLYF_SUBSETGLYPH_HH +#define OT_GLYF_SUBSETGLYPH_HH + + +#include "../../hb-open-type.hh" + + +namespace OT { +namespace glyf_impl { + + +struct SubsetGlyph +{ + hb_codepoint_t new_gid; + hb_codepoint_t old_gid; + Glyph source_glyph; + hb_bytes_t dest_start; /* region of source_glyph to copy first */ + hb_bytes_t dest_end; /* region of source_glyph to copy second */ + + bool serialize (hb_serialize_context_t *c, + bool use_short_loca, + const hb_subset_plan_t *plan) const + { + TRACE_SERIALIZE (this); + + hb_bytes_t dest_glyph = dest_start.copy (c); + dest_glyph = hb_bytes_t (&dest_glyph, dest_glyph.length + dest_end.copy (c).length); + unsigned int pad_length = use_short_loca ? padding () : 0; + DEBUG_MSG (SUBSET, nullptr, "serialize %d byte glyph, width %d pad %d", dest_glyph.length, dest_glyph.length + pad_length, pad_length); + + HBUINT8 pad; + pad = 0; + while (pad_length > 0) + { + c->embed (pad); + pad_length--; + } + + if (unlikely (!dest_glyph.length)) return_trace (true); + + /* update components gids */ + for (auto &_ : Glyph (dest_glyph).get_composite_iterator ()) + { + hb_codepoint_t new_gid; + if (plan->new_gid_for_old_gid (_.glyphIndex, &new_gid)) + const_cast<CompositeGlyphRecord &> (_).glyphIndex = new_gid; + } + + if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING) + Glyph (dest_glyph).drop_hints (); + + if (plan->flags & HB_SUBSET_FLAGS_SET_OVERLAPS_FLAG) + Glyph (dest_glyph).set_overlaps_flag (); + + return_trace (true); + } + + void drop_hints_bytes () + { source_glyph.drop_hints_bytes (dest_start, dest_end); } + + unsigned int length () const { return dest_start.length + dest_end.length; } + /* pad to 2 to ensure 2-byte loca will be ok */ + unsigned int padding () const { return length () % 2; } + unsigned int padded_size () const { return length () + padding (); } +}; + + +} /* namespace glyf_impl */ +} /* namespace OT */ + + +#endif /* OT_GLYF_SUBSETGLYPH_HH */ diff --git a/thirdparty/harfbuzz/src/OT/glyf/glyf-helpers.hh b/thirdparty/harfbuzz/src/OT/glyf/glyf-helpers.hh new file mode 100644 index 0000000000..f51f7a81fc --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/glyf/glyf-helpers.hh @@ -0,0 +1,90 @@ +#ifndef OT_GLYF_GLYF_HELPERS_HH +#define OT_GLYF_GLYF_HELPERS_HH + + +#include "../../hb-open-type.hh" +#include "../../hb-subset-plan.hh" + +#include "loca.hh" + + +namespace OT { +namespace glyf_impl { + + +template<typename IteratorIn, typename IteratorOut, + hb_requires (hb_is_source_of (IteratorIn, unsigned int)), + hb_requires (hb_is_sink_of (IteratorOut, unsigned))> +static void +_write_loca (IteratorIn it, bool short_offsets, IteratorOut dest) +{ + unsigned right_shift = short_offsets ? 1 : 0; + unsigned int offset = 0; + dest << 0; + + it + | hb_map ([=, &offset] (unsigned int padded_size) + { + offset += padded_size; + DEBUG_MSG (SUBSET, nullptr, "loca entry offset %d", offset); + return offset >> right_shift; + }) + | hb_sink (dest) + ; +} + +static bool +_add_head_and_set_loca_version (hb_subset_plan_t *plan, bool use_short_loca) +{ + hb_blob_t *head_blob = hb_sanitize_context_t ().reference_table<head> (plan->source); + hb_blob_t *head_prime_blob = hb_blob_copy_writable_or_fail (head_blob); + hb_blob_destroy (head_blob); + + if (unlikely (!head_prime_blob)) + return false; + + head *head_prime = (head *) hb_blob_get_data_writable (head_prime_blob, nullptr); + head_prime->indexToLocFormat = use_short_loca ? 0 : 1; + bool success = plan->add_table (HB_OT_TAG_head, head_prime_blob); + + hb_blob_destroy (head_prime_blob); + return success; +} + +template<typename Iterator, + hb_requires (hb_is_source_of (Iterator, unsigned int))> +static bool +_add_loca_and_head (hb_subset_plan_t * plan, Iterator padded_offsets, bool use_short_loca) +{ + unsigned num_offsets = padded_offsets.len () + 1; + unsigned entry_size = use_short_loca ? 2 : 4; + char *loca_prime_data = (char *) hb_calloc (entry_size, num_offsets); + + if (unlikely (!loca_prime_data)) return false; + + DEBUG_MSG (SUBSET, nullptr, "loca entry_size %d num_offsets %d size %d", + entry_size, num_offsets, entry_size * num_offsets); + + if (use_short_loca) + _write_loca (padded_offsets, true, hb_array ((HBUINT16 *) loca_prime_data, num_offsets)); + else + _write_loca (padded_offsets, false, hb_array ((HBUINT32 *) loca_prime_data, num_offsets)); + + hb_blob_t *loca_blob = hb_blob_create (loca_prime_data, + entry_size * num_offsets, + HB_MEMORY_MODE_WRITABLE, + loca_prime_data, + hb_free); + + bool result = plan->add_table (HB_OT_TAG_loca, loca_blob) + && _add_head_and_set_loca_version (plan, use_short_loca); + + hb_blob_destroy (loca_blob); + return result; +} + + +} /* namespace glyf_impl */ +} /* namespace OT */ + + +#endif /* OT_GLYF_GLYF_HELPERS_HH */ diff --git a/thirdparty/harfbuzz/src/OT/glyf/glyf.hh b/thirdparty/harfbuzz/src/OT/glyf/glyf.hh new file mode 100644 index 0000000000..f74513cb96 --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/glyf/glyf.hh @@ -0,0 +1,388 @@ +#ifndef OT_GLYF_GLYF_HH +#define OT_GLYF_GLYF_HH + + +#include "../../hb-open-type.hh" +#include "../../hb-ot-head-table.hh" +#include "../../hb-ot-hmtx-table.hh" +#include "../../hb-ot-var-gvar-table.hh" +#include "../../hb-draw.hh" + +#include "glyf-helpers.hh" +#include "Glyph.hh" +#include "SubsetGlyph.hh" +#include "loca.hh" +#include "path-builder.hh" + + +namespace OT { + + +/* + * glyf -- TrueType Glyph Data + * https://docs.microsoft.com/en-us/typography/opentype/spec/glyf + */ +#define HB_OT_TAG_glyf HB_TAG('g','l','y','f') + + +struct glyf +{ + friend struct glyf_accelerator_t; + + static constexpr hb_tag_t tableTag = HB_OT_TAG_glyf; + + bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const + { + TRACE_SANITIZE (this); + /* Runtime checks as eager sanitizing each glyph is costy */ + return_trace (true); + } + + /* requires source of SubsetGlyph complains the identifier isn't declared */ + template <typename Iterator> + bool serialize (hb_serialize_context_t *c, + Iterator it, + bool use_short_loca, + const hb_subset_plan_t *plan) + { + TRACE_SERIALIZE (this); + unsigned init_len = c->length (); + for (const auto &_ : it) _.serialize (c, use_short_loca, plan); + + /* As a special case when all glyph in the font are empty, add a zero byte + * to the table, so that OTS doesn’t reject it, and to make the table work + * on Windows as well. + * See https://github.com/khaledhosny/ots/issues/52 */ + if (init_len == c->length ()) + { + HBUINT8 empty_byte; + empty_byte = 0; + c->copy (empty_byte); + } + return_trace (true); + } + + /* Byte region(s) per glyph to output + unpadded, hints removed if so requested + If we fail to process a glyph we produce an empty (0-length) glyph */ + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + + glyf *glyf_prime = c->serializer->start_embed <glyf> (); + if (unlikely (!c->serializer->check_success (glyf_prime))) return_trace (false); + + hb_vector_t<glyf_impl::SubsetGlyph> glyphs; + _populate_subset_glyphs (c->plan, &glyphs); + + auto padded_offsets = + + hb_iter (glyphs) + | hb_map (&glyf_impl::SubsetGlyph::padded_size) + ; + + unsigned max_offset = + padded_offsets | hb_reduce (hb_add, 0); + bool use_short_loca = max_offset < 0x1FFFF; + + + glyf_prime->serialize (c->serializer, hb_iter (glyphs), use_short_loca, c->plan); + if (!use_short_loca) { + padded_offsets = + + hb_iter (glyphs) + | hb_map (&glyf_impl::SubsetGlyph::length) + ; + } + + + if (unlikely (c->serializer->in_error ())) return_trace (false); + return_trace (c->serializer->check_success (glyf_impl::_add_loca_and_head (c->plan, + padded_offsets, + use_short_loca))); + } + + void + _populate_subset_glyphs (const hb_subset_plan_t *plan, + hb_vector_t<glyf_impl::SubsetGlyph> *glyphs /* OUT */) const; + + protected: + UnsizedArrayOf<HBUINT8> + dataZ; /* Glyphs data. */ + public: + DEFINE_SIZE_MIN (0); /* In reality, this is UNBOUNDED() type; but since we always + * check the size externally, allow Null() object of it by + * defining it _MIN instead. */ +}; + +struct glyf_accelerator_t +{ + glyf_accelerator_t (hb_face_t *face) + { + short_offset = false; + num_glyphs = 0; + loca_table = nullptr; + glyf_table = nullptr; +#ifndef HB_NO_VAR + gvar = nullptr; +#endif + hmtx = nullptr; +#ifndef HB_NO_VERTICAL + vmtx = nullptr; +#endif + const OT::head &head = *face->table.head; + if (head.indexToLocFormat > 1 || head.glyphDataFormat > 0) + /* Unknown format. Leave num_glyphs=0, that takes care of disabling us. */ + return; + short_offset = 0 == head.indexToLocFormat; + + loca_table = face->table.loca.get_blob (); // Needs no destruct! + glyf_table = hb_sanitize_context_t ().reference_table<glyf> (face); +#ifndef HB_NO_VAR + gvar = face->table.gvar; +#endif + hmtx = face->table.hmtx; +#ifndef HB_NO_VERTICAL + vmtx = face->table.vmtx; +#endif + + num_glyphs = hb_max (1u, loca_table.get_length () / (short_offset ? 2 : 4)) - 1; + num_glyphs = hb_min (num_glyphs, face->get_num_glyphs ()); + } + ~glyf_accelerator_t () + { + glyf_table.destroy (); + } + + bool has_data () const { return num_glyphs; } + + protected: + template<typename T> + bool get_points (hb_font_t *font, hb_codepoint_t gid, T consumer) const + { + if (gid >= num_glyphs) return false; + + /* Making this allocfree is not that easy + https://github.com/harfbuzz/harfbuzz/issues/2095 + mostly because of gvar handling in VF fonts, + perhaps a separate path for non-VF fonts can be considered */ + contour_point_vector_t all_points; + + bool phantom_only = !consumer.is_consuming_contour_points (); + if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, phantom_only))) + return false; + + if (consumer.is_consuming_contour_points ()) + { + unsigned count = all_points.length; + assert (count >= glyf_impl::PHANTOM_COUNT); + count -= glyf_impl::PHANTOM_COUNT; + for (unsigned point_index = 0; point_index < count; point_index++) + consumer.consume_point (all_points[point_index]); + consumer.points_end (); + } + + /* Where to write phantoms, nullptr if not requested */ + contour_point_t *phantoms = consumer.get_phantoms_sink (); + if (phantoms) + for (unsigned i = 0; i < glyf_impl::PHANTOM_COUNT; ++i) + phantoms[i] = all_points[all_points.length - glyf_impl::PHANTOM_COUNT + i]; + + return true; + } + +#ifndef HB_NO_VAR + struct points_aggregator_t + { + hb_font_t *font; + hb_glyph_extents_t *extents; + contour_point_t *phantoms; + + struct contour_bounds_t + { + contour_bounds_t () { min_x = min_y = FLT_MAX; max_x = max_y = -FLT_MAX; } + + void add (const contour_point_t &p) + { + min_x = hb_min (min_x, p.x); + min_y = hb_min (min_y, p.y); + max_x = hb_max (max_x, p.x); + max_y = hb_max (max_y, p.y); + } + + bool empty () const { return (min_x >= max_x) || (min_y >= max_y); } + + void get_extents (hb_font_t *font, hb_glyph_extents_t *extents) + { + if (unlikely (empty ())) + { + extents->width = 0; + extents->x_bearing = 0; + extents->height = 0; + extents->y_bearing = 0; + return; + } + extents->x_bearing = font->em_scalef_x (min_x); + extents->width = font->em_scalef_x (max_x) - extents->x_bearing; + extents->y_bearing = font->em_scalef_y (max_y); + extents->height = font->em_scalef_y (min_y) - extents->y_bearing; + } + + protected: + float min_x, min_y, max_x, max_y; + } bounds; + + points_aggregator_t (hb_font_t *font_, hb_glyph_extents_t *extents_, contour_point_t *phantoms_) + { + font = font_; + extents = extents_; + phantoms = phantoms_; + if (extents) bounds = contour_bounds_t (); + } + + void consume_point (const contour_point_t &point) { bounds.add (point); } + void points_end () { bounds.get_extents (font, extents); } + + bool is_consuming_contour_points () { return extents; } + contour_point_t *get_phantoms_sink () { return phantoms; } + }; + + public: + unsigned + get_advance_var (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const + { + if (unlikely (gid >= num_glyphs)) return 0; + + bool success = false; + + contour_point_t phantoms[glyf_impl::PHANTOM_COUNT]; + if (likely (font->num_coords == gvar->get_axis_count ())) + success = get_points (font, gid, points_aggregator_t (font, nullptr, phantoms)); + + if (unlikely (!success)) + return +#ifndef HB_NO_VERTICAL + is_vertical ? vmtx->get_advance (gid) : +#endif + hmtx->get_advance (gid); + + float result = is_vertical + ? phantoms[glyf_impl::PHANTOM_TOP].y - phantoms[glyf_impl::PHANTOM_BOTTOM].y + : phantoms[glyf_impl::PHANTOM_RIGHT].x - phantoms[glyf_impl::PHANTOM_LEFT].x; + return hb_clamp (roundf (result), 0.f, (float) UINT_MAX / 2); + } + + int get_side_bearing_var (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const + { + if (unlikely (gid >= num_glyphs)) return 0; + + hb_glyph_extents_t extents; + + contour_point_t phantoms[glyf_impl::PHANTOM_COUNT]; + if (unlikely (!get_points (font, gid, points_aggregator_t (font, &extents, phantoms)))) + return +#ifndef HB_NO_VERTICAL + is_vertical ? vmtx->get_side_bearing (gid) : +#endif + hmtx->get_side_bearing (gid); + + return is_vertical + ? ceilf (phantoms[glyf_impl::PHANTOM_TOP].y) - extents.y_bearing + : floorf (phantoms[glyf_impl::PHANTOM_LEFT].x); + } +#endif + + public: + bool get_extents (hb_font_t *font, hb_codepoint_t gid, hb_glyph_extents_t *extents) const + { + if (unlikely (gid >= num_glyphs)) return false; + +#ifndef HB_NO_VAR + if (font->num_coords) + return get_points (font, gid, points_aggregator_t (font, extents, nullptr)); +#endif + return glyph_for_gid (gid).get_extents (font, *this, extents); + } + + const glyf_impl::Glyph + glyph_for_gid (hb_codepoint_t gid, bool needs_padding_removal = false) const + { + if (unlikely (gid >= num_glyphs)) return glyf_impl::Glyph (); + + unsigned int start_offset, end_offset; + + if (short_offset) + { + const HBUINT16 *offsets = (const HBUINT16 *) loca_table->dataZ.arrayZ; + start_offset = 2 * offsets[gid]; + end_offset = 2 * offsets[gid + 1]; + } + else + { + const HBUINT32 *offsets = (const HBUINT32 *) loca_table->dataZ.arrayZ; + start_offset = offsets[gid]; + end_offset = offsets[gid + 1]; + } + + if (unlikely (start_offset > end_offset || end_offset > glyf_table.get_length ())) + return glyf_impl::Glyph (); + + glyf_impl::Glyph glyph (hb_bytes_t ((const char *) this->glyf_table + start_offset, + end_offset - start_offset), gid); + return needs_padding_removal ? glyf_impl::Glyph (glyph.trim_padding (), gid) : glyph; + } + + bool + get_path (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session) const + { return get_points (font, gid, glyf_impl::path_builder_t (font, draw_session)); } + +#ifndef HB_NO_VAR + const gvar_accelerator_t *gvar; +#endif + const hmtx_accelerator_t *hmtx; +#ifndef HB_NO_VERTICAL + const vmtx_accelerator_t *vmtx; +#endif + + private: + bool short_offset; + unsigned int num_glyphs; + hb_blob_ptr_t<loca> loca_table; + hb_blob_ptr_t<glyf> glyf_table; +}; + + +inline void +glyf::_populate_subset_glyphs (const hb_subset_plan_t *plan, + hb_vector_t<glyf_impl::SubsetGlyph> *glyphs /* OUT */) const +{ + OT::glyf_accelerator_t glyf (plan->source); + + + hb_range (plan->num_output_glyphs ()) + | hb_map ([&] (hb_codepoint_t new_gid) + { + glyf_impl::SubsetGlyph subset_glyph = {0}; + subset_glyph.new_gid = new_gid; + + /* should never fail: all old gids should be mapped */ + if (!plan->old_gid_for_new_gid (new_gid, &subset_glyph.old_gid)) + return subset_glyph; + + if (new_gid == 0 && + !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)) + subset_glyph.source_glyph = glyf_impl::Glyph (); + else + subset_glyph.source_glyph = glyf.glyph_for_gid (subset_glyph.old_gid, true); + if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING) + subset_glyph.drop_hints_bytes (); + else + subset_glyph.dest_start = subset_glyph.source_glyph.get_bytes (); + return subset_glyph; + }) + | hb_sink (glyphs) + ; +} + + + +} /* namespace OT */ + + +#endif /* OT_GLYF_GLYF_HH */ diff --git a/thirdparty/harfbuzz/src/OT/glyf/loca.hh b/thirdparty/harfbuzz/src/OT/glyf/loca.hh new file mode 100644 index 0000000000..4481cba8ed --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/glyf/loca.hh @@ -0,0 +1,43 @@ +#ifndef OT_GLYF_LOCA_HH +#define OT_GLYF_LOCA_HH + + +#include "../../hb-open-type.hh" + + +namespace OT { + + +/* + * loca -- Index to Location + * https://docs.microsoft.com/en-us/typography/opentype/spec/loca + */ +#define HB_OT_TAG_loca HB_TAG('l','o','c','a') + +struct loca +{ + friend struct glyf; + friend struct glyf_accelerator_t; + + static constexpr hb_tag_t tableTag = HB_OT_TAG_loca; + + bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const + { + TRACE_SANITIZE (this); + return_trace (true); + } + + protected: + UnsizedArrayOf<HBUINT8> + dataZ; /* Location data. */ + public: + DEFINE_SIZE_MIN (0); /* In reality, this is UNBOUNDED() type; but since we always + * check the size externally, allow Null() object of it by + * defining it _MIN instead. */ +}; + + +} /* namespace OT */ + + +#endif /* OT_GLYF_LOCA_HH */ diff --git a/thirdparty/harfbuzz/src/OT/glyf/path-builder.hh b/thirdparty/harfbuzz/src/OT/glyf/path-builder.hh new file mode 100644 index 0000000000..9bfc45a1a6 --- /dev/null +++ b/thirdparty/harfbuzz/src/OT/glyf/path-builder.hh @@ -0,0 +1,135 @@ +#ifndef OT_GLYF_PATH_BUILDER_HH +#define OT_GLYF_PATH_BUILDER_HH + + +#include "../../hb.hh" + + +namespace OT { +namespace glyf_impl { + + +struct path_builder_t +{ + hb_font_t *font; + hb_draw_session_t *draw_session; + + struct optional_point_t + { + optional_point_t () {} + optional_point_t (float x_, float y_) : has_data (true), x (x_), y (y_) {} + operator bool () const { return has_data; } + + bool has_data = false; + float x = 0.; + float y = 0.; + + optional_point_t lerp (optional_point_t p, float t) + { return optional_point_t (x + t * (p.x - x), y + t * (p.y - y)); } + } first_oncurve, first_offcurve, last_offcurve; + + path_builder_t (hb_font_t *font_, hb_draw_session_t &draw_session_) + { + font = font_; + draw_session = &draw_session_; + first_oncurve = first_offcurve = last_offcurve = optional_point_t (); + } + + /* based on https://github.com/RazrFalcon/ttf-parser/blob/4f32821/src/glyf.rs#L287 + See also: + * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM01/Chap1.html + * https://stackoverflow.com/a/20772557 */ + void consume_point (const contour_point_t &point) + { + bool is_on_curve = point.flag & glyf_impl::SimpleGlyph::FLAG_ON_CURVE; + optional_point_t p (font->em_fscalef_x (point.x), font->em_fscalef_y (point.y)); + if (!first_oncurve) + { + if (is_on_curve) + { + first_oncurve = p; + draw_session->move_to (p.x, p.y); + } + else + { + if (first_offcurve) + { + optional_point_t mid = first_offcurve.lerp (p, .5f); + first_oncurve = mid; + last_offcurve = p; + draw_session->move_to (mid.x, mid.y); + } + else + first_offcurve = p; + } + } + else + { + if (last_offcurve) + { + if (is_on_curve) + { + draw_session->quadratic_to (last_offcurve.x, last_offcurve.y, + p.x, p.y); + last_offcurve = optional_point_t (); + } + else + { + optional_point_t mid = last_offcurve.lerp (p, .5f); + draw_session->quadratic_to (last_offcurve.x, last_offcurve.y, + mid.x, mid.y); + last_offcurve = p; + } + } + else + { + if (is_on_curve) + draw_session->line_to (p.x, p.y); + else + last_offcurve = p; + } + } + + if (point.is_end_point) + { + if (first_offcurve && last_offcurve) + { + optional_point_t mid = last_offcurve.lerp (first_offcurve, .5f); + draw_session->quadratic_to (last_offcurve.x, last_offcurve.y, + mid.x, mid.y); + last_offcurve = optional_point_t (); + /* now check the rest */ + } + + if (first_offcurve && first_oncurve) + draw_session->quadratic_to (first_offcurve.x, first_offcurve.y, + first_oncurve.x, first_oncurve.y); + else if (last_offcurve && first_oncurve) + draw_session->quadratic_to (last_offcurve.x, last_offcurve.y, + first_oncurve.x, first_oncurve.y); + else if (first_oncurve) + draw_session->line_to (first_oncurve.x, first_oncurve.y); + else if (first_offcurve) + { + float x = first_offcurve.x, y = first_offcurve.y; + draw_session->move_to (x, y); + draw_session->quadratic_to (x, y, x, y); + } + + /* Getting ready for the next contour */ + first_oncurve = first_offcurve = last_offcurve = optional_point_t (); + draw_session->close_path (); + } + } + void points_end () {} + + bool is_consuming_contour_points () { return true; } + contour_point_t *get_phantoms_sink () { return nullptr; } +}; + + +} /* namespace glyf_impl */ +} /* namespace OT */ + + +#endif /* OT_GLYF_PATH_BUILDER_HH */ diff --git a/thirdparty/harfbuzz/src/graph/graph.hh b/thirdparty/harfbuzz/src/graph/graph.hh new file mode 100644 index 0000000000..52ca9dd142 --- /dev/null +++ b/thirdparty/harfbuzz/src/graph/graph.hh @@ -0,0 +1,860 @@ +/* + * Copyright © 2022 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): Garret Rieger + */ + +#ifndef GRAPH_GRAPH_HH +#define GRAPH_GRAPH_HH + +namespace graph { + +/** + * Represents a serialized table in the form of a graph. + * Provides methods for modifying and reordering the graph. + */ +struct graph_t +{ + struct vertex_t + { + hb_serialize_context_t::object_t obj; + int64_t distance = 0 ; + int64_t space = 0 ; + hb_vector_t<unsigned> parents; + unsigned start = 0; + unsigned end = 0; + unsigned priority = 0; + + friend void swap (vertex_t& a, vertex_t& b) + { + hb_swap (a.obj, b.obj); + hb_swap (a.distance, b.distance); + hb_swap (a.space, b.space); + hb_swap (a.parents, b.parents); + hb_swap (a.start, b.start); + hb_swap (a.end, b.end); + hb_swap (a.priority, b.priority); + } + + bool is_shared () const + { + return parents.length > 1; + } + + unsigned incoming_edges () const + { + return parents.length; + } + + void remove_parent (unsigned parent_index) + { + for (unsigned i = 0; i < parents.length; i++) + { + if (parents[i] != parent_index) continue; + parents.remove (i); + break; + } + } + + void remap_parents (const hb_vector_t<unsigned>& id_map) + { + for (unsigned i = 0; i < parents.length; i++) + parents[i] = id_map[parents[i]]; + } + + void remap_parent (unsigned old_index, unsigned new_index) + { + for (unsigned i = 0; i < parents.length; i++) + { + if (parents[i] == old_index) + parents[i] = new_index; + } + } + + bool is_leaf () const + { + return !obj.real_links.length && !obj.virtual_links.length; + } + + bool raise_priority () + { + if (has_max_priority ()) return false; + priority++; + return true; + } + + bool has_max_priority () const { + return priority >= 3; + } + + int64_t modified_distance (unsigned order) const + { + // TODO(garretrieger): once priority is high enough, should try + // setting distance = 0 which will force to sort immediately after + // it's parent where possible. + + int64_t modified_distance = + hb_min (hb_max(distance + distance_modifier (), 0), 0x7FFFFFFFFFF); + if (has_max_priority ()) { + modified_distance = 0; + } + return (modified_distance << 18) | (0x003FFFF & order); + } + + int64_t distance_modifier () const + { + if (!priority) return 0; + int64_t table_size = obj.tail - obj.head; + + if (priority == 1) + return -table_size / 2; + + return -table_size; + } + }; + + /* + * A topological sorting of an object graph. Ordered + * in reverse serialization order (first object in the + * serialization is at the end of the list). This matches + * the 'packed' object stack used internally in the + * serializer + */ + template<typename T> + graph_t (const T& objects) + : parents_invalid (true), + distance_invalid (true), + positions_invalid (true), + successful (true) + { + num_roots_for_space_.push (1); + bool removed_nil = false; + vertices_.alloc (objects.length); + vertices_scratch_.alloc (objects.length); + for (unsigned i = 0; i < objects.length; i++) + { + // TODO(grieger): check all links point to valid objects. + + // If this graph came from a serialization buffer object 0 is the + // nil object. We don't need it for our purposes here so drop it. + if (i == 0 && !objects[i]) + { + removed_nil = true; + continue; + } + + vertex_t* v = vertices_.push (); + if (check_success (!vertices_.in_error ())) + v->obj = *objects[i]; + if (!removed_nil) continue; + // Fix indices to account for removed nil object. + for (auto& l : v->obj.all_links_writer ()) { + l.objidx--; + } + } + } + + ~graph_t () + { + vertices_.fini (); + } + + bool in_error () const + { + return !successful || + vertices_.in_error () || + num_roots_for_space_.in_error (); + } + + const vertex_t& root () const + { + return vertices_[root_idx ()]; + } + + unsigned root_idx () const + { + // Object graphs are in reverse order, the first object is at the end + // of the vector. Since the graph is topologically sorted it's safe to + // assume the first object has no incoming edges. + return vertices_.length - 1; + } + + const hb_serialize_context_t::object_t& object(unsigned i) const + { + return vertices_[i].obj; + } + + /* + * Generates a new topological sorting of graph ordered by the shortest + * distance to each node. + */ + void sort_shortest_distance () + { + positions_invalid = true; + + if (vertices_.length <= 1) { + // Graph of 1 or less doesn't need sorting. + return; + } + + update_distances (); + + hb_priority_queue_t queue; + hb_vector_t<vertex_t> &sorted_graph = vertices_scratch_; + if (unlikely (!check_success (sorted_graph.resize (vertices_.length)))) return; + hb_vector_t<unsigned> id_map; + if (unlikely (!check_success (id_map.resize (vertices_.length)))) return; + + hb_vector_t<unsigned> removed_edges; + if (unlikely (!check_success (removed_edges.resize (vertices_.length)))) return; + update_parents (); + + queue.insert (root ().modified_distance (0), root_idx ()); + int new_id = root_idx (); + unsigned order = 1; + while (!queue.in_error () && !queue.is_empty ()) + { + unsigned next_id = queue.pop_minimum().second; + + hb_swap (sorted_graph[new_id], vertices_[next_id]); + const vertex_t& next = sorted_graph[new_id]; + + id_map[next_id] = new_id--; + + for (const auto& link : next.obj.all_links ()) { + removed_edges[link.objidx]++; + if (!(vertices_[link.objidx].incoming_edges () - removed_edges[link.objidx])) + // Add the order that the links were encountered to the priority. + // This ensures that ties between priorities objects are broken in a consistent + // way. More specifically this is set up so that if a set of objects have the same + // distance they'll be added to the topological order in the order that they are + // referenced from the parent object. + queue.insert (vertices_[link.objidx].modified_distance (order++), + link.objidx); + } + } + + check_success (!queue.in_error ()); + check_success (!sorted_graph.in_error ()); + if (!check_success (new_id == -1)) + print_orphaned_nodes (); + + remap_all_obj_indices (id_map, &sorted_graph); + + hb_swap (vertices_, sorted_graph); + } + + /* + * Assign unique space numbers to each connected subgraph of 32 bit offset(s). + */ + bool assign_32bit_spaces () + { + unsigned root_index = root_idx (); + hb_set_t visited; + hb_set_t roots; + for (unsigned i = 0; i <= root_index; i++) + { + // Only real links can form 32 bit spaces + for (auto& l : vertices_[i].obj.real_links) + { + if (l.width == 4 && !l.is_signed) + { + roots.add (l.objidx); + find_subgraph (l.objidx, visited); + } + } + } + + // Mark everything not in the subgraphs of 32 bit roots as visited. + // This prevents 32 bit subgraphs from being connected via nodes not in the 32 bit subgraphs. + visited.invert (); + + if (!roots) return false; + + while (roots) + { + unsigned next = HB_SET_VALUE_INVALID; + if (unlikely (!check_success (!roots.in_error ()))) break; + if (!roots.next (&next)) break; + + hb_set_t connected_roots; + find_connected_nodes (next, roots, visited, connected_roots); + if (unlikely (!check_success (!connected_roots.in_error ()))) break; + + isolate_subgraph (connected_roots); + if (unlikely (!check_success (!connected_roots.in_error ()))) break; + + unsigned next_space = this->next_space (); + num_roots_for_space_.push (0); + for (unsigned root : connected_roots) + { + DEBUG_MSG (SUBSET_REPACK, nullptr, "Subgraph %u gets space %u", root, next_space); + vertices_[root].space = next_space; + num_roots_for_space_[next_space] = num_roots_for_space_[next_space] + 1; + distance_invalid = true; + positions_invalid = true; + } + + // TODO(grieger): special case for GSUB/GPOS use extension promotions to move 16 bit space + // into the 32 bit space as needed, instead of using isolation. + } + + + + return true; + } + + /* + * Isolates the subgraph of nodes reachable from root. Any links to nodes in the subgraph + * that originate from outside of the subgraph will be removed by duplicating the linked to + * object. + * + * Indices stored in roots will be updated if any of the roots are duplicated to new indices. + */ + bool isolate_subgraph (hb_set_t& roots) + { + update_parents (); + hb_map_t subgraph; + + // incoming edges to root_idx should be all 32 bit in length so we don't need to de-dup these + // set the subgraph incoming edge count to match all of root_idx's incoming edges + hb_set_t parents; + for (unsigned root_idx : roots) + { + subgraph.set (root_idx, wide_parents (root_idx, parents)); + find_subgraph (root_idx, subgraph); + } + + unsigned original_root_idx = root_idx (); + hb_map_t index_map; + bool made_changes = false; + for (auto entry : subgraph.iter ()) + { + const auto& node = vertices_[entry.first]; + unsigned subgraph_incoming_edges = entry.second; + + if (subgraph_incoming_edges < node.incoming_edges ()) + { + // Only de-dup objects with incoming links from outside the subgraph. + made_changes = true; + duplicate_subgraph (entry.first, index_map); + } + } + + if (!made_changes) + return false; + + if (original_root_idx != root_idx () + && parents.has (original_root_idx)) + { + // If the root idx has changed since parents was determined, update root idx in parents + parents.add (root_idx ()); + parents.del (original_root_idx); + } + + auto new_subgraph = + + subgraph.keys () + | hb_map([&] (unsigned node_idx) { + const unsigned *v; + if (index_map.has (node_idx, &v)) return *v; + return node_idx; + }) + ; + + remap_obj_indices (index_map, new_subgraph); + remap_obj_indices (index_map, parents.iter (), true); + + // Update roots set with new indices as needed. + unsigned next = HB_SET_VALUE_INVALID; + while (roots.next (&next)) + { + const unsigned *v; + if (index_map.has (next, &v)) + { + roots.del (next); + roots.add (*v); + } + } + + return true; + } + + void find_subgraph (unsigned node_idx, hb_map_t& subgraph) + { + for (const auto& link : vertices_[node_idx].obj.all_links ()) + { + const unsigned *v; + if (subgraph.has (link.objidx, &v)) + { + subgraph.set (link.objidx, *v + 1); + continue; + } + subgraph.set (link.objidx, 1); + find_subgraph (link.objidx, subgraph); + } + } + + void find_subgraph (unsigned node_idx, hb_set_t& subgraph) + { + if (subgraph.has (node_idx)) return; + subgraph.add (node_idx); + for (const auto& link : vertices_[node_idx].obj.all_links ()) + find_subgraph (link.objidx, subgraph); + } + + /* + * duplicates all nodes in the subgraph reachable from node_idx. Does not re-assign + * links. index_map is updated with mappings from old id to new id. If a duplication has already + * been performed for a given index, then it will be skipped. + */ + void duplicate_subgraph (unsigned node_idx, hb_map_t& index_map) + { + if (index_map.has (node_idx)) + return; + + index_map.set (node_idx, duplicate (node_idx)); + for (const auto& l : object (node_idx).all_links ()) { + duplicate_subgraph (l.objidx, index_map); + } + } + + /* + * Creates a copy of node_idx and returns it's new index. + */ + unsigned duplicate (unsigned node_idx) + { + positions_invalid = true; + distance_invalid = true; + + auto* clone = vertices_.push (); + auto& child = vertices_[node_idx]; + if (vertices_.in_error ()) { + return -1; + } + + clone->obj.head = child.obj.head; + clone->obj.tail = child.obj.tail; + clone->distance = child.distance; + clone->space = child.space; + clone->parents.reset (); + + unsigned clone_idx = vertices_.length - 2; + for (const auto& l : child.obj.real_links) + { + clone->obj.real_links.push (l); + vertices_[l.objidx].parents.push (clone_idx); + } + for (const auto& l : child.obj.virtual_links) + { + clone->obj.virtual_links.push (l); + vertices_[l.objidx].parents.push (clone_idx); + } + + check_success (!clone->obj.real_links.in_error ()); + check_success (!clone->obj.virtual_links.in_error ()); + + // The last object is the root of the graph, so swap back the root to the end. + // The root's obj idx does change, however since it's root nothing else refers to it. + // all other obj idx's will be unaffected. + hb_swap (vertices_[vertices_.length - 2], *clone); + + // Since the root moved, update the parents arrays of all children on the root. + for (const auto& l : root ().obj.all_links ()) + vertices_[l.objidx].remap_parent (root_idx () - 1, root_idx ()); + + return clone_idx; + } + + /* + * Creates a copy of child and re-assigns the link from + * parent to the clone. The copy is a shallow copy, objects + * linked from child are not duplicated. + */ + bool duplicate (unsigned parent_idx, unsigned child_idx) + { + update_parents (); + + unsigned links_to_child = 0; + for (const auto& l : vertices_[parent_idx].obj.all_links ()) + { + if (l.objidx == child_idx) links_to_child++; + } + + if (vertices_[child_idx].incoming_edges () <= links_to_child) + { + // Can't duplicate this node, doing so would orphan the original one as all remaining links + // to child are from parent. + DEBUG_MSG (SUBSET_REPACK, nullptr, " Not duplicating %d => %d", + parent_idx, child_idx); + return false; + } + + DEBUG_MSG (SUBSET_REPACK, nullptr, " Duplicating %d => %d", + parent_idx, child_idx); + + unsigned clone_idx = duplicate (child_idx); + if (clone_idx == (unsigned) -1) return false; + // duplicate shifts the root node idx, so if parent_idx was root update it. + if (parent_idx == clone_idx) parent_idx++; + + auto& parent = vertices_[parent_idx]; + for (auto& l : parent.obj.all_links_writer ()) + { + if (l.objidx != child_idx) + continue; + + reassign_link (l, parent_idx, clone_idx); + } + + return true; + } + + /* + * Raises the sorting priority of all children. + */ + bool raise_childrens_priority (unsigned parent_idx) + { + DEBUG_MSG (SUBSET_REPACK, nullptr, " Raising priority of all children of %d", + parent_idx); + // This operation doesn't change ordering until a sort is run, so no need + // to invalidate positions. It does not change graph structure so no need + // to update distances or edge counts. + auto& parent = vertices_[parent_idx].obj; + bool made_change = false; + for (auto& l : parent.all_links_writer ()) + made_change |= vertices_[l.objidx].raise_priority (); + return made_change; + } + + void print_orphaned_nodes () + { + if (!DEBUG_ENABLED(SUBSET_REPACK)) return; + + DEBUG_MSG (SUBSET_REPACK, nullptr, "Graph is not fully connected."); + parents_invalid = true; + update_parents(); + + for (unsigned i = 0; i < root_idx (); i++) + { + const auto& v = vertices_[i]; + if (!v.parents) + DEBUG_MSG (SUBSET_REPACK, nullptr, "Node %u is orphaned.", i); + } + } + + unsigned num_roots_for_space (unsigned space) const + { + return num_roots_for_space_[space]; + } + + unsigned next_space () const + { + return num_roots_for_space_.length; + } + + void move_to_new_space (const hb_set_t& indices) + { + num_roots_for_space_.push (0); + unsigned new_space = num_roots_for_space_.length - 1; + + for (unsigned index : indices) { + auto& node = vertices_[index]; + num_roots_for_space_[node.space] = num_roots_for_space_[node.space] - 1; + num_roots_for_space_[new_space] = num_roots_for_space_[new_space] + 1; + node.space = new_space; + distance_invalid = true; + positions_invalid = true; + } + } + + unsigned space_for (unsigned index, unsigned* root = nullptr) const + { + const auto& node = vertices_[index]; + if (node.space) + { + if (root != nullptr) + *root = index; + return node.space; + } + + if (!node.parents) + { + if (root) + *root = index; + return 0; + } + + return space_for (node.parents[0], root); + } + + void err_other_error () { this->successful = false; } + + size_t total_size_in_bytes () const { + size_t total_size = 0; + for (unsigned i = 0; i < vertices_.length; i++) { + size_t size = vertices_[i].obj.tail - vertices_[i].obj.head; + total_size += size; + } + return total_size; + } + + + private: + + /* + * Returns the numbers of incoming edges that are 32bits wide. + */ + unsigned wide_parents (unsigned node_idx, hb_set_t& parents) const + { + unsigned count = 0; + hb_set_t visited; + for (unsigned p : vertices_[node_idx].parents) + { + if (visited.has (p)) continue; + visited.add (p); + + // Only real links can be wide + for (const auto& l : vertices_[p].obj.real_links) + { + if (l.objidx == node_idx && l.width == 4 && !l.is_signed) + { + count++; + parents.add (p); + } + } + } + return count; + } + + bool check_success (bool success) + { return this->successful && (success || ((void) err_other_error (), false)); } + + public: + /* + * Creates a map from objid to # of incoming edges. + */ + void update_parents () + { + if (!parents_invalid) return; + + for (unsigned i = 0; i < vertices_.length; i++) + vertices_[i].parents.reset (); + + for (unsigned p = 0; p < vertices_.length; p++) + { + for (auto& l : vertices_[p].obj.all_links ()) + { + vertices_[l.objidx].parents.push (p); + } + } + + parents_invalid = false; + } + + /* + * compute the serialized start and end positions for each vertex. + */ + void update_positions () + { + if (!positions_invalid) return; + + unsigned current_pos = 0; + for (int i = root_idx (); i >= 0; i--) + { + auto& v = vertices_[i]; + v.start = current_pos; + current_pos += v.obj.tail - v.obj.head; + v.end = current_pos; + } + + positions_invalid = false; + } + + /* + * Finds the distance to each object in the graph + * from the initial node. + */ + void update_distances () + { + if (!distance_invalid) return; + + // Uses Dijkstra's algorithm to find all of the shortest distances. + // https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm + // + // Implementation Note: + // Since our priority queue doesn't support fast priority decreases + // we instead just add new entries into the queue when a priority changes. + // Redundant ones are filtered out later on by the visited set. + // According to https://www3.cs.stonybrook.edu/~rezaul/papers/TR-07-54.pdf + // for practical performance this is faster then using a more advanced queue + // (such as a fibonacci queue) with a fast decrease priority. + for (unsigned i = 0; i < vertices_.length; i++) + { + if (i == vertices_.length - 1) + vertices_[i].distance = 0; + else + vertices_[i].distance = hb_int_max (int64_t); + } + + hb_priority_queue_t queue; + queue.insert (0, vertices_.length - 1); + + hb_vector_t<bool> visited; + visited.resize (vertices_.length); + + while (!queue.in_error () && !queue.is_empty ()) + { + unsigned next_idx = queue.pop_minimum ().second; + if (visited[next_idx]) continue; + const auto& next = vertices_[next_idx]; + int64_t next_distance = vertices_[next_idx].distance; + visited[next_idx] = true; + + for (const auto& link : next.obj.all_links ()) + { + if (visited[link.objidx]) continue; + + const auto& child = vertices_[link.objidx].obj; + unsigned link_width = link.width ? link.width : 4; // treat virtual offsets as 32 bits wide + int64_t child_weight = (child.tail - child.head) + + ((int64_t) 1 << (link_width * 8)) * (vertices_[link.objidx].space + 1); + int64_t child_distance = next_distance + child_weight; + + if (child_distance < vertices_[link.objidx].distance) + { + vertices_[link.objidx].distance = child_distance; + queue.insert (child_distance, link.objidx); + } + } + } + + check_success (!queue.in_error ()); + if (!check_success (queue.is_empty ())) + { + print_orphaned_nodes (); + return; + } + + distance_invalid = false; + } + + private: + /* + * Updates a link in the graph to point to a different object. Corrects the + * parents vector on the previous and new child nodes. + */ + void reassign_link (hb_serialize_context_t::object_t::link_t& link, + unsigned parent_idx, + unsigned new_idx) + { + unsigned old_idx = link.objidx; + link.objidx = new_idx; + vertices_[old_idx].remove_parent (parent_idx); + vertices_[new_idx].parents.push (parent_idx); + } + + /* + * Updates all objidx's in all links using the provided mapping. Corrects incoming edge counts. + */ + template<typename Iterator, hb_requires (hb_is_iterator (Iterator))> + void remap_obj_indices (const hb_map_t& id_map, + Iterator subgraph, + bool only_wide = false) + { + if (!id_map) return; + for (unsigned i : subgraph) + { + for (auto& link : vertices_[i].obj.all_links_writer ()) + { + const unsigned *v; + if (!id_map.has (link.objidx, &v)) continue; + if (only_wide && !(link.width == 4 && !link.is_signed)) continue; + + reassign_link (link, i, *v); + } + } + } + + /* + * Updates all objidx's in all links using the provided mapping. + */ + void remap_all_obj_indices (const hb_vector_t<unsigned>& id_map, + hb_vector_t<vertex_t>* sorted_graph) const + { + for (unsigned i = 0; i < sorted_graph->length; i++) + { + (*sorted_graph)[i].remap_parents (id_map); + for (auto& link : (*sorted_graph)[i].obj.all_links_writer ()) + { + link.objidx = id_map[link.objidx]; + } + } + } + + /* + * Finds all nodes in targets that are reachable from start_idx, nodes in visited will be skipped. + * For this search the graph is treated as being undirected. + * + * Connected targets will be added to connected and removed from targets. All visited nodes + * will be added to visited. + */ + void find_connected_nodes (unsigned start_idx, + hb_set_t& targets, + hb_set_t& visited, + hb_set_t& connected) + { + if (unlikely (!check_success (!visited.in_error ()))) return; + if (visited.has (start_idx)) return; + visited.add (start_idx); + + if (targets.has (start_idx)) + { + targets.del (start_idx); + connected.add (start_idx); + } + + const auto& v = vertices_[start_idx]; + + // Graph is treated as undirected so search children and parents of start_idx + for (const auto& l : v.obj.all_links ()) + find_connected_nodes (l.objidx, targets, visited, connected); + + for (unsigned p : v.parents) + find_connected_nodes (p, targets, visited, connected); + } + + public: + // TODO(garretrieger): make private, will need to move most of offset overflow code into graph. + hb_vector_t<vertex_t> vertices_; + hb_vector_t<vertex_t> vertices_scratch_; + private: + bool parents_invalid; + bool distance_invalid; + bool positions_invalid; + bool successful; + hb_vector_t<unsigned> num_roots_for_space_; +}; + +} + +#endif // GRAPH_GRAPH_HH diff --git a/thirdparty/harfbuzz/src/graph/serialize.hh b/thirdparty/harfbuzz/src/graph/serialize.hh new file mode 100644 index 0000000000..ecc6cc5aea --- /dev/null +++ b/thirdparty/harfbuzz/src/graph/serialize.hh @@ -0,0 +1,249 @@ +/* + * Copyright © 2022 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): Garret Rieger + */ + +#ifndef GRAPH_SERIALIZE_HH +#define GRAPH_SERIALIZE_HH + +namespace graph { + +struct overflow_record_t +{ + unsigned parent; + unsigned child; +}; + +inline +int64_t compute_offset ( + const graph_t& graph, + unsigned parent_idx, + const hb_serialize_context_t::object_t::link_t& link) +{ + const auto& parent = graph.vertices_[parent_idx]; + const auto& child = graph.vertices_[link.objidx]; + int64_t offset = 0; + switch ((hb_serialize_context_t::whence_t) link.whence) { + case hb_serialize_context_t::whence_t::Head: + offset = child.start - parent.start; break; + case hb_serialize_context_t::whence_t::Tail: + offset = child.start - parent.end; break; + case hb_serialize_context_t::whence_t::Absolute: + offset = child.start; break; + } + + assert (offset >= link.bias); + offset -= link.bias; + return offset; +} + +inline +bool is_valid_offset (int64_t offset, + const hb_serialize_context_t::object_t::link_t& link) +{ + if (unlikely (!link.width)) + // Virtual links can't overflow. + return link.is_signed || offset >= 0; + + if (link.is_signed) + { + if (link.width == 4) + return offset >= -((int64_t) 1 << 31) && offset < ((int64_t) 1 << 31); + else + return offset >= -(1 << 15) && offset < (1 << 15); + } + else + { + if (link.width == 4) + return offset >= 0 && offset < ((int64_t) 1 << 32); + else if (link.width == 3) + return offset >= 0 && offset < ((int32_t) 1 << 24); + else + return offset >= 0 && offset < (1 << 16); + } +} + +/* + * Will any offsets overflow on graph when it's serialized? + */ +inline bool +will_overflow (graph_t& graph, + hb_vector_t<overflow_record_t>* overflows = nullptr) +{ + if (overflows) overflows->resize (0); + graph.update_positions (); + + const auto& vertices = graph.vertices_; + for (int parent_idx = vertices.length - 1; parent_idx >= 0; parent_idx--) + { + // Don't need to check virtual links for overflow + for (const auto& link : vertices[parent_idx].obj.real_links) + { + int64_t offset = compute_offset (graph, parent_idx, link); + if (is_valid_offset (offset, link)) + continue; + + if (!overflows) return true; + + overflow_record_t r; + r.parent = parent_idx; + r.child = link.objidx; + overflows->push (r); + } + } + + if (!overflows) return false; + return overflows->length; +} + +inline +void print_overflows (graph_t& graph, + const hb_vector_t<overflow_record_t>& overflows) +{ + if (!DEBUG_ENABLED(SUBSET_REPACK)) return; + + graph.update_parents (); + int limit = 10; + for (const auto& o : overflows) + { + if (!limit--) break; + const auto& parent = graph.vertices_[o.parent]; + const auto& child = graph.vertices_[o.child]; + DEBUG_MSG (SUBSET_REPACK, nullptr, + " overflow from " + "%4d (%4d in, %4d out, space %2d) => " + "%4d (%4d in, %4d out, space %2d)", + o.parent, + parent.incoming_edges (), + parent.obj.real_links.length + parent.obj.virtual_links.length, + graph.space_for (o.parent), + o.child, + child.incoming_edges (), + child.obj.real_links.length + child.obj.virtual_links.length, + graph.space_for (o.child)); + } + if (overflows.length > 10) { + DEBUG_MSG (SUBSET_REPACK, nullptr, " ... plus %d more overflows.", overflows.length - 10); + } +} + +template <typename O> inline void +serialize_link_of_type (const hb_serialize_context_t::object_t::link_t& link, + char* head, + hb_serialize_context_t* c) +{ + OT::Offset<O>* offset = reinterpret_cast<OT::Offset<O>*> (head + link.position); + *offset = 0; + c->add_link (*offset, + // serializer has an extra nil object at the start of the + // object array. So all id's are +1 of what our id's are. + link.objidx + 1, + (hb_serialize_context_t::whence_t) link.whence, + link.bias); +} + +inline +void serialize_link (const hb_serialize_context_t::object_t::link_t& link, + char* head, + hb_serialize_context_t* c) +{ + switch (link.width) + { + case 0: + // Virtual links aren't serialized. + return; + case 4: + if (link.is_signed) + { + serialize_link_of_type<OT::HBINT32> (link, head, c); + } else { + serialize_link_of_type<OT::HBUINT32> (link, head, c); + } + return; + case 2: + if (link.is_signed) + { + serialize_link_of_type<OT::HBINT16> (link, head, c); + } else { + serialize_link_of_type<OT::HBUINT16> (link, head, c); + } + return; + case 3: + serialize_link_of_type<OT::HBUINT24> (link, head, c); + return; + default: + // Unexpected link width. + assert (0); + } +} + +/* + * serialize graph into the provided serialization buffer. + */ +inline hb_blob_t* serialize (const graph_t& graph) +{ + hb_vector_t<char> buffer; + size_t size = graph.total_size_in_bytes (); + if (!buffer.alloc (size)) { + DEBUG_MSG (SUBSET_REPACK, nullptr, "Unable to allocate output buffer."); + return nullptr; + } + hb_serialize_context_t c((void *) buffer, size); + + c.start_serialize<void> (); + const auto& vertices = graph.vertices_; + for (unsigned i = 0; i < vertices.length; i++) { + c.push (); + + size_t size = vertices[i].obj.tail - vertices[i].obj.head; + char* start = c.allocate_size <char> (size); + if (!start) { + DEBUG_MSG (SUBSET_REPACK, nullptr, "Buffer out of space."); + return nullptr; + } + + memcpy (start, vertices[i].obj.head, size); + + // Only real links needs to be serialized. + for (const auto& link : vertices[i].obj.real_links) + serialize_link (link, start, &c); + + // All duplications are already encoded in the graph, so don't + // enable sharing during packing. + c.pop_pack (false); + } + c.end_serialize (); + + if (c.in_error ()) { + DEBUG_MSG (SUBSET_REPACK, nullptr, "Error during serialization. Err flag: %d", + c.errors); + return nullptr; + } + + return c.copy_blob (); +} + +} // namespace graph + +#endif // GRAPH_SERIALIZE_HH diff --git a/thirdparty/harfbuzz/src/hb-aat-layout-kerx-table.hh b/thirdparty/harfbuzz/src/hb-aat-layout-kerx-table.hh index 0354b47d5a..6a24c90c31 100644 --- a/thirdparty/harfbuzz/src/hb-aat-layout-kerx-table.hh +++ b/thirdparty/harfbuzz/src/hb-aat-layout-kerx-table.hh @@ -287,7 +287,7 @@ struct KerxSubTableFormat1 * in the 'kern' table example. */ if (v == -0x8000) { - o.attach_type() = ATTACH_TYPE_NONE; + o.attach_type() = OT::Layout::GPOS_impl::ATTACH_TYPE_NONE; o.attach_chain() = 0; o.y_offset = 0; } @@ -310,7 +310,7 @@ struct KerxSubTableFormat1 /* CoreText doesn't do crossStream kerning in vertical. We do. */ if (v == -0x8000) { - o.attach_type() = ATTACH_TYPE_NONE; + o.attach_type() = OT::Layout::GPOS_impl::ATTACH_TYPE_NONE; o.attach_chain() = 0; o.x_offset = 0; } @@ -567,7 +567,7 @@ struct KerxSubTableFormat4 } break; } - o.attach_type() = ATTACH_TYPE_MARK; + o.attach_type() = OT::Layout::GPOS_impl::ATTACH_TYPE_MARK; o.attach_chain() = (int) mark - (int) buffer->idx; buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT; } @@ -901,7 +901,7 @@ struct KerxTable unsigned int count = c->buffer->len; for (unsigned int i = 0; i < count; i++) { - pos[i].attach_type() = ATTACH_TYPE_CURSIVE; + pos[i].attach_type() = OT::Layout::GPOS_impl::ATTACH_TYPE_CURSIVE; pos[i].attach_chain() = HB_DIRECTION_IS_FORWARD (c->buffer->props.direction) ? -1 : +1; /* We intentionally don't set HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT, * since there needs to be a non-zero attachment for post-positioning to diff --git a/thirdparty/harfbuzz/src/hb-aat-layout-morx-table.hh b/thirdparty/harfbuzz/src/hb-aat-layout-morx-table.hh index 2f99510925..3d053cb13e 100644 --- a/thirdparty/harfbuzz/src/hb-aat-layout-morx-table.hh +++ b/thirdparty/harfbuzz/src/hb-aat-layout-morx-table.hh @@ -123,7 +123,7 @@ struct RearrangementSubtable bool reverse_l = 3 == (m >> 4); bool reverse_r = 3 == (m & 0x0F); - if (end - start >= l + r) + if (end - start >= l + r && end-start <= HB_MAX_CONTEXT_LENGTH) { buffer->merge_clusters (start, hb_min (buffer->idx + 1, buffer->len)); buffer->merge_clusters (start, end); @@ -1038,12 +1038,12 @@ struct Chain goto skip; if (reverse) - _hb_ot_layout_reverse_graphemes (c->buffer); + c->buffer->reverse (); subtable->apply (c); if (reverse) - _hb_ot_layout_reverse_graphemes (c->buffer); + c->buffer->reverse (); (void) c->buffer->message (c->font, "end chainsubtable %d", c->lookup_index); diff --git a/thirdparty/harfbuzz/src/hb-algs.hh b/thirdparty/harfbuzz/src/hb-algs.hh index c40a55cd1f..f1633d886a 100644 --- a/thirdparty/harfbuzz/src/hb-algs.hh +++ b/thirdparty/harfbuzz/src/hb-algs.hh @@ -59,7 +59,7 @@ static inline constexpr T operator | (T l, T r) { return T ((unsigned) l | (unsigned) r); } \ static inline constexpr T operator & (T l, T r) { return T ((unsigned) l & (unsigned) r); } \ static inline constexpr T operator ^ (T l, T r) { return T ((unsigned) l ^ (unsigned) r); } \ - static inline constexpr T operator ~ (T r) { return T (~(unsigned int) r); } \ + static inline constexpr unsigned operator ~ (T r) { return (~(unsigned) r); } \ static inline T& operator |= (T &l, T r) { l = l | r; return l; } \ static inline T& operator &= (T& l, T r) { l = l & r; return l; } \ static inline T& operator ^= (T& l, T r) { l = l ^ r; return l; } \ @@ -150,10 +150,26 @@ struct BEInt<Type, 4> uint8_t ((V >> 16) & 0xFF), uint8_t ((V >> 8) & 0xFF), uint8_t ((V ) & 0xFF)} {} - constexpr operator Type () const { return (v[0] << 24) - + (v[1] << 16) - + (v[2] << 8) - + (v[3] ); } + + struct __attribute__((packed)) packed_uint32_t { uint32_t v; }; + constexpr operator Type () const { +#if ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) && \ + defined(__BYTE_ORDER) && \ + (__BYTE_ORDER == __LITTLE_ENDIAN || __BYTE_ORDER == __BIG_ENDIAN) + /* Spoon-feed the compiler a big-endian integer with alignment 1. + * https://github.com/harfbuzz/harfbuzz/pull/1398 */ +#if __BYTE_ORDER == __LITTLE_ENDIAN + return __builtin_bswap32 (((packed_uint32_t *) this)->v); +#else /* __BYTE_ORDER == __BIG_ENDIAN */ + return ((packed_uint32_t *) this)->v; +#endif +#else + return (v[0] << 24) + + (v[1] << 16) + + (v[2] << 8) + + (v[3] ); +#endif + } private: uint8_t v[4]; }; @@ -211,31 +227,26 @@ struct } HB_FUNCOBJ (hb_bool); -template <typename T> -static inline -T hb_coerce (const T v) { return v; } -template <typename T, typename V, - hb_enable_if (!hb_is_same (hb_decay<T>, hb_decay<V>) && std::is_pointer<V>::value)> -static inline -T hb_coerce (const V v) { return *v; } - struct { private: template <typename T> constexpr auto - impl (const T& v, hb_priority<2>) const HB_RETURN (uint32_t, hb_deref (v).hash ()) + impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, hb_deref (v).hash ()) - template <typename T> constexpr auto - impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, std::hash<hb_decay<decltype (hb_deref (v))>>{} (hb_deref (v))) + template <typename T> constexpr uint32_t + impl (const hb::shared_ptr<T>& v, hb_priority<1>) const + { + return v.get () ? v.get ()->hash () : 0; + } + template <typename T> constexpr uint32_t + impl (const hb::unique_ptr<T>& v, hb_priority<1>) const + { + return v.get () ? v.get ()->hash () : 0; + } - template <typename T, - hb_enable_if (std::is_integral<T>::value)> constexpr auto - impl (const T& v, hb_priority<0>) const HB_AUTO_RETURN - ( - /* Knuth's multiplicative method: */ - (uint32_t) v * 2654435761u - ) + template <typename T> constexpr auto + impl (const T& v, hb_priority<0>) const HB_RETURN (uint32_t, std::hash<hb_decay<decltype (hb_deref (v))>>{} (hb_deref (v))) public: @@ -846,6 +857,11 @@ hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3) { return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2) || hb_in_range (u, lo3, hi3); } +template <typename T> static inline bool +hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3, T lo4, T hi4) +{ + return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2) || hb_in_range (u, lo3, hi3) || hb_in_range (u, lo4, hi4); +} /* diff --git a/thirdparty/harfbuzz/src/hb-array.hh b/thirdparty/harfbuzz/src/hb-array.hh index 1d1476d7cd..5baeb6f7fe 100644 --- a/thirdparty/harfbuzz/src/hb-array.hh +++ b/thirdparty/harfbuzz/src/hb-array.hh @@ -56,7 +56,6 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&> hb_array_t& operator= (const hb_array_t&) = default; hb_array_t& operator= (hb_array_t&&) = default; - constexpr hb_array_t (std::nullptr_t) : hb_array_t () {} constexpr hb_array_t (Type *array_, unsigned int length_) : arrayZ (array_), length (length_) {} template <unsigned int length_> constexpr hb_array_t (Type (&array_)[length_]) : hb_array_t (array_, length_) {} @@ -314,7 +313,6 @@ struct hb_sorted_array_t : hb_sorted_array_t& operator= (const hb_sorted_array_t&) = default; hb_sorted_array_t& operator= (hb_sorted_array_t&&) = default; - constexpr hb_sorted_array_t (std::nullptr_t) : hb_sorted_array_t () {} constexpr hb_sorted_array_t (Type *array_, unsigned int length_) : hb_array_t<Type> (array_, length_) {} template <unsigned int length_> constexpr hb_sorted_array_t (Type (&array_)[length_]) : hb_array_t<Type> (array_) {} @@ -346,7 +344,7 @@ struct hb_sorted_array_t : unsigned int i; return bfind (x, &i) ? &this->arrayZ[i] : not_found; } - template <typename T> + template <typename T, typename ...Ts> const Type *bsearch (const T &x, const Type *not_found = nullptr) const { unsigned int i; @@ -384,15 +382,16 @@ struct hb_sorted_array_t : } return false; } - template <typename T> - bool bsearch_impl (const T &x, unsigned *pos) const + template <typename T, typename ...Ts> + bool bsearch_impl (const T &x, unsigned *pos, Ts... ds) const { return hb_bsearch_impl (pos, x, this->arrayZ, this->length, sizeof (Type), - _hb_cmp_method<T, Type>); + _hb_cmp_method<T, Type, Ts...>, + ds...); } }; template <typename T> inline hb_sorted_array_t<T> @@ -403,7 +402,7 @@ hb_sorted_array (T (&array_)[length_]) { return hb_sorted_array_t<T> (array_); } template <typename T> -bool hb_array_t<T>::operator == (const hb_array_t<T> &o) const +inline bool hb_array_t<T>::operator == (const hb_array_t<T> &o) const { if (o.length != this->length) return false; for (unsigned int i = 0; i < this->length; i++) { @@ -411,8 +410,18 @@ bool hb_array_t<T>::operator == (const hb_array_t<T> &o) const } return true; } - -/* TODO Specialize operator== for hb_bytes_t and hb_ubytes_t. */ +template <> +inline bool hb_array_t<const char>::operator == (const hb_array_t<const char> &o) const +{ + if (o.length != this->length) return false; + return 0 == hb_memcmp (arrayZ, o.arrayZ, length); +} +template <> +inline bool hb_array_t<const unsigned char>::operator == (const hb_array_t<const unsigned char> &o) const +{ + if (o.length != this->length) return false; + return 0 == hb_memcmp (arrayZ, o.arrayZ, length); +} template <> inline uint32_t hb_array_t<const char>::hash () const { @@ -421,7 +430,6 @@ inline uint32_t hb_array_t<const char>::hash () const { current = current * 31 + (uint32_t) (this->arrayZ[i] * 2654435761u); return current; } - template <> inline uint32_t hb_array_t<const unsigned char>::hash () const { uint32_t current = 0; diff --git a/thirdparty/harfbuzz/src/hb-bimap.hh b/thirdparty/harfbuzz/src/hb-bimap.hh index a9e1278de7..8e8c988716 100644 --- a/thirdparty/harfbuzz/src/hb-bimap.hh +++ b/thirdparty/harfbuzz/src/hb-bimap.hh @@ -39,6 +39,12 @@ struct hb_bimap_t back_map.reset (); } + void resize (unsigned pop) + { + forw_map.resize (pop); + back_map.resize (pop); + } + bool in_error () const { return forw_map.in_error () || back_map.in_error (); } void set (hb_codepoint_t lhs, hb_codepoint_t rhs) @@ -48,17 +54,18 @@ struct hb_bimap_t if (unlikely (rhs == HB_MAP_VALUE_INVALID)) { del (lhs); return; } forw_map.set (lhs, rhs); - if (in_error ()) return; + if (unlikely (in_error ())) return; back_map.set (rhs, lhs); - if (in_error ()) forw_map.del (lhs); + if (unlikely (in_error ())) forw_map.del (lhs); } hb_codepoint_t get (hb_codepoint_t lhs) const { return forw_map.get (lhs); } hb_codepoint_t backward (hb_codepoint_t rhs) const { return back_map.get (rhs); } hb_codepoint_t operator [] (hb_codepoint_t lhs) const { return get (lhs); } - bool has (hb_codepoint_t lhs, hb_codepoint_t *vp = nullptr) const { return forw_map.has (lhs, vp); } + bool has (hb_codepoint_t lhs) const { return forw_map.has (lhs); } + void del (hb_codepoint_t lhs) { @@ -72,7 +79,7 @@ struct hb_bimap_t back_map.clear (); } - bool is_empty () const { return get_population () == 0; } + bool is_empty () const { return forw_map.is_empty (); } unsigned int get_population () const { return forw_map.get_population (); } diff --git a/thirdparty/harfbuzz/src/hb-bit-page.hh b/thirdparty/harfbuzz/src/hb-bit-page.hh index 9759836654..cbe918ee40 100644 --- a/thirdparty/harfbuzz/src/hb-bit-page.hh +++ b/thirdparty/harfbuzz/src/hb-bit-page.hh @@ -40,11 +40,18 @@ struct hb_bit_page_t bool is_empty () const { - for (unsigned int i = 0; i < len (); i++) + for (unsigned i = 0; i < len (); i++) if (v[i]) return false; return true; } + uint32_t hash () const + { + uint32_t h = 0; + for (unsigned i = 0; i < len (); i++) + h = h * 31 + hb_hash (v[i]); + return h; + } void add (hb_codepoint_t g) { elt (g) |= mask (g); } void del (hb_codepoint_t g) { elt (g) &= ~mask (g); } diff --git a/thirdparty/harfbuzz/src/hb-bit-set-invertible.hh b/thirdparty/harfbuzz/src/hb-bit-set-invertible.hh index 4a4ce34053..27fb0732ea 100644 --- a/thirdparty/harfbuzz/src/hb-bit-set-invertible.hh +++ b/thirdparty/harfbuzz/src/hb-bit-set-invertible.hh @@ -38,10 +38,10 @@ struct hb_bit_set_invertible_t bool inverted = false; hb_bit_set_invertible_t () = default; - hb_bit_set_invertible_t (hb_bit_set_invertible_t& o) = default; - hb_bit_set_invertible_t (hb_bit_set_invertible_t&& o) = default; + hb_bit_set_invertible_t (const hb_bit_set_invertible_t& o) = default; + hb_bit_set_invertible_t (hb_bit_set_invertible_t&& other) : hb_bit_set_invertible_t () { hb_swap (*this, other); } hb_bit_set_invertible_t& operator= (const hb_bit_set_invertible_t& o) = default; - hb_bit_set_invertible_t& operator= (hb_bit_set_invertible_t&& o) = default; + hb_bit_set_invertible_t& operator= (hb_bit_set_invertible_t&& other) { hb_swap (*this, other); return *this; } friend void swap (hb_bit_set_invertible_t &a, hb_bit_set_invertible_t &b) { if (likely (!a.s.successful || !b.s.successful)) @@ -56,6 +56,7 @@ struct hb_bit_set_invertible_t bool in_error () const { return s.in_error (); } explicit operator bool () const { return !is_empty (); } + void alloc (unsigned sz) { s.alloc (sz); } void reset () { s.reset (); @@ -79,6 +80,8 @@ struct hb_bit_set_invertible_t next (&v); return v == INVALID; } + uint32_t hash () const { return s.hash () ^ (uint32_t) inverted; } + hb_codepoint_t get_min () const { hb_codepoint_t v = INVALID; @@ -97,7 +100,7 @@ struct hb_bit_set_invertible_t void add (hb_codepoint_t g) { unlikely (inverted) ? s.del (g) : s.add (g); } bool add_range (hb_codepoint_t a, hb_codepoint_t b) - { return unlikely (inverted) ? (s.del_range (a, b), true) : s.add_range (a, b); } + { return unlikely (inverted) ? ((void) s.del_range (a, b), true) : s.add_range (a, b); } template <typename T> void add_array (const T *array, unsigned int count, unsigned int stride=sizeof(T)) diff --git a/thirdparty/harfbuzz/src/hb-bit-set.hh b/thirdparty/harfbuzz/src/hb-bit-set.hh index fcaff9f3be..438fb66a2c 100644 --- a/thirdparty/harfbuzz/src/hb-bit-set.hh +++ b/thirdparty/harfbuzz/src/hb-bit-set.hh @@ -56,7 +56,7 @@ struct hb_bit_set_t { successful = true; population = 0; - last_page_lookup = 0; + last_page_lookup.set_relaxed (0); page_map.init (); pages.init (); } @@ -78,7 +78,7 @@ struct hb_bit_set_t bool successful = true; /* Allocations successful */ mutable unsigned int population = 0; - mutable unsigned int last_page_lookup = 0; + mutable hb_atomic_int_t last_page_lookup = 0; hb_sorted_vector_t<page_map_t> page_map; hb_vector_t<page_t> pages; @@ -97,6 +97,13 @@ struct hb_bit_set_t return true; } + void alloc (unsigned sz) + { + sz >>= (page_t::PAGE_BITS_LOG_2 - 1); + pages.alloc (sz); + page_map.alloc (sz); + } + void reset () { successful = true; @@ -119,6 +126,14 @@ struct hb_bit_set_t } explicit operator bool () const { return !is_empty (); } + uint32_t hash () const + { + uint32_t h = 0; + for (auto &map : page_map) + h = h * 31 + hb_hash (map.major) + hb_hash (pages[map.index]); + return h; + } + private: void dirty () { population = UINT_MAX; } public: @@ -341,15 +356,14 @@ struct hb_bit_set_t return; population = other.population; - /* TODO switch to vector operator =. */ - hb_memcpy ((void *) pages, (const void *) other.pages, count * pages.item_size); - hb_memcpy ((void *) page_map, (const void *) other.page_map, count * page_map.item_size); + page_map = other.page_map; + pages = other.pages; } bool is_equal (const hb_bit_set_t &other) const { if (has_population () && other.has_population () && - get_population () != other.get_population ()) + population != other.population) return false; unsigned int na = pages.length; @@ -377,7 +391,7 @@ struct hb_bit_set_t bool is_subset (const hb_bit_set_t &larger_set) const { if (has_population () && larger_set.has_population () && - get_population () != larger_set.get_population ()) + population != larger_set.population) return false; uint32_t spi = 0; @@ -593,7 +607,7 @@ struct hb_bit_set_t const auto* page_map_array = page_map.arrayZ; unsigned int major = get_major (*codepoint); - unsigned int i = last_page_lookup; + unsigned int i = last_page_lookup.get_relaxed (); if (unlikely (i >= page_map.length || page_map_array[i].major != major)) { @@ -611,7 +625,7 @@ struct hb_bit_set_t if (pages_array[current.index].next (codepoint)) { *codepoint += current.major * page_t::PAGE_BITS; - last_page_lookup = i; + last_page_lookup.set_relaxed (i); return true; } i++; @@ -624,11 +638,11 @@ struct hb_bit_set_t if (m != INVALID) { *codepoint = current.major * page_t::PAGE_BITS + m; - last_page_lookup = i; + last_page_lookup.set_relaxed (i); return true; } } - last_page_lookup = 0; + last_page_lookup.set_relaxed (0); *codepoint = INVALID; return false; } @@ -711,7 +725,7 @@ struct hb_bit_set_t { const auto* page_map_array = page_map.arrayZ; unsigned int major = get_major (codepoint); - unsigned int i = last_page_lookup; + unsigned int i = last_page_lookup.get_relaxed (); if (unlikely (i >= page_map.length || page_map_array[i].major != major)) { page_map.bfind (major, &i, HB_NOT_FOUND_STORE_CLOSEST); @@ -752,7 +766,7 @@ struct hb_bit_set_t { const auto* page_map_array = page_map.arrayZ; unsigned int major = get_major (codepoint); - unsigned int i = last_page_lookup; + unsigned int i = last_page_lookup.get_relaxed (); if (unlikely (i >= page_map.length || page_map_array[i].major != major)) { page_map.bfind(major, &i, HB_NOT_FOUND_STORE_CLOSEST); @@ -874,8 +888,20 @@ struct hb_bit_set_t page_t *page_for (hb_codepoint_t g, bool insert = false) { - page_map_t map = {get_major (g), pages.length}; - unsigned int i; + unsigned major = get_major (g); + + /* The extra page_map length is necessary; can't just rely on vector here, + * since the next check would be tricked because a null page also has + * major==0, which we can't distinguish from an actualy major==0 page... */ + unsigned i = last_page_lookup.get_relaxed (); + if (likely (i < page_map.length)) + { + auto &cached_page = page_map.arrayZ[i]; + if (cached_page.major == major) + return &pages[cached_page.index]; + } + + page_map_t map = {major, pages.length}; if (!page_map.bfind (map, &i, HB_NOT_FOUND_STORE_CLOSEST)) { if (!insert) @@ -890,15 +916,31 @@ struct hb_bit_set_t (page_map.length - 1 - i) * page_map.item_size); page_map[i] = map; } + + last_page_lookup.set_relaxed (i); return &pages[page_map[i].index]; } const page_t *page_for (hb_codepoint_t g) const { - page_map_t key = {get_major (g)}; - const page_map_t *found = page_map.bsearch (key); - if (found) - return &pages[found->index]; - return nullptr; + unsigned major = get_major (g); + + /* The extra page_map length is necessary; can't just rely on vector here, + * since the next check would be tricked because a null page also has + * major==0, which we can't distinguish from an actualy major==0 page... */ + unsigned i = last_page_lookup.get_relaxed (); + if (likely (i < page_map.length)) + { + auto &cached_page = page_map.arrayZ[i]; + if (cached_page.major == major) + return &pages[cached_page.index]; + } + + page_map_t key = {major}; + if (!page_map.bfind (key, &i)) + return nullptr; + + last_page_lookup.set_relaxed (i); + return &pages[page_map[i].index]; } page_t &page_at (unsigned int i) { return pages[page_map[i].index]; } const page_t &page_at (unsigned int i) const { return pages[page_map[i].index]; } diff --git a/thirdparty/harfbuzz/src/hb-blob.cc b/thirdparty/harfbuzz/src/hb-blob.cc index f120002d17..b561a9374e 100644 --- a/thirdparty/harfbuzz/src/hb-blob.cc +++ b/thirdparty/harfbuzz/src/hb-blob.cc @@ -369,7 +369,7 @@ hb_blob_get_length (hb_blob_t *blob) * * Fetches the data from a blob. * - * Returns: (transfer none) (array length=length): the byte data of @blob. + * Returns: (nullable) (transfer none) (array length=length): the byte data of @blob. * * Since: 0.9.2 **/ @@ -572,7 +572,7 @@ _open_resource_fork (const char *file_name, hb_mapped_file_t *file) strncpy (rsrc_name, file_name, name_len); strncpy (rsrc_name + name_len, _PATH_RSRCFORKSPEC, - sizeof (_PATH_RSRCFORKSPEC) - 1); + sizeof (_PATH_RSRCFORKSPEC)); int fd = open (rsrc_name, O_RDONLY | O_BINARY, 0); hb_free (rsrc_name); @@ -631,7 +631,7 @@ hb_blob_create_from_file_or_fail (const char *file_name) Allison Lortie permission but changed a lot to suit our need. */ #if defined(HAVE_MMAP) && !defined(HB_NO_MMAP) hb_mapped_file_t *file = (hb_mapped_file_t *) hb_calloc (1, sizeof (hb_mapped_file_t)); - if (unlikely (!file)) return hb_blob_get_empty (); + if (unlikely (!file)) return nullptr; int fd = open (file_name, O_RDONLY | O_BINARY, 0); if (unlikely (fd == -1)) goto fail_without_close; @@ -671,7 +671,7 @@ fail_without_close: #elif defined(_WIN32) && !defined(HB_NO_MMAP) hb_mapped_file_t *file = (hb_mapped_file_t *) hb_calloc (1, sizeof (hb_mapped_file_t)); - if (unlikely (!file)) return hb_blob_get_empty (); + if (unlikely (!file)) return nullptr; HANDLE fd; unsigned int size = strlen (file_name) + 1; diff --git a/thirdparty/harfbuzz/src/hb-buffer-serialize.cc b/thirdparty/harfbuzz/src/hb-buffer-serialize.cc index 6539b89640..3f619a113e 100644 --- a/thirdparty/harfbuzz/src/hb-buffer-serialize.cc +++ b/thirdparty/harfbuzz/src/hb-buffer-serialize.cc @@ -31,7 +31,7 @@ #include "hb-buffer.hh" -static const char *serialize_formats[] = { +static const char *_hb_buffer_serialize_formats[] = { "text", "json", nullptr @@ -50,7 +50,7 @@ static const char *serialize_formats[] = { const char ** hb_buffer_serialize_list_formats () { - return serialize_formats; + return _hb_buffer_serialize_formats; } /** @@ -91,8 +91,8 @@ 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]; + case HB_BUFFER_SERIALIZE_FORMAT_TEXT: return _hb_buffer_serialize_formats[0]; + case HB_BUFFER_SERIALIZE_FORMAT_JSON: return _hb_buffer_serialize_formats[1]; default: case HB_BUFFER_SERIALIZE_FORMAT_INVALID: return nullptr; } @@ -400,9 +400,9 @@ _hb_buffer_serialize_unicode_text (hb_buffer_t *buffer, * @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) (optional): if not %NULL, will be set to the number of byes written into @buf. + * @buf_consumed: (out) (optional): if not %NULL, will be set to the number of bytes written into @buf. * @font: (nullable): the #hb_font_t used to shape this buffer, needed to - * read glyph names and extents. If %NULL, and empty font will be used. + * read glyph names and extents. If %NULL, an 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. @@ -514,7 +514,7 @@ hb_buffer_serialize_glyphs (hb_buffer_t *buffer, * @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) (optional): if not %NULL, will be set to the number of byes written into @buf. + * @buf_consumed: (out) (optional): if not %NULL, will be set to the number of bytes written into @buf. * @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. @@ -637,9 +637,9 @@ _hb_buffer_serialize_invalid (hb_buffer_t *buffer, * @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) (optional): if not %NULL, will be set to the number of byes written into @buf. + * @buf_consumed: (out) (optional): if not %NULL, will be set to the number of bytes written into @buf. * @font: (nullable): the #hb_font_t used to shape this buffer, needed to - * read glyph names and extents. If %NULL, and empty font will be used. + * read glyph names and extents. If %NULL, an 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. diff --git a/thirdparty/harfbuzz/src/hb-buffer-verify.cc b/thirdparty/harfbuzz/src/hb-buffer-verify.cc index dea2c11c35..5453e1ca94 100644 --- a/thirdparty/harfbuzz/src/hb-buffer-verify.cc +++ b/thirdparty/harfbuzz/src/hb-buffer-verify.cc @@ -102,9 +102,9 @@ buffer_verify_unsafe_to_break (hb_buffer_t *buffer, /* Check that breaking up shaping at safe-to-break is indeed safe. */ hb_buffer_t *fragment = hb_buffer_create_similar (buffer); - hb_buffer_set_flags (fragment, hb_buffer_get_flags (fragment) & ~HB_BUFFER_FLAG_VERIFY); + hb_buffer_set_flags (fragment, (hb_buffer_flags_t (hb_buffer_get_flags (fragment) & ~HB_BUFFER_FLAG_VERIFY))); hb_buffer_t *reconstruction = hb_buffer_create_similar (buffer); - hb_buffer_set_flags (reconstruction, hb_buffer_get_flags (reconstruction) & ~HB_BUFFER_FLAG_VERIFY); + hb_buffer_set_flags (reconstruction, (hb_buffer_flags_t (hb_buffer_get_flags (reconstruction) & ~HB_BUFFER_FLAG_VERIFY))); unsigned int num_glyphs; hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, &num_glyphs); @@ -169,6 +169,12 @@ buffer_verify_unsafe_to_break (hb_buffer_t *buffer, hb_buffer_destroy (fragment); return false; } + else if (!fragment->successful || fragment->shaping_failed) + { + hb_buffer_destroy (reconstruction); + hb_buffer_destroy (fragment); + return true; + } hb_buffer_append (reconstruction, fragment, 0, -1); start = end; @@ -238,10 +244,10 @@ buffer_verify_unsafe_to_concat (hb_buffer_t *buffer, hb_buffer_t *fragments[2] {hb_buffer_create_similar (buffer), hb_buffer_create_similar (buffer)}; - hb_buffer_set_flags (fragments[0], hb_buffer_get_flags (fragments[0]) & ~HB_BUFFER_FLAG_VERIFY); - hb_buffer_set_flags (fragments[1], hb_buffer_get_flags (fragments[1]) & ~HB_BUFFER_FLAG_VERIFY); + hb_buffer_set_flags (fragments[0], (hb_buffer_flags_t (hb_buffer_get_flags (fragments[0]) & ~HB_BUFFER_FLAG_VERIFY))); + hb_buffer_set_flags (fragments[1], (hb_buffer_flags_t (hb_buffer_get_flags (fragments[1]) & ~HB_BUFFER_FLAG_VERIFY))); hb_buffer_t *reconstruction = hb_buffer_create_similar (buffer); - hb_buffer_set_flags (reconstruction, hb_buffer_get_flags (reconstruction) & ~HB_BUFFER_FLAG_VERIFY); + hb_buffer_set_flags (reconstruction, (hb_buffer_flags_t (hb_buffer_get_flags (reconstruction) & ~HB_BUFFER_FLAG_VERIFY))); hb_segment_properties_t props; hb_buffer_get_segment_properties (buffer, &props); hb_buffer_set_segment_properties (fragments[0], &props); @@ -317,12 +323,22 @@ buffer_verify_unsafe_to_concat (hb_buffer_t *buffer, ret = false; goto out; } + else if (!fragments[0]->successful || fragments[0]->shaping_failed) + { + ret = true; + goto out; + } if (!hb_shape_full (font, fragments[1], features, num_features, shapers)) { buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "shaping failed while shaping fragment."); ret = false; goto out; } + else if (!fragments[1]->successful || fragments[1]->shaping_failed) + { + ret = true; + goto out; + } if (!forward) { @@ -402,6 +418,7 @@ hb_buffer_t::verify (hb_buffer_t *text_buffer, ret = false; if (!ret) { +#ifndef HB_NO_BUFFER_SERIALIZE unsigned len = text_buffer->len; hb_vector_t<char> bytes; if (likely (bytes.resize (len * 10 + 16))) @@ -414,6 +431,7 @@ hb_buffer_t::verify (hb_buffer_t *text_buffer, HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS); buffer_verify_error (this, font, BUFFER_VERIFY_ERROR "text was: %s.", bytes.arrayZ); } +#endif } return ret; } diff --git a/thirdparty/harfbuzz/src/hb-buffer.cc b/thirdparty/harfbuzz/src/hb-buffer.cc index 6a9ee3ccc8..2272ecf09b 100644 --- a/thirdparty/harfbuzz/src/hb-buffer.cc +++ b/thirdparty/harfbuzz/src/hb-buffer.cc @@ -81,8 +81,8 @@ hb_segment_properties_equal (const hb_segment_properties_t *a, unsigned int hb_segment_properties_hash (const hb_segment_properties_t *p) { - return (unsigned int) p->direction ^ - (unsigned int) p->script ^ + return ((unsigned int) p->direction * 31 + + (unsigned int) p->script) * 31 + (intptr_t) (p->language); } @@ -289,6 +289,7 @@ hb_buffer_t::clear () props = default_props; successful = true; + shaping_failed = false; have_output = false; have_positions = false; @@ -310,6 +311,7 @@ hb_buffer_t::enter () { deallocate_var_all (); serial = 0; + shaping_failed = false; scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT; if (likely (!hb_unsigned_mul_overflows (len, HB_BUFFER_MAX_LEN_FACTOR))) { @@ -329,6 +331,7 @@ hb_buffer_t::leave () max_ops = HB_BUFFER_MAX_OPS_DEFAULT; deallocate_var_all (); serial = 0; + // Intentionally not reseting shaping_failed, such that it can be inspected. } @@ -542,7 +545,8 @@ hb_buffer_t::delete_glyph () /* The logic here is duplicated in hb_ot_hide_default_ignorables(). */ unsigned int cluster = info[idx].cluster; - if (idx + 1 < len && cluster == info[idx + 1].cluster) + if ((idx + 1 < len && cluster == info[idx + 1].cluster) || + (out_len && cluster == out_info[out_len - 1].cluster)) { /* Cluster survives; do nothing. */ goto done; @@ -623,6 +627,7 @@ DEFINE_NULL_INSTANCE (hb_buffer_t) = HB_SEGMENT_PROPERTIES_DEFAULT, false, /* successful */ + true, /* shaping_failed */ false, /* have_output */ true /* have_positions */ @@ -631,7 +636,7 @@ DEFINE_NULL_INSTANCE (hb_buffer_t) = /** - * hb_buffer_create: (Xconstructor) + * hb_buffer_create: * * Creates a new #hb_buffer_t with all properties to defaults. * @@ -834,7 +839,7 @@ hb_buffer_set_content_type (hb_buffer_t *buffer, * Since: 0.9.5 **/ hb_buffer_content_type_t -hb_buffer_get_content_type (hb_buffer_t *buffer) +hb_buffer_get_content_type (const hb_buffer_t *buffer) { return buffer->content_type; } @@ -876,7 +881,7 @@ hb_buffer_set_unicode_funcs (hb_buffer_t *buffer, * Since: 0.9.2 **/ hb_unicode_funcs_t * -hb_buffer_get_unicode_funcs (hb_buffer_t *buffer) +hb_buffer_get_unicode_funcs (const hb_buffer_t *buffer) { return buffer->unicode; } @@ -919,7 +924,7 @@ hb_buffer_set_direction (hb_buffer_t *buffer, * Since: 0.9.2 **/ hb_direction_t -hb_buffer_get_direction (hb_buffer_t *buffer) +hb_buffer_get_direction (const hb_buffer_t *buffer) { return buffer->props.direction; } @@ -963,7 +968,7 @@ hb_buffer_set_script (hb_buffer_t *buffer, * Since: 0.9.2 **/ hb_script_t -hb_buffer_get_script (hb_buffer_t *buffer) +hb_buffer_get_script (const hb_buffer_t *buffer) { return buffer->props.script; } @@ -1007,7 +1012,7 @@ hb_buffer_set_language (hb_buffer_t *buffer, * Since: 0.9.2 **/ hb_language_t -hb_buffer_get_language (hb_buffer_t *buffer) +hb_buffer_get_language (const hb_buffer_t *buffer) { return buffer->props.language; } @@ -1043,7 +1048,7 @@ hb_buffer_set_segment_properties (hb_buffer_t *buffer, * Since: 0.9.7 **/ void -hb_buffer_get_segment_properties (hb_buffer_t *buffer, +hb_buffer_get_segment_properties (const hb_buffer_t *buffer, hb_segment_properties_t *props) { *props = buffer->props; @@ -1081,7 +1086,7 @@ hb_buffer_set_flags (hb_buffer_t *buffer, * Since: 0.9.7 **/ hb_buffer_flags_t -hb_buffer_get_flags (hb_buffer_t *buffer) +hb_buffer_get_flags (const hb_buffer_t *buffer) { return buffer->flags; } @@ -1120,7 +1125,7 @@ hb_buffer_set_cluster_level (hb_buffer_t *buffer, * Since: 0.9.42 **/ hb_buffer_cluster_level_t -hb_buffer_get_cluster_level (hb_buffer_t *buffer) +hb_buffer_get_cluster_level (const hb_buffer_t *buffer) { return buffer->cluster_level; } @@ -1161,7 +1166,7 @@ hb_buffer_set_replacement_codepoint (hb_buffer_t *buffer, * Since: 0.9.31 **/ hb_codepoint_t -hb_buffer_get_replacement_codepoint (hb_buffer_t *buffer) +hb_buffer_get_replacement_codepoint (const hb_buffer_t *buffer) { return buffer->replacement; } @@ -1201,7 +1206,7 @@ hb_buffer_set_invisible_glyph (hb_buffer_t *buffer, * Since: 2.0.0 **/ hb_codepoint_t -hb_buffer_get_invisible_glyph (hb_buffer_t *buffer) +hb_buffer_get_invisible_glyph (const hb_buffer_t *buffer) { return buffer->invisible; } @@ -1241,7 +1246,7 @@ hb_buffer_set_not_found_glyph (hb_buffer_t *buffer, * Since: 3.1.0 **/ hb_codepoint_t -hb_buffer_get_not_found_glyph (hb_buffer_t *buffer) +hb_buffer_get_not_found_glyph (const hb_buffer_t *buffer) { return buffer->not_found; } @@ -1381,7 +1386,7 @@ hb_buffer_set_length (hb_buffer_t *buffer, * Since: 0.9.2 **/ unsigned int -hb_buffer_get_length (hb_buffer_t *buffer) +hb_buffer_get_length (const hb_buffer_t *buffer) { return buffer->len; } diff --git a/thirdparty/harfbuzz/src/hb-buffer.h b/thirdparty/harfbuzz/src/hb-buffer.h index 14aaa5e1f5..22fb3496f2 100644 --- a/thirdparty/harfbuzz/src/hb-buffer.h +++ b/thirdparty/harfbuzz/src/hb-buffer.h @@ -289,7 +289,7 @@ hb_buffer_set_content_type (hb_buffer_t *buffer, hb_buffer_content_type_t content_type); HB_EXTERN hb_buffer_content_type_t -hb_buffer_get_content_type (hb_buffer_t *buffer); +hb_buffer_get_content_type (const hb_buffer_t *buffer); HB_EXTERN void @@ -297,21 +297,21 @@ hb_buffer_set_unicode_funcs (hb_buffer_t *buffer, hb_unicode_funcs_t *unicode_funcs); HB_EXTERN hb_unicode_funcs_t * -hb_buffer_get_unicode_funcs (hb_buffer_t *buffer); +hb_buffer_get_unicode_funcs (const hb_buffer_t *buffer); HB_EXTERN void hb_buffer_set_direction (hb_buffer_t *buffer, hb_direction_t direction); HB_EXTERN hb_direction_t -hb_buffer_get_direction (hb_buffer_t *buffer); +hb_buffer_get_direction (const hb_buffer_t *buffer); HB_EXTERN void hb_buffer_set_script (hb_buffer_t *buffer, hb_script_t script); HB_EXTERN hb_script_t -hb_buffer_get_script (hb_buffer_t *buffer); +hb_buffer_get_script (const hb_buffer_t *buffer); HB_EXTERN void hb_buffer_set_language (hb_buffer_t *buffer, @@ -319,14 +319,14 @@ hb_buffer_set_language (hb_buffer_t *buffer, HB_EXTERN hb_language_t -hb_buffer_get_language (hb_buffer_t *buffer); +hb_buffer_get_language (const hb_buffer_t *buffer); HB_EXTERN void hb_buffer_set_segment_properties (hb_buffer_t *buffer, const hb_segment_properties_t *props); HB_EXTERN void -hb_buffer_get_segment_properties (hb_buffer_t *buffer, +hb_buffer_get_segment_properties (const hb_buffer_t *buffer, hb_segment_properties_t *props); HB_EXTERN void @@ -373,6 +373,7 @@ hb_buffer_guess_segment_properties (hb_buffer_t *buffer); * flag indicating that the @HB_GLYPH_FLAG_UNSAFE_TO_CONCAT * glyph-flag should be produced by the shaper. By default * it will not be produced since it incurs a cost. Since: 4.0.0 + * @HB_BUFFER_FLAG_DEFINED: All currently defined flags: Since: 4.4.0 * * Flags for #hb_buffer_t. * @@ -386,7 +387,9 @@ typedef enum { /*< flags >*/ HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES = 0x00000008u, HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE = 0x00000010u, HB_BUFFER_FLAG_VERIFY = 0x00000020u, - HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT = 0x00000040u + HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT = 0x00000040u, + + HB_BUFFER_FLAG_DEFINED = 0x0000007Fu } hb_buffer_flags_t; HB_EXTERN void @@ -394,7 +397,7 @@ hb_buffer_set_flags (hb_buffer_t *buffer, hb_buffer_flags_t flags); HB_EXTERN hb_buffer_flags_t -hb_buffer_get_flags (hb_buffer_t *buffer); +hb_buffer_get_flags (const hb_buffer_t *buffer); /** * hb_buffer_cluster_level_t: @@ -436,7 +439,7 @@ hb_buffer_set_cluster_level (hb_buffer_t *buffer, hb_buffer_cluster_level_t cluster_level); HB_EXTERN hb_buffer_cluster_level_t -hb_buffer_get_cluster_level (hb_buffer_t *buffer); +hb_buffer_get_cluster_level (const hb_buffer_t *buffer); /** * HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT: @@ -453,21 +456,21 @@ hb_buffer_set_replacement_codepoint (hb_buffer_t *buffer, hb_codepoint_t replacement); HB_EXTERN hb_codepoint_t -hb_buffer_get_replacement_codepoint (hb_buffer_t *buffer); +hb_buffer_get_replacement_codepoint (const hb_buffer_t *buffer); HB_EXTERN void hb_buffer_set_invisible_glyph (hb_buffer_t *buffer, hb_codepoint_t invisible); HB_EXTERN hb_codepoint_t -hb_buffer_get_invisible_glyph (hb_buffer_t *buffer); +hb_buffer_get_invisible_glyph (const hb_buffer_t *buffer); HB_EXTERN void hb_buffer_set_not_found_glyph (hb_buffer_t *buffer, hb_codepoint_t not_found); HB_EXTERN hb_codepoint_t -hb_buffer_get_not_found_glyph (hb_buffer_t *buffer); +hb_buffer_get_not_found_glyph (const hb_buffer_t *buffer); /* @@ -549,7 +552,7 @@ hb_buffer_set_length (hb_buffer_t *buffer, unsigned int length); HB_EXTERN unsigned int -hb_buffer_get_length (hb_buffer_t *buffer); +hb_buffer_get_length (const hb_buffer_t *buffer); /* Getting glyphs out of the buffer */ @@ -583,6 +586,7 @@ hb_buffer_normalize_glyphs (hb_buffer_t *buffer); * @HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS: serialize glyph flags. Since: 1.5.0 * @HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES: do not serialize glyph advances, * glyph offsets will reflect absolute glyph positions. Since: 1.8.0 + * @HB_BUFFER_SERIALIZE_FLAG_DEFINED: All currently defined flags. Since: 4.4.0 * * Flags that control what glyph information are serialized in hb_buffer_serialize_glyphs(). * @@ -595,7 +599,9 @@ typedef enum { /*< flags >*/ HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES = 0x00000004u, HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS = 0x00000008u, HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS = 0x00000010u, - HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES = 0x00000020u + HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES = 0x00000020u, + + HB_BUFFER_SERIALIZE_FLAG_DEFINED = 0x0000003Fu } hb_buffer_serialize_flags_t; /** diff --git a/thirdparty/harfbuzz/src/hb-buffer.hh b/thirdparty/harfbuzz/src/hb-buffer.hh index bc6992905e..6ca78f28d4 100644 --- a/thirdparty/harfbuzz/src/hb-buffer.hh +++ b/thirdparty/harfbuzz/src/hb-buffer.hh @@ -57,6 +57,7 @@ static_assert ((sizeof (hb_glyph_info_t) == 20), ""); static_assert ((sizeof (hb_glyph_info_t) == sizeof (hb_glyph_position_t)), ""); +HB_MARK_AS_FLAG_T (hb_glyph_flags_t); HB_MARK_AS_FLAG_T (hb_buffer_flags_t); HB_MARK_AS_FLAG_T (hb_buffer_serialize_flags_t); HB_MARK_AS_FLAG_T (hb_buffer_diff_flags_t); @@ -69,12 +70,13 @@ enum hb_buffer_scratch_flags_t { HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT = 0x00000008u, HB_BUFFER_SCRATCH_FLAG_HAS_CGJ = 0x00000010u, HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS = 0x00000020u, + HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE = 0x00000040u, - /* Reserved for complex shapers' internal use. */ - HB_BUFFER_SCRATCH_FLAG_COMPLEX0 = 0x01000000u, - HB_BUFFER_SCRATCH_FLAG_COMPLEX1 = 0x02000000u, - HB_BUFFER_SCRATCH_FLAG_COMPLEX2 = 0x04000000u, - HB_BUFFER_SCRATCH_FLAG_COMPLEX3 = 0x08000000u, + /* Reserved for shapers' internal use. */ + HB_BUFFER_SCRATCH_FLAG_SHAPER0 = 0x01000000u, + HB_BUFFER_SCRATCH_FLAG_SHAPER1 = 0x02000000u, + HB_BUFFER_SCRATCH_FLAG_SHAPER2 = 0x04000000u, + HB_BUFFER_SCRATCH_FLAG_SHAPER3 = 0x08000000u, }; HB_MARK_AS_FLAG_T (hb_buffer_scratch_flags_t); @@ -106,6 +108,7 @@ struct hb_buffer_t hb_segment_properties_t props; /* Script, language, direction */ bool successful; /* Allocations successful */ + bool shaping_failed; /* Shaping failure */ bool have_output; /* Whether we have an output buffer going on */ bool have_positions; /* Whether we have positions */ @@ -130,9 +133,7 @@ struct hb_buffer_t * Managed by enter / leave */ -#ifndef HB_NDEBUG uint8_t allocated_var_bits; -#endif uint8_t serial; hb_buffer_scratch_flags_t scratch_flags; /* Have space-fallback, etc. */ unsigned int max_len; /* Maximum allowed len. */ @@ -161,38 +162,40 @@ struct hb_buffer_t void allocate_var (unsigned int start, unsigned int count) { -#ifndef HB_NDEBUG unsigned int end = start + count; assert (end <= 8); unsigned int bits = (1u<<end) - (1u<<start); assert (0 == (allocated_var_bits & bits)); allocated_var_bits |= bits; -#endif + } + bool try_allocate_var (unsigned int start, unsigned int count) + { + unsigned int end = start + count; + assert (end <= 8); + unsigned int bits = (1u<<end) - (1u<<start); + if (allocated_var_bits & bits) + return false; + allocated_var_bits |= bits; + return true; } void deallocate_var (unsigned int start, unsigned int count) { -#ifndef HB_NDEBUG unsigned int end = start + count; assert (end <= 8); unsigned int bits = (1u<<end) - (1u<<start); assert (bits == (allocated_var_bits & bits)); allocated_var_bits &= ~bits; -#endif } void assert_var (unsigned int start, unsigned int count) { -#ifndef HB_NDEBUG unsigned int end = start + count; assert (end <= 8); - unsigned int bits = (1u<<end) - (1u<<start); + HB_UNUSED unsigned int bits = (1u<<end) - (1u<<start); assert (bits == (allocated_var_bits & bits)); -#endif } void deallocate_var_all () { -#ifndef HB_NDEBUG allocated_var_bits = 0; -#endif } hb_glyph_info_t &cur (unsigned int i = 0) { return info[idx + i]; } @@ -549,7 +552,7 @@ struct hb_buffer_t #ifdef HB_NO_BUFFER_MESSAGE return true; #else - if (!messaging ()) + if (likely (!messaging ())) return true; message_depth++; @@ -619,9 +622,10 @@ DECLARE_NULL_INSTANCE (hb_buffer_t); #define HB_BUFFER_XALLOCATE_VAR(b, func, var) \ b->func (offsetof (hb_glyph_info_t, var) - offsetof(hb_glyph_info_t, var1), \ sizeof (b->info[0].var)) -#define HB_BUFFER_ALLOCATE_VAR(b, var) HB_BUFFER_XALLOCATE_VAR (b, allocate_var, var ()) -#define HB_BUFFER_DEALLOCATE_VAR(b, var) HB_BUFFER_XALLOCATE_VAR (b, deallocate_var, var ()) -#define HB_BUFFER_ASSERT_VAR(b, var) HB_BUFFER_XALLOCATE_VAR (b, assert_var, var ()) +#define HB_BUFFER_ALLOCATE_VAR(b, var) HB_BUFFER_XALLOCATE_VAR (b, allocate_var, var ()) +#define HB_BUFFER_TRY_ALLOCATE_VAR(b, var) HB_BUFFER_XALLOCATE_VAR (b, try_allocate_var, var ()) +#define HB_BUFFER_DEALLOCATE_VAR(b, var) HB_BUFFER_XALLOCATE_VAR (b, deallocate_var, var ()) +#define HB_BUFFER_ASSERT_VAR(b, var) HB_BUFFER_XALLOCATE_VAR (b, assert_var, var ()) #endif /* HB_BUFFER_HH */ diff --git a/thirdparty/harfbuzz/src/hb-cache.hh b/thirdparty/harfbuzz/src/hb-cache.hh index e617b75de9..d6b229ed65 100644 --- a/thirdparty/harfbuzz/src/hb-cache.hh +++ b/thirdparty/harfbuzz/src/hb-cache.hh @@ -32,7 +32,7 @@ /* Implements a lockfree cache for int->int functions. */ -template <unsigned int key_bits, unsigned int value_bits, unsigned int cache_bits> +template <unsigned int key_bits=16, unsigned int value_bits=8 + 32 - key_bits, unsigned int cache_bits=8> struct hb_cache_t { static_assert ((key_bits >= cache_bits), ""); diff --git a/thirdparty/harfbuzz/src/hb-cff-interp-common.hh b/thirdparty/harfbuzz/src/hb-cff-interp-common.hh index 641de0eff2..5c2cb060a4 100644 --- a/thirdparty/harfbuzz/src/hb-cff-interp-common.hh +++ b/thirdparty/harfbuzz/src/hb-cff-interp-common.hh @@ -248,6 +248,9 @@ struct number_t /* byte string */ struct UnsizedByteStr : UnsizedArrayOf <HBUINT8> { + hb_ubytes_t as_ubytes (unsigned l) const + { return hb_ubytes_t ((const unsigned char *) this, l); } + // encode 2-byte int (Dict/CharString) or 4-byte int (Dict) template <typename T, typename V> static bool serialize_int (hb_serialize_context_t *c, op_code_t intOp, V value) @@ -274,33 +277,10 @@ struct UnsizedByteStr : UnsizedArrayOf <HBUINT8> /* Defining null_size allows a Null object may be created. Should be safe because: * A descendent struct Dict uses a Null pointer to indicate a missing table, * checked before access. - * byte_str_t, a wrapper struct pairing a byte pointer along with its length, always - * checks the length before access. A Null pointer is used as the initial pointer - * along with zero length by the default ctor. */ DEFINE_SIZE_MIN(0); }; -/* Holder of a section of byte string within a CFFIndex entry */ -struct byte_str_t : hb_ubytes_t -{ - byte_str_t () - : hb_ubytes_t () {} - byte_str_t (const UnsizedByteStr& s, unsigned int l) - : hb_ubytes_t ((const unsigned char*)&s, l) {} - byte_str_t (const unsigned char *s, unsigned int l) - : hb_ubytes_t (s, l) {} - byte_str_t (const hb_ubytes_t &ub) /* conversion from hb_ubytes_t */ - : hb_ubytes_t (ub) {} - - /* sub-string */ - byte_str_t sub_str (unsigned int offset, unsigned int len_) const - { return byte_str_t (hb_ubytes_t::sub_array (offset, len_)); } - - bool check_limit (unsigned int offset, unsigned int count) const - { return (offset + count <= length); } -}; - /* A byte string associated with the current offset and an error condition */ struct byte_str_ref_t { @@ -308,17 +288,17 @@ struct byte_str_ref_t void init () { - str = byte_str_t (); + str = hb_ubytes_t (); offset = 0; error = false; } void fini () {} - byte_str_ref_t (const byte_str_t &str_, unsigned int offset_ = 0) + byte_str_ref_t (const hb_ubytes_t &str_, unsigned int offset_ = 0) : str (str_), offset (offset_), error (false) {} - void reset (const byte_str_t &str_, unsigned int offset_ = 0) + void reset (const hb_ubytes_t &str_, unsigned int offset_ = 0) { str = str_; offset = offset_; @@ -334,14 +314,14 @@ struct byte_str_ref_t return str[offset + i]; } - /* Conversion to byte_str_t */ - operator byte_str_t () const { return str.sub_str (offset, str.length - offset); } + /* Conversion to hb_ubytes_t */ + operator hb_ubytes_t () const { return str.sub_array (offset, str.length - offset); } - byte_str_t sub_str (unsigned int offset_, unsigned int len_) const - { return str.sub_str (offset_, len_); } + hb_ubytes_t sub_array (unsigned int offset_, unsigned int len_) const + { return str.sub_array (offset_, len_); } bool avail (unsigned int count=1) const - { return (!in_error () && str.check_limit (offset, count)); } + { return (!in_error () && offset + count <= str.length); } void inc (unsigned int count=1) { if (likely (!in_error () && (offset <= str.length) && (offset + count <= str.length))) @@ -358,44 +338,39 @@ struct byte_str_ref_t void set_error () { error = true; } bool in_error () const { return error; } - byte_str_t str; + hb_ubytes_t str; unsigned int offset; /* beginning of the sub-string within str */ protected: bool error; }; -typedef hb_vector_t<byte_str_t> byte_str_array_t; +using byte_str_array_t = hb_vector_t<hb_ubytes_t>; /* stack */ template <typename ELEM, int LIMIT> struct cff_stack_t { - void init () - { - error = false; - count = 0; - elements.init (); - elements.resize (kSizeLimit); - } - void fini () { elements.fini (); } - ELEM& operator [] (unsigned int i) { - if (unlikely (i >= count)) set_error (); + if (unlikely (i >= count)) + { + set_error (); + return Crap (ELEM); + } return elements[i]; } void push (const ELEM &v) { - if (likely (count < elements.length)) + if (likely (count < LIMIT)) elements[count++] = v; else set_error (); } ELEM &push () { - if (likely (count < elements.length)) + if (likely (count < LIMIT)) return elements[count++]; else { @@ -424,7 +399,7 @@ struct cff_stack_t const ELEM& peek () { - if (unlikely (count < 0)) + if (unlikely (count == 0)) { set_error (); return Null (ELEM); @@ -434,7 +409,7 @@ struct cff_stack_t void unpop () { - if (likely (count < elements.length)) + if (likely (count < LIMIT)) count++; else set_error (); @@ -442,18 +417,19 @@ struct cff_stack_t void clear () { count = 0; } - bool in_error () const { return (error || elements.in_error ()); } + bool in_error () const { return (error); } void set_error () { error = true; } unsigned int get_count () const { return count; } bool is_empty () const { return !count; } - static constexpr unsigned kSizeLimit = LIMIT; + hb_array_t<const ELEM> sub_array (unsigned start, unsigned length) const + { return hb_array_t<const ELEM> (elements).sub_array (start, length); } - protected: - bool error; - unsigned int count; - hb_vector_t<ELEM> elements; + private: + bool error = false; + unsigned int count = 0; + ELEM elements[LIMIT]; }; /* argument stack */ @@ -508,9 +484,6 @@ struct arg_stack_t : cff_stack_t<ARG, 513> return true; } - hb_array_t<const ARG> get_subarray (unsigned int start) const - { return S::elements.sub_array (start); } - private: typedef cff_stack_t<ARG, 513> S; }; @@ -518,8 +491,8 @@ struct arg_stack_t : cff_stack_t<ARG, 513> /* an operator prefixed by its operands in a byte string */ struct op_str_t { + hb_ubytes_t str; op_code_t op; - byte_str_t str; }; /* base of OP_SERIALIZER */ @@ -547,11 +520,16 @@ struct parsed_values_t } void fini () { values.fini (); } + void alloc (unsigned n) + { + values.alloc (n); + } + void add_op (op_code_t op, const byte_str_ref_t& str_ref = byte_str_ref_t ()) { VAL *val = values.push (); val->op = op; - val->str = str_ref.str.sub_str (opStart, str_ref.offset - opStart); + val->str = str_ref.str.sub_array (opStart, str_ref.offset - opStart); opStart = str_ref.offset; } @@ -559,14 +537,14 @@ struct parsed_values_t { VAL *val = values.push (v); val->op = op; - val->str = str_ref.sub_str ( opStart, str_ref.offset - opStart); + val->str = str_ref.sub_array ( opStart, str_ref.offset - opStart); opStart = str_ref.offset; } bool has_op (op_code_t op) const { - for (unsigned int i = 0; i < get_count (); i++) - if (get_value (i).op == op) return true; + for (const auto& v : values) + if (v.op == op) return true; return false; } @@ -581,14 +559,11 @@ struct parsed_values_t template <typename ARG=number_t> struct interp_env_t { - void init (const byte_str_t &str_) + interp_env_t () {} + interp_env_t (const hb_ubytes_t &str_) { str_ref.reset (str_); - argStack.init (); - error = false; } - void fini () { argStack.fini (); } - bool in_error () const { return error || str_ref.in_error () || argStack.in_error (); } @@ -622,10 +597,10 @@ struct interp_env_t arg_stack_t<ARG> argStack; protected: - bool error; + bool error = false; }; -typedef interp_env_t<> num_interp_env_t; +using num_interp_env_t = interp_env_t<>; template <typename ARG=number_t> struct opset_t @@ -668,11 +643,8 @@ struct opset_t template <typename ENV> struct interpreter_t { - ~interpreter_t() { fini (); } - - void fini () { env.fini (); } - - ENV env; + interpreter_t (ENV& env_) : env (env_) {} + ENV& env; }; } /* namespace CFF */ diff --git a/thirdparty/harfbuzz/src/hb-cff-interp-cs-common.hh b/thirdparty/harfbuzz/src/hb-cff-interp-cs-common.hh index ef299369b5..2983ae54a1 100644 --- a/thirdparty/harfbuzz/src/hb-cff-interp-cs-common.hh +++ b/thirdparty/harfbuzz/src/hb-cff-interp-cs-common.hh @@ -79,10 +79,10 @@ struct biased_subrs_t unsigned int get_count () const { return subrs ? subrs->count : 0; } unsigned int get_bias () const { return bias; } - byte_str_t operator [] (unsigned int index) const + hb_ubytes_t operator [] (unsigned int index) const { if (unlikely (!subrs || index >= subrs->count)) - return Null (byte_str_t); + return hb_ubytes_t (); else return (*subrs)[index]; } @@ -112,10 +112,9 @@ struct point_t template <typename ARG, typename SUBRS> struct cs_interp_env_t : interp_env_t<ARG> { - void init (const byte_str_t &str, const SUBRS *globalSubrs_, const SUBRS *localSubrs_) + cs_interp_env_t (const hb_ubytes_t &str, const SUBRS *globalSubrs_, const SUBRS *localSubrs_) : + interp_env_t<ARG> (str) { - interp_env_t<ARG>::init (str); - context.init (str, CSType_CharString); seen_moveto = true; seen_hintmask = false; @@ -123,15 +122,11 @@ struct cs_interp_env_t : interp_env_t<ARG> vstem_count = 0; hintmask_size = 0; pt.set_int (0, 0); - callStack.init (); globalSubrs.init (globalSubrs_); localSubrs.init (localSubrs_); } - void fini () + ~cs_interp_env_t () { - interp_env_t<ARG>::fini (); - - callStack.fini (); globalSubrs.fini (); localSubrs.fini (); } @@ -880,6 +875,8 @@ struct path_procs_t template <typename ENV, typename OPSET, typename PARAM> struct cs_interpreter_t : interpreter_t<ENV> { + cs_interpreter_t (ENV& env_) : interpreter_t<ENV> (env_) {} + bool interpret (PARAM& param) { SUPER::env.set_endchar (false); diff --git a/thirdparty/harfbuzz/src/hb-cff-interp-dict-common.hh b/thirdparty/harfbuzz/src/hb-cff-interp-dict-common.hh index a520ca3bce..79fe9b42c5 100644 --- a/thirdparty/harfbuzz/src/hb-cff-interp-dict-common.hh +++ b/thirdparty/harfbuzz/src/hb-cff-interp-dict-common.hh @@ -179,6 +179,8 @@ struct top_dict_opset_t : dict_opset_t template <typename OPSET, typename PARAM, typename ENV=num_interp_env_t> struct dict_interpreter_t : interpreter_t<ENV> { + dict_interpreter_t (ENV& env_) : interpreter_t<ENV> (env_) {} + bool interpret (PARAM& param) { param.init (); diff --git a/thirdparty/harfbuzz/src/hb-cff1-interp-cs.hh b/thirdparty/harfbuzz/src/hb-cff1-interp-cs.hh index 1c8762c172..b306c2ecc9 100644 --- a/thirdparty/harfbuzz/src/hb-cff1-interp-cs.hh +++ b/thirdparty/harfbuzz/src/hb-cff1-interp-cs.hh @@ -38,17 +38,15 @@ typedef biased_subrs_t<CFF1Subrs> cff1_biased_subrs_t; struct cff1_cs_interp_env_t : cs_interp_env_t<number_t, CFF1Subrs> { template <typename ACC> - void init (const byte_str_t &str, ACC &acc, unsigned int fd) + cff1_cs_interp_env_t (const hb_ubytes_t &str, ACC &acc, unsigned int fd) + : SUPER (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs) { - SUPER::init (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs); processed_width = false; has_width = false; arg_start = 0; in_seac = false; } - void fini () { SUPER::fini (); } - void set_width (bool has_width_) { if (likely (!processed_width && (SUPER::argStack.get_count () > 0))) @@ -154,7 +152,7 @@ struct cff1_cs_opset_t : cs_opset_t<number_t, OPSET, cff1_cs_interp_env_t, PARAM }; template <typename OPSET, typename PARAM> -struct cff1_cs_interpreter_t : cs_interpreter_t<cff1_cs_interp_env_t, OPSET, PARAM> {}; +using cff1_cs_interpreter_t = cs_interpreter_t<cff1_cs_interp_env_t, OPSET, PARAM>; } /* namespace CFF */ diff --git a/thirdparty/harfbuzz/src/hb-cff2-interp-cs.hh b/thirdparty/harfbuzz/src/hb-cff2-interp-cs.hh index 766183760e..d0b9e7b086 100644 --- a/thirdparty/harfbuzz/src/hb-cff2-interp-cs.hh +++ b/thirdparty/harfbuzz/src/hb-cff2-interp-cs.hh @@ -64,14 +64,14 @@ struct blend_arg_t : number_t typedef interp_env_t<blend_arg_t> BlendInterpEnv; typedef biased_subrs_t<CFF2Subrs> cff2_biased_subrs_t; -struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs> +template <typename ELEM> +struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs> { template <typename ACC> - void init (const byte_str_t &str, ACC &acc, unsigned int fd, - const int *coords_=nullptr, unsigned int num_coords_=0) + cff2_cs_interp_env_t (const hb_ubytes_t &str, ACC &acc, unsigned int fd, + const int *coords_=nullptr, unsigned int num_coords_=0) + : SUPER (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs) { - SUPER::init (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs); - coords = coords_; num_coords = num_coords_; varStore = acc.varStore; @@ -100,18 +100,14 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs> return OpCode_return; } - const blend_arg_t& eval_arg (unsigned int i) + const ELEM& eval_arg (unsigned int i) { - blend_arg_t &arg = argStack[i]; - blend_arg (arg); - return arg; + return SUPER::argStack[i]; } - const blend_arg_t& pop_arg () + const ELEM& pop_arg () { - blend_arg_t &arg = argStack.pop (); - blend_arg (arg); - return arg; + return SUPER::argStack.pop (); } void process_blend () @@ -122,7 +118,7 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs> if (do_blend) { if (unlikely (!scalars.resize (region_count))) - set_error (); + SUPER::set_error (); else varStore->varStore.get_region_scalars (get_ivs (), coords, num_coords, &scalars[0], region_count); @@ -133,10 +129,10 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs> void process_vsindex () { - unsigned int index = argStack.pop_uint (); + unsigned int index = SUPER::argStack.pop_uint (); if (unlikely (seen_vsindex () || seen_blend)) { - set_error (); + SUPER::set_error (); } else { @@ -151,22 +147,18 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs> void set_ivs (unsigned int ivs_) { ivs = ivs_; } bool seen_vsindex () const { return seen_vsindex_; } - protected: - void blend_arg (blend_arg_t &arg) + double blend_deltas (hb_array_t<const ELEM> deltas) const { - if (do_blend && arg.blending ()) + double v = 0; + if (do_blend) { - if (likely (scalars.length == arg.deltas.length)) + if (likely (scalars.length == deltas.length)) { - double v = arg.to_real (); for (unsigned int i = 0; i < scalars.length; i++) - { - v += (double)scalars[i] * arg.deltas[i].to_real (); - } - arg.set_real (v); - arg.deltas.resize (0); + v += (double) scalars[i] * deltas[i].to_real (); } } + return v; } protected: @@ -180,22 +172,24 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs> bool seen_vsindex_; bool seen_blend; - typedef cs_interp_env_t<blend_arg_t, CFF2Subrs> SUPER; + typedef cs_interp_env_t<ELEM, CFF2Subrs> SUPER; }; -template <typename OPSET, typename PARAM, typename PATH=path_procs_null_t<cff2_cs_interp_env_t, PARAM>> -struct cff2_cs_opset_t : cs_opset_t<blend_arg_t, OPSET, cff2_cs_interp_env_t, PARAM, PATH> +template <typename OPSET, typename PARAM, typename ELEM, typename PATH=path_procs_null_t<cff2_cs_interp_env_t<ELEM>, PARAM>> +struct cff2_cs_opset_t : cs_opset_t<ELEM, OPSET, cff2_cs_interp_env_t<ELEM>, PARAM, PATH> { - static void process_op (op_code_t op, cff2_cs_interp_env_t &env, PARAM& param) + static void process_op (op_code_t op, cff2_cs_interp_env_t<ELEM> &env, PARAM& param) { switch (op) { case OpCode_callsubr: case OpCode_callgsubr: /* a subroutine number shouldn't be a blended value */ +#if 0 if (unlikely (env.argStack.peek ().blending ())) { env.set_error (); break; } +#endif SUPER::process_op (op, env, param); break; @@ -204,11 +198,13 @@ struct cff2_cs_opset_t : cs_opset_t<blend_arg_t, OPSET, cff2_cs_interp_env_t, PA break; case OpCode_vsindexcs: +#if 0 if (unlikely (env.argStack.peek ().blending ())) { env.set_error (); break; } +#endif OPSET::process_vsindex (env, param); break; @@ -217,7 +213,26 @@ struct cff2_cs_opset_t : cs_opset_t<blend_arg_t, OPSET, cff2_cs_interp_env_t, PA } } - static void process_blend (cff2_cs_interp_env_t &env, PARAM& param) + template <typename T = ELEM, + hb_enable_if (hb_is_same (T, blend_arg_t))> + static void process_arg_blend (cff2_cs_interp_env_t<ELEM> &env, + ELEM &arg, + const hb_array_t<const ELEM> blends, + unsigned n, unsigned i) + { + arg.set_blends (n, i, blends.length, blends); + } + template <typename T = ELEM, + hb_enable_if (!hb_is_same (T, blend_arg_t))> + static void process_arg_blend (cff2_cs_interp_env_t<ELEM> &env, + ELEM &arg, + const hb_array_t<const ELEM> blends, + unsigned n, unsigned i) + { + arg.set_real (arg.to_real () + env.blend_deltas (blends)); + } + + static void process_blend (cff2_cs_interp_env_t<ELEM> &env, PARAM& param) { unsigned int n, k; @@ -234,26 +249,26 @@ struct cff2_cs_opset_t : cs_opset_t<blend_arg_t, OPSET, cff2_cs_interp_env_t, PA } for (unsigned int i = 0; i < n; i++) { - const hb_array_t<const blend_arg_t> blends = env.argStack.get_subarray (start + n + (i * k)); - env.argStack[start + i].set_blends (n, i, k, blends); + const hb_array_t<const ELEM> blends = env.argStack.sub_array (start + n + (i * k), k); + process_arg_blend (env, env.argStack[start + i], blends, n, i); } /* pop off blend values leaving default values now adorned with blend values */ env.argStack.pop (k * n); } - static void process_vsindex (cff2_cs_interp_env_t &env, PARAM& param) + static void process_vsindex (cff2_cs_interp_env_t<ELEM> &env, PARAM& param) { env.process_vsindex (); env.clear_args (); } private: - typedef cs_opset_t<blend_arg_t, OPSET, cff2_cs_interp_env_t, PARAM, PATH> SUPER; + typedef cs_opset_t<ELEM, OPSET, cff2_cs_interp_env_t<ELEM>, PARAM, PATH> SUPER; }; -template <typename OPSET, typename PARAM> -struct cff2_cs_interpreter_t : cs_interpreter_t<cff2_cs_interp_env_t, OPSET, PARAM> {}; +template <typename OPSET, typename PARAM, typename ELEM> +using cff2_cs_interpreter_t = cs_interpreter_t<cff2_cs_interp_env_t<ELEM>, OPSET, PARAM>; } /* namespace CFF */ diff --git a/thirdparty/harfbuzz/src/hb-common.cc b/thirdparty/harfbuzz/src/hb-common.cc index 41229b9183..7266d9b01f 100644 --- a/thirdparty/harfbuzz/src/hb-common.cc +++ b/thirdparty/harfbuzz/src/hb-common.cc @@ -160,7 +160,7 @@ hb_tag_to_string (hb_tag_t tag, char *buf) /* hb_direction_t */ -const char direction_strings[][4] = { +static const char direction_strings[][4] = { "ltr", "rtl", "ttb", diff --git a/thirdparty/harfbuzz/src/hb-config.hh b/thirdparty/harfbuzz/src/hb-config.hh index 4b46dea938..2578231d23 100644 --- a/thirdparty/harfbuzz/src/hb-config.hh +++ b/thirdparty/harfbuzz/src/hb-config.hh @@ -64,6 +64,7 @@ #define HB_NO_FACE_COLLECT_UNICODES #define HB_NO_GETENV #define HB_NO_HINTING +#define HB_NO_LANGUAGE_LONG #define HB_NO_LANGUAGE_PRIVATE_SUBTAG #define HB_NO_LAYOUT_FEATURE_PARAMS #define HB_NO_LAYOUT_COLLECT_GLYPHS @@ -145,10 +146,10 @@ #endif #ifdef HB_NO_OT_SHAPE_FALLBACK -#define HB_NO_OT_SHAPE_COMPLEX_ARABIC_FALLBACK -#define HB_NO_OT_SHAPE_COMPLEX_HEBREW_FALLBACK -#define HB_NO_OT_SHAPE_COMPLEX_THAI_FALLBACK -#define HB_NO_OT_SHAPE_COMPLEX_VOWEL_CONSTRAINTS +#define HB_NO_OT_SHAPER_ARABIC_FALLBACK +#define HB_NO_OT_SHAPER_HEBREW_FALLBACK +#define HB_NO_OT_SHAPER_THAI_FALLBACK +#define HB_NO_OT_SHAPER_VOWEL_CONSTRAINTS #endif #ifdef NDEBUG @@ -163,5 +164,9 @@ #endif #endif +#ifdef HB_OPTIMIZE_SIZE +#define HB_NO_OT_LAYOUT_LOOKUP_CACHE +#endif + #endif /* HB_CONFIG_HH */ diff --git a/thirdparty/harfbuzz/src/hb-coretext.cc b/thirdparty/harfbuzz/src/hb-coretext.cc index 6ccc1b0a2b..99b33c001e 100644 --- a/thirdparty/harfbuzz/src/hb-coretext.cc +++ b/thirdparty/harfbuzz/src/hb-coretext.cc @@ -332,7 +332,7 @@ _hb_coretext_shaper_font_data_create (hb_font_t *font) return nullptr; } - if (font->coords) + if (font->num_coords) { CFMutableDictionaryRef variations = CFDictionaryCreateMutable (kCFAllocatorDefault, @@ -379,37 +379,6 @@ _hb_coretext_shaper_font_data_destroy (hb_coretext_font_data_t *data) CFRelease ((CTFontRef) data); } -static const hb_coretext_font_data_t * -hb_coretext_font_data_sync (hb_font_t *font) -{ -retry: - const hb_coretext_font_data_t *data = font->data.coretext; - if (unlikely (!data)) return nullptr; - - if (fabs (CTFontGetSize ((CTFontRef) data) - (CGFloat) font->ptem) > (CGFloat) .5) - { - /* XXX-MT-bug - * Note that evaluating condition above can be dangerous if another thread - * got here first and destructed data. That's, as always, bad use pattern. - * If you modify the font (change font size), other threads must not be - * using it at the same time. However, since this check is delayed to - * when one actually tries to shape something, this is a XXX race condition - * (and the only one we have that I know of) right now. Ie. you modify the - * font size in one thread, then (supposedly safely) try to use it from two - * or more threads and BOOM! I'm not sure how to fix this. We want RCU. - */ - - /* Drop and recreate. */ - /* If someone dropped it in the mean time, throw it away and don't touch it. - * Otherwise, destruct it. */ - if (likely (font->data.coretext.cmpexch (const_cast<hb_coretext_font_data_t *> (data), nullptr))) - _hb_coretext_shaper_font_data_destroy (const_cast<hb_coretext_font_data_t *> (data)); - else - goto retry; - } - return font->data.coretext; -} - /** * hb_coretext_font_create: * @ct_font: The CTFontRef to work upon @@ -455,8 +424,8 @@ hb_coretext_font_create (CTFontRef ct_font) CTFontRef hb_coretext_font_get_ct_font (hb_font_t *font) { - const hb_coretext_font_data_t *data = hb_coretext_font_data_sync (font); - return data ? (CTFontRef) data : nullptr; + CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext; + return ct_font ? (CTFontRef) ct_font : nullptr; } @@ -516,7 +485,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan, { hb_face_t *face = font->face; CGFontRef cg_font = (CGFontRef) (const void *) face->data.coretext; - CTFontRef ct_font = (CTFontRef) hb_coretext_font_data_sync (font); + CTFontRef ct_font = (CTFontRef) (const void *) font->data.coretext; CGFloat ct_font_size = CTFontGetSize (ct_font); CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size; @@ -1106,7 +1075,8 @@ resize_and_retry: advance = positions[j + 1].x - positions[j].x; else /* last glyph */ advance = run_advance - (positions[j].x - positions[0].x); - info->mask = round (advance * x_mult); + /* int cast necessary to pass through negative values. */ + info->mask = (int) round (advance * x_mult); info->var1.i32 = x_offset; info->var2.i32 = round (positions[j].y * y_mult); info++; @@ -1122,7 +1092,8 @@ resize_and_retry: advance = positions[j + 1].y - positions[j].y; else /* last glyph */ advance = run_advance - (positions[j].y - positions[0].y); - info->mask = round (advance * y_mult); + /* int cast necessary to pass through negative values. */ + info->mask = (int) round (advance * y_mult); info->var1.i32 = round (positions[j].x * x_mult); info->var2.i32 = y_offset; info++; @@ -1151,7 +1122,7 @@ resize_and_retry: pos->x_offset = info->var1.i32; pos->y_offset = info->var2.i32; - info++, pos++; + info++; pos++; } else for (unsigned int i = 0; i < count; i++) @@ -1160,7 +1131,7 @@ resize_and_retry: pos->x_offset = info->var1.i32; pos->y_offset = info->var2.i32; - info++, pos++; + info++; pos++; } /* Fix up clusters so that we never return out-of-order indices; @@ -1173,7 +1144,8 @@ resize_and_retry: * This does *not* mean we'll form the same clusters as Uniscribe * or the native OT backend, only that the cluster indices will be * monotonic in the output buffer. */ - if (count > 1 && (status_or & kCTRunStatusNonMonotonic)) + if (count > 1 && (status_or & kCTRunStatusNonMonotonic) && + buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_CHARACTERS) { hb_glyph_info_t *info = buffer->info; if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) @@ -1197,6 +1169,10 @@ resize_and_retry: } } + /* TODO: Sometimes the above positioning code generates negative + * advance values. Fix them up. Example, with NotoNastaliqUrdu + * font and sequence ابهد. */ + buffer->clear_glyph_flags (); buffer->unsafe_to_break (); diff --git a/thirdparty/harfbuzz/src/hb-cplusplus.hh b/thirdparty/harfbuzz/src/hb-cplusplus.hh new file mode 100644 index 0000000000..86d0452080 --- /dev/null +++ b/thirdparty/harfbuzz/src/hb-cplusplus.hh @@ -0,0 +1,192 @@ +/* + * Copyright © 2022 Behdad Esfahbod + * + * 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_CPLUSPLUS_HH +#define HB_CPLUSPLUS_HH + +#include "hb.h" + +HB_BEGIN_DECLS +HB_END_DECLS + +#ifdef __cplusplus + +#include <functional> +#include <utility> + +#if 0 +#if !(__cplusplus >= 201103L) +#error "HarfBuzz C++ helpers require C++11" +#endif +#endif + +namespace hb { + + +template <typename T> +struct vtable; + +template <typename T> +struct shared_ptr +{ + using element_type = T; + + using v = vtable<T>; + + explicit shared_ptr (T *p = nullptr) : p (p) {} + shared_ptr (const shared_ptr &o) : p (v::reference (o.p)) {} + shared_ptr (shared_ptr &&o) : p (o.p) { o.p = nullptr; } + shared_ptr& operator = (const shared_ptr &o) { if (p != o.p) { destroy (); p = o.p; reference (); } return *this; } + shared_ptr& operator = (shared_ptr &&o) { v::destroy (p); p = o.p; o.p = nullptr; return *this; } + ~shared_ptr () { v::destroy (p); p = nullptr; } + + T* get() const { return p; } + + void swap (shared_ptr &o) { std::swap (p, o.p); } + friend void swap (shared_ptr &a, shared_ptr &b) { std::swap (a.p, b.p); } + + operator T * () const { return p; } + T& operator * () const { return *get (); } + T* operator -> () const { return get (); } + operator bool () { return p; } + bool operator == (const shared_ptr &o) { return p == o.p; } + bool operator != (const shared_ptr &o) { return p != o.p; } + + static T* get_empty() { return v::get_empty (); } + T* reference() { return v::reference (p); } + void destroy() { v::destroy (p); } + void set_user_data (hb_user_data_key_t *key, + void *value, + hb_destroy_func_t destroy, + hb_bool_t replace) { v::set_user_data (p, key, value, destroy, replace); } + void * get_user_data (hb_user_data_key_t *key) { return v::get_user_data (p, key); } + + private: + T *p; +}; + +template<typename T> struct is_shared_ptr : std::false_type {}; +template<typename T> struct is_shared_ptr<shared_ptr<T>> : std::true_type {}; + +template <typename T> +struct unique_ptr +{ + using element_type = T; + + using v = vtable<T>; + + explicit unique_ptr (T *p = nullptr) : p (p) {} + unique_ptr (const unique_ptr &o) = delete; + unique_ptr (unique_ptr &&o) : p (o.p) { o.p = nullptr; } + unique_ptr& operator = (const unique_ptr &o) = delete; + unique_ptr& operator = (unique_ptr &&o) { v::destroy (p); p = o.p; o.p = nullptr; return *this; } + ~unique_ptr () { v::destroy (p); p = nullptr; } + + T* get() const { return p; } + T* release () { T* v = p; p = nullptr; return v; } + + void swap (unique_ptr &o) { std::swap (p, o.p); } + friend void swap (unique_ptr &a, unique_ptr &b) { std::swap (a.p, b.p); } + + operator T * () const { return p; } + T& operator * () const { return *get (); } + T* operator -> () const { return get (); } + operator bool () { return p; } + + private: + T *p; +}; + +template<typename T> struct is_unique_ptr : std::false_type {}; +template<typename T> struct is_unique_ptr<unique_ptr<T>> : std::true_type {}; + +template <typename T, + T * (*_get_empty) (void), + T * (*_reference) (T *), + void (*_destroy) (T *), + hb_bool_t (*_set_user_data) (T *, + hb_user_data_key_t *, + void *, + hb_destroy_func_t, + hb_bool_t), + void * (*_get_user_data) (T *, + hb_user_data_key_t *)> +struct vtable_t +{ + static constexpr auto get_empty = _get_empty; + static constexpr auto reference = _reference; + static constexpr auto destroy = _destroy; + static constexpr auto set_user_data = _set_user_data; + static constexpr auto get_user_data = _get_user_data; +}; + +#define HB_DEFINE_VTABLE(name) \ + template<> \ + struct vtable<hb_##name##_t> \ + : vtable_t<hb_##name##_t, \ + &hb_##name##_get_empty, \ + &hb_##name##_reference, \ + &hb_##name##_destroy, \ + &hb_##name##_set_user_data, \ + &hb_##name##_get_user_data> {} + +HB_DEFINE_VTABLE (buffer); +HB_DEFINE_VTABLE (blob); +HB_DEFINE_VTABLE (face); +HB_DEFINE_VTABLE (font); +HB_DEFINE_VTABLE (font_funcs); +HB_DEFINE_VTABLE (map); +HB_DEFINE_VTABLE (set); +HB_DEFINE_VTABLE (shape_plan); +HB_DEFINE_VTABLE (unicode_funcs); + +#undef HB_DEFINE_VTABLE + + +} // namespace hb + +template<typename T> +struct std::hash<hb::shared_ptr<T>> +{ + std::size_t operator()(const hb::shared_ptr<T>& v) const noexcept + { + std::size_t h = std::hash<decltype (v.get ())>{}(v.get ()); + return h; + } +}; + +template<typename T> +struct std::hash<hb::unique_ptr<T>> +{ + std::size_t operator()(const hb::unique_ptr<T>& v) const noexcept + { + std::size_t h = std::hash<decltype (v.get ())>{}(v.get ()); + return h; + } +}; + + +#endif /* __cplusplus */ + +#endif /* HB_CPLUSPLUS_HH */ diff --git a/thirdparty/harfbuzz/src/hb-directwrite.cc b/thirdparty/harfbuzz/src/hb-directwrite.cc index f177ff31c0..ce04f5bab1 100644 --- a/thirdparty/harfbuzz/src/hb-directwrite.cc +++ b/thirdparty/harfbuzz/src/hb-directwrite.cc @@ -241,17 +241,12 @@ struct hb_directwrite_font_data_t {}; hb_directwrite_font_data_t * _hb_directwrite_shaper_font_data_create (hb_font_t *font) { - hb_directwrite_font_data_t *data = new hb_directwrite_font_data_t; - if (unlikely (!data)) - return nullptr; - - return data; + return (hb_directwrite_font_data_t *) HB_SHAPER_DATA_SUCCEEDED; } void _hb_directwrite_shaper_font_data_destroy (hb_directwrite_font_data_t *data) { - delete data; } diff --git a/thirdparty/harfbuzz/src/hb-draw.cc b/thirdparty/harfbuzz/src/hb-draw.cc index b31019b07e..fdc71102d6 100644 --- a/thirdparty/harfbuzz/src/hb-draw.cc +++ b/thirdparty/harfbuzz/src/hb-draw.cc @@ -56,12 +56,14 @@ hb_draw_quadratic_to_nil (hb_draw_funcs_t *dfuncs, void *draw_data, float to_x, float to_y, void *user_data HB_UNUSED) { +#define HB_ONE_THIRD 0.33333333f dfuncs->emit_cubic_to (draw_data, *st, - (st->current_x + 2.f * control_x) / 3.f, - (st->current_y + 2.f * control_y) / 3.f, - (to_x + 2.f * control_x) / 3.f, - (to_y + 2.f * control_y) / 3.f, + (st->current_x + 2.f * control_x) * HB_ONE_THIRD, + (st->current_y + 2.f * control_y) * HB_ONE_THIRD, + (to_x + 2.f * control_x) * HB_ONE_THIRD, + (to_y + 2.f * control_y) * HB_ONE_THIRD, to_x, to_y); +#undef HB_ONE_THIRD } static void @@ -89,25 +91,46 @@ hb_draw_funcs_set_##name##_func (hb_draw_funcs_t *dfuncs, \ if (hb_object_is_immutable (dfuncs)) \ return; \ \ - if (dfuncs->destroy.name) \ - dfuncs->destroy.name (dfuncs->user_data.name); \ - \ - if (func) { \ - dfuncs->func.name = func; \ - dfuncs->user_data.name = user_data; \ - dfuncs->destroy.name = destroy; \ - } else { \ - dfuncs->func.name = hb_draw_##name##_nil; \ - dfuncs->user_data.name = nullptr; \ - dfuncs->destroy.name = nullptr; \ - } \ + if (dfuncs->destroy && dfuncs->destroy->name) \ + dfuncs->destroy->name (!dfuncs->user_data ? nullptr : dfuncs->user_data->name); \ + \ + if (user_data && !dfuncs->user_data) \ + { \ + dfuncs->user_data = (decltype (dfuncs->user_data)) hb_calloc (1, sizeof (*dfuncs->user_data)); \ + if (unlikely (!dfuncs->user_data)) \ + goto fail; \ + } \ + if (destroy && !dfuncs->destroy) \ + { \ + dfuncs->destroy = (decltype (dfuncs->destroy)) hb_calloc (1, sizeof (*dfuncs->destroy)); \ + if (unlikely (!dfuncs->destroy)) \ + goto fail; \ + } \ + \ + if (func) { \ + dfuncs->func.name = func; \ + if (dfuncs->user_data) \ + dfuncs->user_data->name = user_data; \ + if (dfuncs->destroy) \ + dfuncs->destroy->name = destroy; \ + } else { \ + dfuncs->func.name = hb_draw_##name##_nil; \ + if (dfuncs->user_data) \ + dfuncs->user_data->name = nullptr; \ + if (dfuncs->destroy) \ + dfuncs->destroy->name = nullptr; \ + } \ + \ +fail: \ + if (destroy) \ + destroy (user_data); \ } HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS #undef HB_DRAW_FUNC_IMPLEMENT /** - * hb_draw_funcs_create: (Xconstructor) + * hb_draw_funcs_create: * * Creates a new draw callbacks object. * @@ -177,11 +200,13 @@ hb_draw_funcs_destroy (hb_draw_funcs_t *dfuncs) { if (!hb_object_destroy (dfuncs)) return; + if (dfuncs->destroy) + { #define HB_DRAW_FUNC_IMPLEMENT(name) \ - if (dfuncs->destroy.name) dfuncs->destroy.name (dfuncs->user_data.name); - HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS + if (dfuncs->destroy->name) dfuncs->destroy->name (!dfuncs->user_data ? nullptr : dfuncs->user_data->name); + HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS #undef HB_DRAW_FUNC_IMPLEMENT - + } hb_free (dfuncs); } diff --git a/thirdparty/harfbuzz/src/hb-draw.hh b/thirdparty/harfbuzz/src/hb-draw.hh index 28bc9218e1..768f51a875 100644 --- a/thirdparty/harfbuzz/src/hb-draw.hh +++ b/thirdparty/harfbuzz/src/hb-draw.hh @@ -54,31 +54,31 @@ struct hb_draw_funcs_t #define HB_DRAW_FUNC_IMPLEMENT(name) void *name; HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS #undef HB_DRAW_FUNC_IMPLEMENT - } user_data; + } *user_data; struct { #define HB_DRAW_FUNC_IMPLEMENT(name) hb_destroy_func_t name; HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS #undef HB_DRAW_FUNC_IMPLEMENT - } destroy; + } *destroy; void emit_move_to (void *draw_data, hb_draw_state_t &st, float to_x, float to_y) { func.move_to (this, draw_data, &st, to_x, to_y, - user_data.move_to); } + !user_data ? nullptr : user_data->move_to); } void emit_line_to (void *draw_data, hb_draw_state_t &st, float to_x, float to_y) { func.line_to (this, draw_data, &st, to_x, to_y, - user_data.line_to); } + !user_data ? nullptr : user_data->line_to); } void emit_quadratic_to (void *draw_data, hb_draw_state_t &st, float control_x, float control_y, float to_x, float to_y) { func.quadratic_to (this, draw_data, &st, control_x, control_y, to_x, to_y, - user_data.quadratic_to); } + !user_data ? nullptr : user_data->quadratic_to); } void emit_cubic_to (void *draw_data, hb_draw_state_t &st, float control1_x, float control1_y, float control2_x, float control2_y, @@ -87,10 +87,10 @@ struct hb_draw_funcs_t control1_x, control1_y, control2_x, control2_y, to_x, to_y, - user_data.cubic_to); } + !user_data ? nullptr : user_data->cubic_to); } void emit_close_path (void *draw_data, hb_draw_state_t &st) { func.close_path (this, draw_data, &st, - user_data.close_path); } + !user_data ? nullptr : user_data->close_path); } void move_to (void *draw_data, hb_draw_state_t &st, diff --git a/thirdparty/harfbuzz/src/hb-face.cc b/thirdparty/harfbuzz/src/hb-face.cc index 5365598636..7cdd6cb49f 100644 --- a/thirdparty/harfbuzz/src/hb-face.cc +++ b/thirdparty/harfbuzz/src/hb-face.cc @@ -190,7 +190,7 @@ _hb_face_for_data_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void } /** - * hb_face_create: (Xconstructor) + * hb_face_create: * @blob: #hb_blob_t to work upon * @index: The index of the face within @blob * @@ -342,7 +342,7 @@ hb_face_set_user_data (hb_face_t *face, * Since: 0.9.2 **/ void * -hb_face_get_user_data (const hb_face_t *face, +hb_face_get_user_data (hb_face_t *face, hb_user_data_key_t *key) { return hb_object_get_user_data (face, key); diff --git a/thirdparty/harfbuzz/src/hb-face.h b/thirdparty/harfbuzz/src/hb-face.h index 6ef2f8b886..3b7477a76c 100644 --- a/thirdparty/harfbuzz/src/hb-face.h +++ b/thirdparty/harfbuzz/src/hb-face.h @@ -96,7 +96,7 @@ hb_face_set_user_data (hb_face_t *face, hb_bool_t replace); HB_EXTERN void * -hb_face_get_user_data (const hb_face_t *face, +hb_face_get_user_data (hb_face_t *face, hb_user_data_key_t *key); HB_EXTERN void diff --git a/thirdparty/harfbuzz/src/hb-font.cc b/thirdparty/harfbuzz/src/hb-font.cc index db05f017a5..8c4fe863b6 100644 --- a/thirdparty/harfbuzz/src/hb-font.cc +++ b/thirdparty/harfbuzz/src/hb-font.cc @@ -636,16 +636,8 @@ DEFINE_NULL_INSTANCE (hb_font_funcs_t) = { HB_OBJECT_HEADER_STATIC, - { -#define HB_FONT_FUNC_IMPLEMENT(name) nullptr, - HB_FONT_FUNCS_IMPLEMENT_CALLBACKS -#undef HB_FONT_FUNC_IMPLEMENT - }, - { -#define HB_FONT_FUNC_IMPLEMENT(name) nullptr, - HB_FONT_FUNCS_IMPLEMENT_CALLBACKS -#undef HB_FONT_FUNC_IMPLEMENT - }, + nullptr, + nullptr, { { #define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_nil, @@ -658,16 +650,8 @@ DEFINE_NULL_INSTANCE (hb_font_funcs_t) = static const hb_font_funcs_t _hb_font_funcs_default = { HB_OBJECT_HEADER_STATIC, - { -#define HB_FONT_FUNC_IMPLEMENT(name) nullptr, - HB_FONT_FUNCS_IMPLEMENT_CALLBACKS -#undef HB_FONT_FUNC_IMPLEMENT - }, - { -#define HB_FONT_FUNC_IMPLEMENT(name) nullptr, - HB_FONT_FUNCS_IMPLEMENT_CALLBACKS -#undef HB_FONT_FUNC_IMPLEMENT - }, + nullptr, + nullptr, { { #define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_default, @@ -679,7 +663,7 @@ static const hb_font_funcs_t _hb_font_funcs_default = { /** - * hb_font_funcs_create: (Xconstructor) + * hb_font_funcs_create: * * Creates a new #hb_font_funcs_t structure of font functions. * @@ -746,10 +730,16 @@ hb_font_funcs_destroy (hb_font_funcs_t *ffuncs) { if (!hb_object_destroy (ffuncs)) return; -#define HB_FONT_FUNC_IMPLEMENT(name) if (ffuncs->destroy.name) \ - ffuncs->destroy.name (ffuncs->user_data.name); - HB_FONT_FUNCS_IMPLEMENT_CALLBACKS + if (ffuncs->destroy) + { +#define HB_FONT_FUNC_IMPLEMENT(name) if (ffuncs->destroy->name) \ + ffuncs->destroy->name (!ffuncs->user_data ? nullptr : ffuncs->user_data->name); + HB_FONT_FUNCS_IMPLEMENT_CALLBACKS #undef HB_FONT_FUNC_IMPLEMENT + } + + hb_free (ffuncs->destroy); + hb_free (ffuncs->user_data); hb_free (ffuncs); } @@ -841,24 +831,50 @@ hb_font_funcs_set_##name##_func (hb_font_funcs_t *ffuncs, \ hb_destroy_func_t destroy) \ { \ if (hb_object_is_immutable (ffuncs)) \ + goto fail; \ + \ + if (!func) \ { \ if (destroy) \ destroy (user_data); \ - return; \ + destroy = nullptr; \ + user_data = nullptr; \ } \ \ - if (ffuncs->destroy.name) \ - ffuncs->destroy.name (ffuncs->user_data.name); \ + if (ffuncs->destroy && ffuncs->destroy->name) \ + ffuncs->destroy->name (!ffuncs->user_data ? nullptr : ffuncs->user_data->name); \ + \ + if (user_data && !ffuncs->user_data) \ + { \ + ffuncs->user_data = (decltype (ffuncs->user_data)) hb_calloc (1, sizeof (*ffuncs->user_data)); \ + if (unlikely (!ffuncs->user_data)) \ + goto fail; \ + } \ + if (destroy && !ffuncs->destroy) \ + { \ + ffuncs->destroy = (decltype (ffuncs->destroy)) hb_calloc (1, sizeof (*ffuncs->destroy)); \ + if (unlikely (!ffuncs->destroy)) \ + goto fail; \ + } \ \ if (func) { \ ffuncs->get.f.name = func; \ - ffuncs->user_data.name = user_data; \ - ffuncs->destroy.name = destroy; \ + if (ffuncs->user_data) \ + ffuncs->user_data->name = user_data; \ + if (ffuncs->destroy) \ + ffuncs->destroy->name = destroy; \ } else { \ ffuncs->get.f.name = hb_font_get_##name##_default; \ - ffuncs->user_data.name = nullptr; \ - ffuncs->destroy.name = nullptr; \ + if (ffuncs->user_data) \ + ffuncs->user_data->name = nullptr; \ + if (ffuncs->destroy) \ + ffuncs->destroy->name = nullptr; \ } \ + return; \ + \ +fail: \ + if (destroy) \ + destroy (user_data); \ } HB_FONT_FUNCS_IMPLEMENT_CALLBACKS @@ -1623,6 +1639,9 @@ DEFINE_NULL_INSTANCE (hb_font_t) = { HB_OBJECT_HEADER_STATIC, + 0, /* serial */ + 0, /* serial_coords */ + nullptr, /* parent */ const_cast<hb_face_t *> (&_hb_Null_hb_face_t), @@ -1630,6 +1649,8 @@ DEFINE_NULL_INSTANCE (hb_font_t) = 1000, /* y_scale */ 0., /* slant */ 0., /* slant_xy; */ + 1.f, /* x_multf */ + 1.f, /* y_multf */ 1<<16, /* x_mult */ 1<<16, /* y_mult */ @@ -1662,14 +1683,15 @@ _hb_font_create (hb_face_t *face) font->face = hb_face_reference (face); font->klass = hb_font_funcs_get_empty (); font->data.init0 (font); - font->x_scale = font->y_scale = hb_face_get_upem (face); + font->x_scale = font->y_scale = face->get_upem (); + font->x_multf = font->y_multf = 1.f; font->x_mult = font->y_mult = 1 << 16; return font; } /** - * hb_font_create: (Xconstructor) + * hb_font_create: * @face: a face. * * Constructs a new font object from the specified face. @@ -1715,6 +1737,8 @@ _hb_font_adopt_var_coords (hb_font_t *font, font->coords = coords; font->design_coords = design_coords; font->num_coords = coords_length; + + font->mults_changed (); // Easiest to call this to drop cached data } /** @@ -1744,7 +1768,6 @@ hb_font_create_sub_font (hb_font_t *parent) font->x_scale = parent->x_scale; font->y_scale = parent->y_scale; font->slant = parent->slant; - font->mults_changed (); font->x_ppem = parent->x_ppem; font->y_ppem = parent->y_ppem; font->ptem = parent->ptem; @@ -1767,6 +1790,8 @@ hb_font_create_sub_font (hb_font_t *parent) } } + font->mults_changed (); + return font; } @@ -1852,6 +1877,9 @@ hb_font_set_user_data (hb_font_t *font, hb_destroy_func_t destroy /* May be NULL. */, hb_bool_t replace) { + if (!hb_object_is_immutable (font)) + font->serial++; + return hb_object_set_user_data (font, key, data, destroy, replace); } @@ -1911,6 +1939,45 @@ hb_font_is_immutable (hb_font_t *font) } /** + * hb_font_get_serial: + * @font: #hb_font_t to work upon + * + * Returns the internal serial number of the font. The serial + * number is increased every time a setting on the font is + * changed, using a setter function. + * + * Return value: serial number + * + * Since: 4.4.0. + **/ +unsigned int +hb_font_get_serial (hb_font_t *font) +{ + return font->serial; +} + +/** + * hb_font_changed: + * @font: #hb_font_t to work upon + * + * Notifies the @font that underlying font data has changed. + * This has the effect of increasing the serial as returned + * by hb_font_get_serial(), which invalidates internal caches. + * + * Since: 4.4.0. + **/ +void +hb_font_changed (hb_font_t *font) +{ + if (hb_object_is_immutable (font)) + return; + + font->serial++; + + font->mults_changed (); +} + +/** * hb_font_set_parent: * @font: #hb_font_t to work upon * @parent: The parent font object to assign @@ -1926,6 +1993,11 @@ hb_font_set_parent (hb_font_t *font, if (hb_object_is_immutable (font)) return; + if (parent == font->parent) + return; + + font->serial++; + if (!parent) parent = hb_font_get_empty (); @@ -1968,6 +2040,11 @@ hb_font_set_face (hb_font_t *font, if (hb_object_is_immutable (font)) return; + if (face == font->face) + return; + + font->serial++; + if (unlikely (!face)) face = hb_face_get_empty (); @@ -2022,6 +2099,8 @@ hb_font_set_funcs (hb_font_t *font, return; } + font->serial++; + if (font->destroy) font->destroy (font->user_data); @@ -2059,6 +2138,8 @@ hb_font_set_funcs_data (hb_font_t *font, return; } + font->serial++; + if (font->destroy) font->destroy (font->user_data); @@ -2085,6 +2166,11 @@ hb_font_set_scale (hb_font_t *font, if (hb_object_is_immutable (font)) return; + if (font->x_scale == x_scale && font->y_scale == y_scale) + return; + + font->serial++; + font->x_scale = x_scale; font->y_scale = y_scale; font->mults_changed (); @@ -2127,6 +2213,11 @@ hb_font_set_ppem (hb_font_t *font, if (hb_object_is_immutable (font)) return; + if (font->x_ppem == x_ppem && font->y_ppem == y_ppem) + return; + + font->serial++; + font->x_ppem = x_ppem; font->y_ppem = y_ppem; } @@ -2169,6 +2260,11 @@ hb_font_set_ptem (hb_font_t *font, if (hb_object_is_immutable (font)) return; + if (font->ptem == ptem) + return; + + font->serial++; + font->ptem = ptem; } @@ -2216,6 +2312,11 @@ hb_font_set_synthetic_slant (hb_font_t *font, float slant) if (hb_object_is_immutable (font)) return; + if (font->slant == slant) + return; + + font->serial++; + font->slant = slant; font->mults_changed (); } @@ -2263,6 +2364,8 @@ hb_font_set_variations (hb_font_t *font, if (hb_object_is_immutable (font)) return; + font->serial_coords = ++font->serial; + if (!variations_length) { hb_font_set_var_coords_normalized (font, nullptr, 0); @@ -2322,6 +2425,8 @@ hb_font_set_var_coords_design (hb_font_t *font, if (hb_object_is_immutable (font)) return; + font->serial_coords = ++font->serial; + int *normalized = coords_length ? (int *) hb_calloc (coords_length, sizeof (int)) : nullptr; float *design_coords = coords_length ? (float *) hb_calloc (coords_length, sizeof (float)) : nullptr; @@ -2355,6 +2460,8 @@ hb_font_set_var_named_instance (hb_font_t *font, if (hb_object_is_immutable (font)) return; + font->serial_coords = ++font->serial; + unsigned int coords_length = hb_ot_var_named_instance_get_design_coords (font->face, instance_index, nullptr, nullptr); float *coords = coords_length ? (float *) hb_calloc (coords_length, sizeof (float)) : nullptr; @@ -2391,6 +2498,8 @@ hb_font_set_var_coords_normalized (hb_font_t *font, if (hb_object_is_immutable (font)) return; + font->serial_coords = ++font->serial; + int *copy = coords_length ? (int *) hb_calloc (coords_length, sizeof (coords[0])) : nullptr; int *unmapped = coords_length ? (int *) hb_calloc (coords_length, sizeof (coords[0])) : nullptr; float *design_coords = coords_length ? (float *) hb_calloc (coords_length, sizeof (design_coords[0])) : nullptr; @@ -2596,12 +2705,14 @@ hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs, return; } + /* Since we pass it to two destroying functions. */ + trampoline_reference (&trampoline->closure); + hb_font_funcs_set_nominal_glyph_func (ffuncs, hb_font_get_nominal_glyph_trampoline, trampoline, trampoline_destroy); - trampoline_reference (&trampoline->closure); hb_font_funcs_set_variation_glyph_func (ffuncs, hb_font_get_variation_glyph_trampoline, trampoline, diff --git a/thirdparty/harfbuzz/src/hb-font.h b/thirdparty/harfbuzz/src/hb-font.h index 9548857535..ca6ecf7963 100644 --- a/thirdparty/harfbuzz/src/hb-font.h +++ b/thirdparty/harfbuzz/src/hb-font.h @@ -1002,6 +1002,12 @@ hb_font_make_immutable (hb_font_t *font); HB_EXTERN hb_bool_t hb_font_is_immutable (hb_font_t *font); +HB_EXTERN unsigned int +hb_font_get_serial (hb_font_t *font); + +HB_EXTERN void +hb_font_changed (hb_font_t *font); + HB_EXTERN void hb_font_set_parent (hb_font_t *font, hb_font_t *parent); diff --git a/thirdparty/harfbuzz/src/hb-font.hh b/thirdparty/harfbuzz/src/hb-font.hh index 70311b4a85..bb402e23eb 100644 --- a/thirdparty/harfbuzz/src/hb-font.hh +++ b/thirdparty/harfbuzz/src/hb-font.hh @@ -68,13 +68,13 @@ struct hb_font_funcs_t #define HB_FONT_FUNC_IMPLEMENT(name) void *name; HB_FONT_FUNCS_IMPLEMENT_CALLBACKS #undef HB_FONT_FUNC_IMPLEMENT - } user_data; + } *user_data; struct { #define HB_FONT_FUNC_IMPLEMENT(name) hb_destroy_func_t name; HB_FONT_FUNCS_IMPLEMENT_CALLBACKS #undef HB_FONT_FUNC_IMPLEMENT - } destroy; + } *destroy; /* Don't access these directly. Call font->get_*() instead. */ union get_t { @@ -104,6 +104,8 @@ DECLARE_NULL_INSTANCE (hb_font_funcs_t); struct hb_font_t { hb_object_header_t header; + unsigned int serial; + unsigned int serial_coords; hb_font_t *parent; hb_face_t *face; @@ -112,6 +114,8 @@ struct hb_font_t int32_t y_scale; float slant; float slant_xy; + float x_multf; + float y_multf; int64_t x_mult; int64_t y_mult; @@ -137,12 +141,12 @@ struct hb_font_t { return HB_DIRECTION_IS_VERTICAL(direction) ? y_mult : x_mult; } hb_position_t em_scale_x (int16_t v) { return em_mult (v, x_mult); } hb_position_t em_scale_y (int16_t v) { return em_mult (v, y_mult); } - hb_position_t em_scalef_x (float v) { return em_scalef (v, x_scale); } - hb_position_t em_scalef_y (float v) { return em_scalef (v, y_scale); } - float em_fscale_x (int16_t v) { return em_fscale (v, x_scale); } - float em_fscale_y (int16_t v) { return em_fscale (v, y_scale); } - float em_fscalef_x (float v) { return em_fscalef (v, x_scale); } - float em_fscalef_y (float v) { return em_fscalef (v, y_scale); } + hb_position_t em_scalef_x (float v) { return em_multf (v, x_multf); } + hb_position_t em_scalef_y (float v) { return em_multf (v, y_multf); } + float em_fscale_x (int16_t v) { return em_fmult (v, x_multf); } + float em_fscale_y (int16_t v) { return em_fmult (v, y_multf); } + float em_fscalef_x (float v) { return em_fmultf (v, x_multf); } + float em_fscalef_y (float v) { return em_fmultf (v, y_multf); } hb_position_t em_scale_dir (int16_t v, hb_direction_t direction) { return em_mult (v, dir_mult (direction)); } @@ -205,14 +209,14 @@ struct hb_font_t memset (extents, 0, sizeof (*extents)); return klass->get.f.font_h_extents (this, user_data, extents, - klass->user_data.font_h_extents); + !klass->user_data ? nullptr : klass->user_data->font_h_extents); } hb_bool_t get_font_v_extents (hb_font_extents_t *extents) { memset (extents, 0, sizeof (*extents)); return klass->get.f.font_v_extents (this, user_data, extents, - klass->user_data.font_v_extents); + !klass->user_data ? nullptr : klass->user_data->font_v_extents); } bool has_glyph (hb_codepoint_t unicode) @@ -228,7 +232,7 @@ struct hb_font_t *glyph = not_found; return klass->get.f.nominal_glyph (this, user_data, unicode, glyph, - klass->user_data.nominal_glyph); + !klass->user_data ? nullptr : klass->user_data->nominal_glyph); } unsigned int get_nominal_glyphs (unsigned int count, const hb_codepoint_t *first_unicode, @@ -240,7 +244,7 @@ struct hb_font_t count, first_unicode, unicode_stride, first_glyph, glyph_stride, - klass->user_data.nominal_glyphs); + !klass->user_data ? nullptr : klass->user_data->nominal_glyphs); } hb_bool_t get_variation_glyph (hb_codepoint_t unicode, hb_codepoint_t variation_selector, @@ -250,21 +254,21 @@ struct hb_font_t *glyph = not_found; return klass->get.f.variation_glyph (this, user_data, unicode, variation_selector, glyph, - klass->user_data.variation_glyph); + !klass->user_data ? nullptr : klass->user_data->variation_glyph); } hb_position_t get_glyph_h_advance (hb_codepoint_t glyph) { return klass->get.f.glyph_h_advance (this, user_data, glyph, - klass->user_data.glyph_h_advance); + !klass->user_data ? nullptr : klass->user_data->glyph_h_advance); } hb_position_t get_glyph_v_advance (hb_codepoint_t glyph) { return klass->get.f.glyph_v_advance (this, user_data, glyph, - klass->user_data.glyph_v_advance); + !klass->user_data ? nullptr : klass->user_data->glyph_v_advance); } void get_glyph_h_advances (unsigned int count, @@ -277,7 +281,7 @@ struct hb_font_t count, first_glyph, glyph_stride, first_advance, advance_stride, - klass->user_data.glyph_h_advances); + !klass->user_data ? nullptr : klass->user_data->glyph_h_advances); } void get_glyph_v_advances (unsigned int count, @@ -290,7 +294,7 @@ struct hb_font_t count, first_glyph, glyph_stride, first_advance, advance_stride, - klass->user_data.glyph_v_advances); + !klass->user_data ? nullptr : klass->user_data->glyph_v_advances); } hb_bool_t get_glyph_h_origin (hb_codepoint_t glyph, @@ -299,7 +303,7 @@ struct hb_font_t *x = *y = 0; return klass->get.f.glyph_h_origin (this, user_data, glyph, x, y, - klass->user_data.glyph_h_origin); + !klass->user_data ? nullptr : klass->user_data->glyph_h_origin); } hb_bool_t get_glyph_v_origin (hb_codepoint_t glyph, @@ -308,7 +312,7 @@ struct hb_font_t *x = *y = 0; return klass->get.f.glyph_v_origin (this, user_data, glyph, x, y, - klass->user_data.glyph_v_origin); + !klass->user_data ? nullptr : klass->user_data->glyph_v_origin); } hb_position_t get_glyph_h_kerning (hb_codepoint_t left_glyph, @@ -319,7 +323,7 @@ struct hb_font_t #else return klass->get.f.glyph_h_kerning (this, user_data, left_glyph, right_glyph, - klass->user_data.glyph_h_kerning); + !klass->user_data ? nullptr : klass->user_data->glyph_h_kerning); #endif } @@ -331,7 +335,7 @@ struct hb_font_t #else return klass->get.f.glyph_v_kerning (this, user_data, top_glyph, bottom_glyph, - klass->user_data.glyph_v_kerning); + !klass->user_data ? nullptr : klass->user_data->glyph_v_kerning); #endif } @@ -342,7 +346,7 @@ struct hb_font_t return klass->get.f.glyph_extents (this, user_data, glyph, extents, - klass->user_data.glyph_extents); + !klass->user_data ? nullptr : klass->user_data->glyph_extents); } hb_bool_t get_glyph_contour_point (hb_codepoint_t glyph, unsigned int point_index, @@ -352,7 +356,7 @@ struct hb_font_t return klass->get.f.glyph_contour_point (this, user_data, glyph, point_index, x, y, - klass->user_data.glyph_contour_point); + !klass->user_data ? nullptr : klass->user_data->glyph_contour_point); } hb_bool_t get_glyph_name (hb_codepoint_t glyph, @@ -362,7 +366,7 @@ struct hb_font_t return klass->get.f.glyph_name (this, user_data, glyph, name, size, - klass->user_data.glyph_name); + !klass->user_data ? nullptr : klass->user_data->glyph_name); } hb_bool_t get_glyph_from_name (const char *name, int len, /* -1 means nul-terminated */ @@ -373,7 +377,7 @@ struct hb_font_t return klass->get.f.glyph_from_name (this, user_data, name, len, glyph, - klass->user_data.glyph_from_name); + !klass->user_data ? nullptr : klass->user_data->glyph_from_name); } void get_glyph_shape (hb_codepoint_t glyph, @@ -382,7 +386,7 @@ struct hb_font_t klass->get.f.glyph_shape (this, user_data, glyph, draw_funcs, draw_data, - klass->user_data.glyph_shape); + !klass->user_data ? nullptr : klass->user_data->glyph_shape); } @@ -444,7 +448,6 @@ struct hb_font_t { *x = get_glyph_h_advance (glyph) / 2; - /* TODO cache this somehow?! */ hb_font_extents_t extents; get_h_extents_with_fallback (&extents); *y = extents.ascender; @@ -628,20 +631,26 @@ struct hb_font_t void mults_changed () { - signed upem = face->get_upem (); - x_mult = ((int64_t) x_scale << 16) / upem; - y_mult = ((int64_t) y_scale << 16) / upem; + float upem = face->get_upem (); + x_multf = x_scale / upem; + y_multf = y_scale / upem; + bool x_neg = x_scale < 0; + x_mult = (x_neg ? -((int64_t) -x_scale << 16) : ((int64_t) x_scale << 16)) / upem; + bool y_neg = y_scale < 0; + y_mult = (y_neg ? -((int64_t) -y_scale << 16) : ((int64_t) y_scale << 16)) / upem; slant_xy = y_scale ? slant * x_scale / y_scale : 0.f; + + data.fini (); } hb_position_t em_mult (int16_t v, int64_t mult) { return (hb_position_t) ((v * mult + 32768) >> 16); } - hb_position_t em_scalef (float v, int scale) - { return (hb_position_t) roundf (em_fscalef (v, scale)); } - float em_fscalef (float v, int scale) - { return v * scale / face->get_upem (); } - float em_fscale (int16_t v, int scale) - { return (float) v * scale / face->get_upem (); } + hb_position_t em_multf (float v, float mult) + { return (hb_position_t) roundf (em_fmultf (v, mult)); } + float em_fmultf (float v, float mult) + { return v * mult; } + float em_fmult (int16_t v, float mult) + { return (float) v * mult; } }; DECLARE_NULL_INSTANCE (hb_font_t); diff --git a/thirdparty/harfbuzz/src/hb-ft.cc b/thirdparty/harfbuzz/src/hb-ft.cc index 0cfbb22e31..b526a82865 100644 --- a/thirdparty/harfbuzz/src/hb-ft.cc +++ b/thirdparty/harfbuzz/src/hb-ft.cc @@ -37,6 +37,8 @@ #include "hb-font.hh" #include "hb-machinery.hh" #include "hb-cache.hh" +#include "hb-ot-os2-table.hh" +#include "hb-ot-shaper-arabic-pua.hh" #include FT_ADVANCES_H #include FT_MULTIPLE_MASTERS_H @@ -80,13 +82,13 @@ struct hb_ft_font_t { - mutable hb_mutex_t lock; - FT_Face ft_face; int load_flags; bool symbol; /* Whether selected cmap is symbol cmap. */ bool unref; /* Whether to destroy ft_face when done. */ - mutable int cached_x_scale; + mutable hb_mutex_t lock; + FT_Face ft_face; + mutable unsigned cached_serial; mutable hb_advance_cache_t advance_cache; }; @@ -103,7 +105,7 @@ _hb_ft_font_create (FT_Face ft_face, bool symbol, bool unref) ft_font->load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING; - ft_font->cached_x_scale = 0; + ft_font->cached_serial = (unsigned) -1; ft_font->advance_cache.init (); return ft_font; @@ -130,6 +132,58 @@ _hb_ft_font_destroy (void *data) hb_free (ft_font); } + +/* hb_font changed, update FT_Face. */ +static void _hb_ft_hb_font_changed (hb_font_t *font, FT_Face ft_face) +{ + + FT_Set_Char_Size (ft_face, + abs (font->x_scale), abs (font->y_scale), + 0, 0); +#if 0 + font->x_ppem * 72 * 64 / font->x_scale, + font->y_ppem * 72 * 64 / font->y_scale); +#endif + if (font->x_scale < 0 || font->y_scale < 0) + { + FT_Matrix matrix = { font->x_scale < 0 ? -1 : +1, 0, + 0, font->y_scale < 0 ? -1 : +1}; + FT_Set_Transform (ft_face, &matrix, nullptr); + } + +#if defined(HAVE_FT_GET_VAR_BLEND_COORDINATES) && !defined(HB_NO_VAR) + unsigned int num_coords; + const int *coords = hb_font_get_var_coords_normalized (font, &num_coords); + if (num_coords) + { + FT_Fixed *ft_coords = (FT_Fixed *) hb_calloc (num_coords, sizeof (FT_Fixed)); + if (ft_coords) + { + for (unsigned int i = 0; i < num_coords; i++) + ft_coords[i] = coords[i] * 4; + FT_Set_Var_Blend_Coordinates (ft_face, num_coords, ft_coords); + hb_free (ft_coords); + } + } +#endif +} + +/* Check if hb_font changed, update FT_Face. */ +static inline bool +_hb_ft_hb_font_check_changed (hb_font_t *font, + const hb_ft_font_t *ft_font) +{ + if (font->serial != ft_font->cached_serial) + { + _hb_ft_hb_font_changed (font, ft_font->ft_face); + ft_font->advance_cache.clear (); + ft_font->cached_serial = font->serial; + return true; + } + return false; +} + + /** * hb_ft_font_set_load_flags: * @font: #hb_font_t to work upon @@ -181,7 +235,7 @@ hb_ft_font_get_load_flags (hb_font_t *font) } /** - * hb_ft_font_get_face: + * hb_ft_font_get_face: (skip) * @font: #hb_font_t to work upon * * Fetches the FT_Face associated with the specified #hb_font_t @@ -203,7 +257,7 @@ hb_ft_font_get_face (hb_font_t *font) } /** - * hb_ft_font_lock_face: + * hb_ft_font_lock_face: (skip) * @font: #hb_font_t to work upon * * Gets the FT_Face associated with @font, This face will be kept around until @@ -246,7 +300,7 @@ hb_ft_font_unlock_face (hb_font_t *font) static hb_bool_t -hb_ft_get_nominal_glyph (hb_font_t *font HB_UNUSED, +hb_ft_get_nominal_glyph (hb_font_t *font, void *font_data, hb_codepoint_t unicode, hb_codepoint_t *glyph, @@ -258,14 +312,29 @@ hb_ft_get_nominal_glyph (hb_font_t *font HB_UNUSED, if (unlikely (!g)) { - if (unlikely (ft_font->symbol) && unicode <= 0x00FFu) + if (unlikely (ft_font->symbol)) { - /* For symbol-encoded OpenType fonts, we duplicate the - * U+F000..F0FF range at U+0000..U+00FF. That's what - * Windows seems to do, and that's hinted about at: - * https://docs.microsoft.com/en-us/typography/opentype/spec/recom - * under "Non-Standard (Symbol) Fonts". */ - g = FT_Get_Char_Index (ft_font->ft_face, 0xF000u + unicode); + switch ((unsigned) font->face->table.OS2->get_font_page ()) { + case OT::OS2::font_page_t::FONT_PAGE_NONE: + if (unicode <= 0x00FFu) + /* For symbol-encoded OpenType fonts, we duplicate the + * U+F000..F0FF range at U+0000..U+00FF. That's what + * Windows seems to do, and that's hinted about at: + * https://docs.microsoft.com/en-us/typography/opentype/spec/recom + * under "Non-Standard (Symbol) Fonts". */ + g = FT_Get_Char_Index (ft_font->ft_face, 0xF000u + unicode); + break; +#ifndef HB_NO_OT_SHAPER_ARABIC_FALLBACK + case OT::OS2::font_page_t::FONT_PAGE_SIMP_ARABIC: + g = FT_Get_Char_Index (ft_font->ft_face, _hb_arabic_pua_simp_map (unicode)); + break; + case OT::OS2::font_page_t::FONT_PAGE_TRAD_ARABIC: + g = FT_Get_Char_Index (ft_font->ft_face, _hb_arabic_pua_trad_map (unicode)); + break; +#endif + default: + break; + } if (!g) return false; } @@ -337,12 +406,6 @@ hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data, int load_flags = ft_font->load_flags; int mult = font->x_scale < 0 ? -1 : +1; - if (font->x_scale != ft_font->cached_x_scale) - { - ft_font->advance_cache.clear (); - ft_font->cached_x_scale = font->x_scale; - } - for (unsigned int i = 0; i < count; i++) { FT_Fixed v = 0; @@ -426,6 +489,7 @@ hb_ft_get_glyph_h_kerning (hb_font_t *font, void *user_data HB_UNUSED) { const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + hb_lock_t lock (ft_font->lock); FT_Vector kerningv; FT_Kerning_Mode mode = font->x_ppem ? FT_KERNING_DEFAULT : FT_KERNING_UNFITTED; @@ -556,6 +620,7 @@ hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED, const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; + metrics->ascender = FT_MulFix(ft_face->ascender, ft_face->size->metrics.y_scale); metrics->descender = FT_MulFix(ft_face->descender, ft_face->size->metrics.y_scale); metrics->line_gap = FT_MulFix( ft_face->height, ft_face->size->metrics.y_scale ) - (metrics->ascender - metrics->descender); @@ -619,6 +684,8 @@ hb_ft_get_glyph_shape (hb_font_t *font HB_UNUSED, hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; + _hb_ft_hb_font_check_changed (font, ft_font); + if (unlikely (FT_Load_Glyph (ft_face, glyph, FT_LOAD_NO_BITMAP | ft_font->load_flags))) return; @@ -964,6 +1031,31 @@ hb_ft_font_changed (hb_font_t *font) } /** + * hb_ft_hb_font_changed: + * @font: #hb_font_t to work upon + * + * Refreshes the state of the underlying FT_Face of @font when the hb_font_t + * @font has changed. + * This function should be called after changing the size or + * variation-axis settings on the @font. + * This call is fast if nothing has changed on @font. + * + * Return value: true if changed, false otherwise + * + * Since: 4.4.0 + **/ +hb_bool_t +hb_ft_hb_font_changed (hb_font_t *font) +{ + if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy) + return false; + + hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data; + + return _hb_ft_hb_font_check_changed (font, ft_font); +} + +/** * hb_ft_font_create_referenced: * @ft_face: FT_Face to work upon * @@ -1081,35 +1173,7 @@ hb_ft_font_set_funcs (hb_font_t *font) if (FT_Select_Charmap (ft_face, FT_ENCODING_MS_SYMBOL)) FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE); - FT_Set_Char_Size (ft_face, - abs (font->x_scale), abs (font->y_scale), - 0, 0); -#if 0 - font->x_ppem * 72 * 64 / font->x_scale, - font->y_ppem * 72 * 64 / font->y_scale); -#endif - if (font->x_scale < 0 || font->y_scale < 0) - { - FT_Matrix matrix = { font->x_scale < 0 ? -1 : +1, 0, - 0, font->y_scale < 0 ? -1 : +1}; - FT_Set_Transform (ft_face, &matrix, nullptr); - } - -#if defined(HAVE_FT_GET_VAR_BLEND_COORDINATES) && !defined(HB_NO_VAR) - unsigned int num_coords; - const int *coords = hb_font_get_var_coords_normalized (font, &num_coords); - if (num_coords) - { - FT_Fixed *ft_coords = (FT_Fixed *) hb_calloc (num_coords, sizeof (FT_Fixed)); - if (ft_coords) - { - for (unsigned int i = 0; i < num_coords; i++) - ft_coords[i] = coords[i] * 4; - FT_Set_Var_Blend_Coordinates (ft_face, num_coords, ft_coords); - hb_free (ft_coords); - } - } -#endif + _hb_ft_hb_font_changed (font, ft_face); ft_face->generic.data = blob; ft_face->generic.finalizer = (FT_Generic_Finalizer) _release_blob; diff --git a/thirdparty/harfbuzz/src/hb-ft.h b/thirdparty/harfbuzz/src/hb-ft.h index bf07115ab9..6a8a7abe8c 100644 --- a/thirdparty/harfbuzz/src/hb-ft.h +++ b/thirdparty/harfbuzz/src/hb-ft.h @@ -122,10 +122,17 @@ hb_ft_font_set_load_flags (hb_font_t *font, int load_flags); HB_EXTERN int hb_ft_font_get_load_flags (hb_font_t *font); -/* Call when size or variations settings on underlying FT_Face change. */ +/* Call when size or variations settings on underlying FT_Face changed, + * and you want to update the hb_font_t from it. */ HB_EXTERN void hb_ft_font_changed (hb_font_t *font); +/* Call when size or variations settings on underlying hb_font_t may have + * changed, and you want to update the FT_Face from it. This call is fast + * if nothing changed on hb_font_t. Returns true if changed. */ +HB_EXTERN hb_bool_t +hb_ft_hb_font_changed (hb_font_t *font); + /* Makes an hb_font_t use FreeType internally to implement font functions. * Note: this internally creates an FT_Face. Use it when you create your * hb_face_t using hb_face_create(). */ diff --git a/thirdparty/harfbuzz/src/hb-iter.hh b/thirdparty/harfbuzz/src/hb-iter.hh index 43a3098f65..d4461f166c 100644 --- a/thirdparty/harfbuzz/src/hb-iter.hh +++ b/thirdparty/harfbuzz/src/hb-iter.hh @@ -43,17 +43,12 @@ * is writable, then the iterator returns lvalues, otherwise it * returns rvalues. * - * TODO Document more. - * - * If iterator implementation implements operator!=, then can be + * If iterator implementation implements operator!=, then it can be * used in range-based for loop. That already happens if the iterator * is random-access. Otherwise, the range-based for loop incurs * one traversal to find end(), which can be avoided if written * as a while-style for loop, or if iterator implements a faster - * __end__() method. - * TODO When opting in for C++17, address this by changing return - * type of .end()? - */ + * __end__() method. */ /* * Base classes for iterators. @@ -75,10 +70,6 @@ struct hb_iter_t iter_t* thiz () { return static_cast< iter_t *> (this); } public: - /* TODO: - * Port operators below to use hb_enable_if to sniff which method implements - * an operator and use it, and remove hb_iter_fallback_mixin_t completely. */ - /* Operators. */ iter_t iter () const { return *thiz(); } iter_t operator + () const { return *thiz(); } @@ -87,8 +78,7 @@ struct hb_iter_t explicit operator bool () const { return thiz()->__more__ (); } unsigned len () const { return thiz()->__len__ (); } /* The following can only be enabled if item_t is reference type. Otherwise - * it will be returning pointer to temporary rvalue. - * TODO Use a wrapper return type to fix for non-reference type. */ + * it will be returning pointer to temporary rvalue. */ template <typename T = item_t, hb_enable_if (std::is_reference<T>::value)> hb_remove_reference<item_t>* operator -> () const { return std::addressof (**thiz()); } diff --git a/thirdparty/harfbuzz/src/hb-machinery.hh b/thirdparty/harfbuzz/src/hb-machinery.hh index e52a6a4124..ff2a99f5ed 100644 --- a/thirdparty/harfbuzz/src/hb-machinery.hh +++ b/thirdparty/harfbuzz/src/hb-machinery.hh @@ -176,7 +176,7 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData> void init0 () {} /* Init, when memory is already set to 0. No-op for us. */ void init () { instance.set_relaxed (nullptr); } - void fini () { do_destroy (instance.get ()); } + void fini () { do_destroy (instance.get ()); init (); } void free_instance () { diff --git a/thirdparty/harfbuzz/src/hb-map.cc b/thirdparty/harfbuzz/src/hb-map.cc index 9f1ac42846..089615c72a 100644 --- a/thirdparty/harfbuzz/src/hb-map.cc +++ b/thirdparty/harfbuzz/src/hb-map.cc @@ -40,7 +40,7 @@ /** - * hb_map_create: (Xconstructor) + * hb_map_create: * * Creates a new, initially empty map. * @@ -172,6 +172,25 @@ hb_map_allocation_successful (const hb_map_t *map) return map->successful; } +/** + * hb_map_copy: + * @map: A map + * + * Allocate a copy of @map. + * + * Return value: Newly-allocated map. + * + * Since: 4.4.0 + **/ +hb_map_t * +hb_map_copy (const hb_map_t *map) +{ + hb_map_t *copy = hb_map_create (); + if (unlikely (!copy)) return nullptr; + copy->resize (map->population); + hb_copy (*map, *copy); + return copy; +} /** * hb_map_set: @@ -289,3 +308,40 @@ hb_map_get_population (const hb_map_t *map) { return map->get_population (); } + +/** + * hb_map_is_equal: + * @map: A map + * @other: Another map + * + * Tests whether @map and @other are equal (contain the same + * elements). + * + * Return value: %true if the two maps are equal, %false otherwise. + * + * Since: 4.3.0 + **/ +hb_bool_t +hb_map_is_equal (const hb_map_t *map, + const hb_map_t *other) +{ + return map->is_equal (*other); +} + +/** + * hb_map_hash: + * @map: A map + * + * Creates a hash representing @map. + * + * Return value: + * A hash of @map. + * + * Since: 4.4.0 + **/ +HB_EXTERN unsigned int +hb_map_hash (const hb_map_t *map) +{ + return map->hash (); +} + diff --git a/thirdparty/harfbuzz/src/hb-map.h b/thirdparty/harfbuzz/src/hb-map.h index 6a45a7bdd5..41d877d6a1 100644 --- a/thirdparty/harfbuzz/src/hb-map.h +++ b/thirdparty/harfbuzz/src/hb-map.h @@ -82,6 +82,9 @@ hb_map_get_user_data (hb_map_t *map, HB_EXTERN hb_bool_t hb_map_allocation_successful (const hb_map_t *map); +HB_EXTERN hb_map_t * +hb_map_copy (const hb_map_t *map); + HB_EXTERN void hb_map_clear (hb_map_t *map); @@ -91,6 +94,13 @@ hb_map_is_empty (const hb_map_t *map); HB_EXTERN unsigned int hb_map_get_population (const hb_map_t *map); +HB_EXTERN hb_bool_t +hb_map_is_equal (const hb_map_t *map, + const hb_map_t *other); + +HB_EXTERN unsigned int +hb_map_hash (const hb_map_t *map); + HB_EXTERN void hb_map_set (hb_map_t *map, hb_codepoint_t key, diff --git a/thirdparty/harfbuzz/src/hb-map.hh b/thirdparty/harfbuzz/src/hb-map.hh index 9341637eac..5efad8d20c 100644 --- a/thirdparty/harfbuzz/src/hb-map.hh +++ b/thirdparty/harfbuzz/src/hb-map.hh @@ -34,19 +34,18 @@ * hb_hashmap_t */ +extern HB_INTERNAL const hb_codepoint_t minus_1; + template <typename K, typename V, - typename k_invalid_t = K, - typename v_invalid_t = V, - k_invalid_t kINVALID = std::is_pointer<K>::value ? 0 : std::is_signed<K>::value ? hb_int_min (K) : (K) -1, - v_invalid_t vINVALID = std::is_pointer<V>::value ? 0 : std::is_signed<V>::value ? hb_int_min (V) : (V) -1> + bool minus_one = false> struct hb_hashmap_t { hb_hashmap_t () { init (); } ~hb_hashmap_t () { fini (); } - hb_hashmap_t (const hb_hashmap_t& o) : hb_hashmap_t () { hb_copy (o, *this); } + hb_hashmap_t (const hb_hashmap_t& o) : hb_hashmap_t () { resize (population); hb_copy (o, *this); } hb_hashmap_t (hb_hashmap_t&& o) : hb_hashmap_t () { hb_swap (*this, o); } - hb_hashmap_t& operator= (const hb_hashmap_t& o) { hb_copy (o, *this); return *this; } + hb_hashmap_t& operator= (const hb_hashmap_t& o) { resize (population); hb_copy (o, *this); return *this; } hb_hashmap_t& operator= (hb_hashmap_t&& o) { hb_swap (*this, o); return *this; } hb_hashmap_t (std::initializer_list<hb_pair_t<K, V>> lst) : hb_hashmap_t () @@ -58,44 +57,53 @@ struct hb_hashmap_t hb_requires (hb_is_iterable (Iterable))> hb_hashmap_t (const Iterable &o) : hb_hashmap_t () { - hb_copy (o, *this); + auto iter = hb_iter (o); + if (iter.is_random_access_iterator) + resize (hb_len (iter)); + hb_copy (iter, *this); } struct item_t { K key; + uint32_t hash : 30; + uint32_t is_used_ : 1; + uint32_t is_tombstone_ : 1; V value; - uint32_t hash; + + bool is_used () const { return is_used_; } + void set_used (bool is_used) { is_used_ = is_used; } + bool is_tombstone () const { return is_tombstone_; } + void set_tombstone (bool is_tombstone) { is_tombstone_ = is_tombstone; } + bool is_real () const { return is_used_ && !is_tombstone_; } + + template <bool v = minus_one, + hb_enable_if (v == false)> + static inline const V& default_value () { return Null(V); }; + template <bool v = minus_one, + hb_enable_if (v == true)> + static inline const V& default_value () + { + static_assert (hb_is_same (V, hb_codepoint_t), ""); + return minus_1; + }; void clear () { new (std::addressof (key)) K (); - key = hb_coerce<K> (kINVALID); new (std::addressof (value)) V (); - value = hb_coerce<V> (vINVALID); hash = 0; + is_used_ = false; + is_tombstone_ = false; } bool operator == (const K &o) { return hb_deref (key) == hb_deref (o); } bool operator == (const item_t &o) { return *this == o.key; } - bool is_unused () const - { - const K inv = hb_coerce<K> (kINVALID); - return key == inv; - } - bool is_tombstone () const - { - const K kinv = hb_coerce<K> (kINVALID); - const V vinv = hb_coerce<V> (vINVALID); - return key != kinv && value == vinv; - } - bool is_real () const - { - const K kinv = hb_coerce<K> (kINVALID); - const V vinv = hb_coerce<V> (vINVALID); - return key != kinv && value != vinv; - } hb_pair_t<K, V> get_pair() const { return hb_pair_t<K, V> (key, value); } + hb_pair_t<const K &, const V &> get_pair_ref() const { return hb_pair_t<const K &, const V &> (key, value); } + + uint32_t total_hash () const + { return (hash * 31) + hb_hash (value); } }; hb_object_header_t header; @@ -154,11 +162,11 @@ struct hb_hashmap_t bool in_error () const { return !successful; } - bool resize () + bool resize (unsigned new_population = 0) { if (unlikely (!successful)) return false; - unsigned int power = hb_bit_storage (population * 2 + 8); + unsigned int power = hb_bit_storage (hb_max (population, new_population) * 2 + 8); unsigned int new_size = 1u << power; item_t *new_items = (item_t *) hb_malloc ((size_t) new_size * sizeof (item_t)); if (unlikely (!new_items)) @@ -196,27 +204,39 @@ struct hb_hashmap_t return true; } - bool set (K key, const V& value) { return set_with_hash (key, hb_hash (key), value); } - bool set (K key, V&& value) { return set_with_hash (key, hb_hash (key), std::move (value)); } + template <typename VV> + bool set (K key, VV&& value) { return set_with_hash (key, hb_hash (key), std::forward<VV> (value)); } - V get (K key) const + const V& get (K key) const { - if (unlikely (!items)) return hb_coerce<V> (vINVALID); + if (unlikely (!items)) return item_t::default_value (); unsigned int i = bucket_for (key); - return items[i].is_real () && items[i] == key ? items[i].value : hb_coerce<V> (vINVALID); + return items[i].is_real () && items[i] == key ? items[i].value : item_t::default_value (); } - void del (K key) { set (key, hb_coerce<V> (vINVALID)); } + void del (K key) { set_with_hash (key, hb_hash (key), item_t::default_value (), true); } /* Has interface. */ - typedef V value_t; + typedef const V& value_t; value_t operator [] (K k) const { return get (k); } - bool has (K k, V *vp = nullptr) const + bool has (K key, const V **vp = nullptr) const { - V v = (*this)[k]; - if (vp) *vp = v; - const V vinv = hb_coerce<V> (vINVALID); - return v != vinv; + if (unlikely (!items)) + { + if (vp) *vp = &item_t::default_value (); + return false; + } + unsigned int i = bucket_for (key); + if (items[i].is_real () && items[i] == key) + { + if (vp) *vp = &items[i].value; + return true; + } + else + { + if (vp) *vp = &item_t::default_value (); + return false; + } } /* Projection. */ V operator () (K k) const { return get (k); } @@ -235,6 +255,28 @@ struct hb_hashmap_t bool is_empty () const { return population == 0; } explicit operator bool () const { return !is_empty (); } + uint32_t hash () const + { + uint32_t h = 0; + for (const auto &item : + hb_array (items, mask ? mask + 1 : 0) + | hb_filter (&item_t::is_real)) + h ^= item.total_hash (); + return h; + } + + bool is_equal (const hb_hashmap_t &other) const + { + if (population != other.population) return false; + + for (auto pair : iter ()) + if (get (pair.first) != pair.second) + return false; + + return true; + } + bool operator == (const hb_hashmap_t &other) const { return is_equal (other); } + bool operator != (const hb_hashmap_t &other) const { return !is_equal (other); } + unsigned int get_population () const { return population; } /* @@ -246,6 +288,12 @@ struct hb_hashmap_t | hb_filter (&item_t::is_real) | hb_map (&item_t::get_pair) ) + auto iter_ref () const HB_AUTO_RETURN + ( + + hb_array (items, mask ? mask + 1 : 0) + | hb_filter (&item_t::is_real) + | hb_map (&item_t::get_pair_ref) + ) auto keys () const HB_AUTO_RETURN ( + hb_array (items, mask ? mask + 1 : 0) @@ -268,19 +316,16 @@ struct hb_hashmap_t protected: template <typename VV> - bool set_with_hash (K key, uint32_t hash, VV&& value) + bool set_with_hash (K key, uint32_t hash, VV&& value, bool is_delete=false) { if (unlikely (!successful)) return false; - const K kinv = hb_coerce<K> (kINVALID); - if (unlikely (key == kinv)) return true; if (unlikely ((occupancy + occupancy / 2) >= mask && !resize ())) return false; unsigned int i = bucket_for_hash (key, hash); - const V vinv = hb_coerce<V> (vINVALID); - if (value == vinv && items[i].key != key) + if (is_delete && items[i].key != key) return true; /* Trying to delete non-existent key. */ - if (!items[i].is_unused ()) + if (items[i].is_used ()) { occupancy--; if (!items[i].is_tombstone ()) @@ -288,27 +333,30 @@ struct hb_hashmap_t } items[i].key = key; - items[i].value = value; + items[i].value = std::forward<VV> (value); items[i].hash = hash; + items[i].set_used (true); + items[i].set_tombstone (is_delete); occupancy++; - if (!items[i].is_tombstone ()) + if (!is_delete) population++; return true; } - unsigned int bucket_for (K key) const + unsigned int bucket_for (const K &key) const { return bucket_for_hash (key, hb_hash (key)); } - unsigned int bucket_for_hash (K key, uint32_t hash) const + unsigned int bucket_for_hash (const K &key, uint32_t hash) const { + hash &= 0x3FFFFFFF; // We only store lower 30bit of hash unsigned int i = hash % prime; unsigned int step = 0; unsigned int tombstone = (unsigned) -1; - while (!items[i].is_unused ()) + while (items[i].is_used ()) { if (items[i].hash == hash && items[i] == key) return i; @@ -377,21 +425,16 @@ struct hb_hashmap_t struct hb_map_t : hb_hashmap_t<hb_codepoint_t, hb_codepoint_t, - hb_codepoint_t, - hb_codepoint_t, - HB_MAP_VALUE_INVALID, - HB_MAP_VALUE_INVALID> + true> { using hashmap = hb_hashmap_t<hb_codepoint_t, hb_codepoint_t, - hb_codepoint_t, - hb_codepoint_t, - HB_MAP_VALUE_INVALID, - HB_MAP_VALUE_INVALID>; + true>; - hb_map_t () = default; ~hb_map_t () = default; - hb_map_t (hb_map_t&) = default; + hb_map_t () : hashmap () {} + hb_map_t (const hb_map_t &o) : hashmap ((hashmap &) o) {} + hb_map_t (hb_map_t &&o) : hashmap (std::move ((hashmap &) o)) {} hb_map_t& operator= (const hb_map_t&) = default; hb_map_t& operator= (hb_map_t&&) = default; hb_map_t (std::initializer_list<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> lst) : hashmap (lst) {} diff --git a/thirdparty/harfbuzz/src/hb-meta.hh b/thirdparty/harfbuzz/src/hb-meta.hh index 3fea5d995e..e97d790fc3 100644 --- a/thirdparty/harfbuzz/src/hb-meta.hh +++ b/thirdparty/harfbuzz/src/hb-meta.hh @@ -188,6 +188,19 @@ template <> struct hb_int_max<signed long long> : hb_integral_constant<signed l 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 +#if defined(__GNUC__) && __GNUC__ < 5 +#define hb_is_trivially_copyable(T) __has_trivial_copy(T) +#define hb_is_trivially_copy_assignable(T) __has_trivial_assign(T) +#define hb_is_trivially_constructible(T) __has_trivial_constructor(T) +#define hb_is_trivially_copy_constructible(T) __has_trivial_copy_constructor(T) +#define hb_is_trivially_destructible(T) __has_trivial_destructor(T) +#else +#define hb_is_trivially_copyable(T) std::is_trivially_copyable<T>::value +#define hb_is_trivially_copy_assignable(T) std::is_trivially_copy_assignable<T>::value +#define hb_is_trivially_constructible(T) std::is_trivially_constructible<T>::value +#define hb_is_trivially_copy_constructible(T) std::is_trivially_copy_constructible<T>::value +#define hb_is_trivially_destructible(T) std::is_trivially_destructible<T>::value +#endif /* Class traits. */ diff --git a/thirdparty/harfbuzz/src/hb-null.hh b/thirdparty/harfbuzz/src/hb-null.hh index db38a4dfd2..78eb6474d5 100644 --- a/thirdparty/harfbuzz/src/hb-null.hh +++ b/thirdparty/harfbuzz/src/hb-null.hh @@ -37,7 +37,7 @@ /* Global nul-content Null pool. Enlarge as necessary. */ -#define HB_NULL_POOL_SIZE 384 +#define HB_NULL_POOL_SIZE 448 /* Use SFINAE to sniff whether T has min_size; in which case return the larger * of sizeof(T) and T::null_size, otherwise return sizeof(T). @@ -108,7 +108,7 @@ struct NullHelper /* Specializations for arbitrary-content Null objects expressed in bytes. */ #define DECLARE_NULL_NAMESPACE_BYTES(Namespace, Type) \ } /* Close namespace. */ \ - extern HB_INTERNAL const unsigned char _hb_Null_##Namespace##_##Type[Namespace::Type::null_size]; \ + extern HB_INTERNAL const unsigned char _hb_Null_##Namespace##_##Type[hb_null_size (Namespace::Type)]; \ template <> \ struct Null<Namespace::Type> { \ static Namespace::Type const & get_null () { \ @@ -118,7 +118,7 @@ struct NullHelper namespace Namespace { \ static_assert (true, "") /* Require semicolon after. */ #define DEFINE_NULL_NAMESPACE_BYTES(Namespace, Type) \ - const unsigned char _hb_Null_##Namespace##_##Type[Namespace::Type::null_size] + const unsigned char _hb_Null_##Namespace##_##Type[hb_null_size (Namespace::Type)] /* Specializations for arbitrary-content Null objects expressed as struct initializer. */ #define DECLARE_NULL_INSTANCE(Type) \ diff --git a/thirdparty/harfbuzz/src/hb-open-type.hh b/thirdparty/harfbuzz/src/hb-open-type.hh index 7e524177f6..aee7064be3 100644 --- a/thirdparty/harfbuzz/src/hb-open-type.hh +++ b/thirdparty/harfbuzz/src/hb-open-type.hh @@ -33,6 +33,7 @@ #include "hb-blob.hh" #include "hb-face.hh" #include "hb-machinery.hh" +#include "hb-meta.hh" #include "hb-subset.hh" @@ -518,7 +519,7 @@ struct UnsizedArrayOf { TRACE_SANITIZE (this); if (unlikely (!sanitize_shallow (c, count))) return_trace (false); - if (!sizeof... (Ts) && std::is_trivially_copyable<Type>::value) return_trace (true); + if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true); for (unsigned int i = 0; i < count; i++) if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...))) return_trace (false); @@ -707,7 +708,7 @@ struct ArrayOf { TRACE_SANITIZE (this); if (unlikely (!sanitize_shallow (c))) return_trace (false); - if (!sizeof... (Ts) && std::is_trivially_copyable<Type>::value) return_trace (true); + if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true); unsigned int count = len; for (unsigned int i = 0; i < count; i++) if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...))) @@ -835,7 +836,7 @@ struct HeadlessArrayOf { TRACE_SANITIZE (this); if (unlikely (!sanitize_shallow (c))) return_trace (false); - if (!sizeof... (Ts) && std::is_trivially_copyable<Type>::value) return_trace (true); + if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true); unsigned int count = get_length (); for (unsigned int i = 0; i < count; i++) if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...))) @@ -884,7 +885,7 @@ struct ArrayOfM1 { TRACE_SANITIZE (this); if (unlikely (!sanitize_shallow (c))) return_trace (false); - if (!sizeof... (Ts) && std::is_trivially_copyable<Type>::value) return_trace (true); + if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true); unsigned int count = lenM1 + 1; for (unsigned int i = 0; i < count; i++) if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...))) @@ -1070,7 +1071,7 @@ struct VarSizedBinSearchArrayOf { TRACE_SANITIZE (this); if (unlikely (!sanitize_shallow (c))) return_trace (false); - if (!sizeof... (Ts) && std::is_trivially_copyable<Type>::value) return_trace (true); + if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true); unsigned int count = get_length (); for (unsigned int i = 0; i < count; i++) if (unlikely (!(*this)[i].sanitize (c, std::forward<Ts> (ds)...))) diff --git a/thirdparty/harfbuzz/src/hb-ot-cff-common.hh b/thirdparty/harfbuzz/src/hb-ot-cff-common.hh index c102c15173..ae3b83a256 100644 --- a/thirdparty/harfbuzz/src/hb-ot-cff-common.hh +++ b/thirdparty/harfbuzz/src/hb-ot-cff-common.hh @@ -46,49 +46,21 @@ template<typename Type> static inline const Type& StructAtOffsetOrNull (const void *P, unsigned int offset) { return offset ? StructAtOffset<Type> (P, offset) : Null (Type); } -inline unsigned int calcOffSize (unsigned int dataSize) -{ - unsigned int size = 1; - unsigned int offset = dataSize + 1; - while (offset & ~0xFF) - { - size++; - offset >>= 8; - } - /* format does not support size > 4; caller should handle it as an error */ - return size; -} - struct code_pair_t { hb_codepoint_t code; hb_codepoint_t glyph; }; -typedef hb_vector_t<unsigned char> str_buff_t; -struct str_buff_vec_t : hb_vector_t<str_buff_t> -{ - unsigned int total_size () const - { - unsigned int size = 0; - for (unsigned int i = 0; i < length; i++) - size += (*this)[i].length; - return size; - } - - private: - typedef hb_vector_t<str_buff_t> SUPER; -}; +using str_buff_t = hb_vector_t<unsigned char>; +using str_buff_vec_t = hb_vector_t<str_buff_t>; /* CFF INDEX */ template <typename COUNT> struct CFFIndex { - static unsigned int calculate_offset_array_size (unsigned int offSize, unsigned int count) - { return offSize * (count + 1); } - unsigned int offset_array_size () const - { return calculate_offset_array_size (offSize, count); } + { return offSize * (count + 1); } CFFIndex *copy (hb_serialize_context_t *c) const { @@ -100,55 +72,46 @@ struct CFFIndex return_trace (out); } - bool serialize (hb_serialize_context_t *c, const CFFIndex &src) - { - TRACE_SERIALIZE (this); - unsigned int size = src.get_size (); - CFFIndex *dest = c->allocate_size<CFFIndex> (size); - if (unlikely (!dest)) return_trace (false); - memcpy (dest, &src, size); - return_trace (true); - } - bool serialize (hb_serialize_context_t *c, unsigned int offSize_, const byte_str_array_t &byteArray) { TRACE_SERIALIZE (this); + if (byteArray.length == 0) { COUNT *dest = c->allocate_min<COUNT> (); if (unlikely (!dest)) return_trace (false); *dest = 0; + return_trace (true); } - else - { - /* serialize CFFIndex header */ - if (unlikely (!c->extend_min (this))) return_trace (false); - this->count = byteArray.length; - this->offSize = offSize_; - if (unlikely (!c->allocate_size<HBUINT8> (offSize_ * (byteArray.length + 1)))) - return_trace (false); - /* serialize indices */ - unsigned int offset = 1; - unsigned int i = 0; - for (; i < byteArray.length; i++) - { - set_offset_at (i, offset); - offset += byteArray[i].get_size (); - } + /* serialize CFFIndex header */ + if (unlikely (!c->extend_min (this))) return_trace (false); + this->count = byteArray.length; + this->offSize = offSize_; + if (unlikely (!c->allocate_size<HBUINT8> (offSize_ * (byteArray.length + 1)))) + return_trace (false); + + /* serialize indices */ + unsigned int offset = 1; + unsigned int i = 0; + for (; i < byteArray.length; i++) + { set_offset_at (i, offset); + offset += byteArray[i].get_size (); + } + set_offset_at (i, offset); - /* serialize data */ - for (unsigned int i = 0; i < byteArray.length; i++) - { - const byte_str_t &bs = byteArray[i]; - unsigned char *dest = c->allocate_size<unsigned char> (bs.length); - if (unlikely (!dest)) return_trace (false); - memcpy (dest, &bs[0], bs.length); - } + /* serialize data */ + for (unsigned int i = 0; i < byteArray.length; i++) + { + const hb_ubytes_t &bs = byteArray[i]; + unsigned char *dest = c->allocate_size<unsigned char> (bs.length); + if (unlikely (!dest)) return_trace (false); + memcpy (dest, &bs[0], bs.length); } + return_trace (true); } @@ -160,7 +123,7 @@ struct CFFIndex byteArray.init (); byteArray.resize (buffArray.length); for (unsigned int i = 0; i < byteArray.length; i++) - byteArray[i] = byte_str_t (buffArray[i].arrayZ, buffArray[i].length); + byteArray[i] = hb_ubytes_t (buffArray[i].arrayZ, buffArray[i].length); bool result = this->serialize (c, offSize_, byteArray); byteArray.fini (); return result; @@ -172,18 +135,9 @@ struct CFFIndex Iterator it) { TRACE_SERIALIZE (this); - if (it.len () == 0) - { - COUNT *dest = c->allocate_min<COUNT> (); - if (unlikely (!dest)) return_trace (false); - *dest = 0; - } - else - { - serialize_header(c, + it | hb_map ([] (const byte_str_t &_) { return _.length; })); - for (const auto &_ : +it) - _.copy (c); - } + serialize_header(c, + it | hb_map ([] (const hb_ubytes_t &_) { return _.length; })); + for (const auto &_ : +it) + _.copy (c); return_trace (true); } @@ -196,7 +150,7 @@ struct CFFIndex { auto it = + hb_iter (buffArray) - | hb_map ([] (const str_buff_t &_) { return byte_str_t (_.arrayZ, _.length); }) + | hb_map ([] (const str_buff_t &_) { return hb_ubytes_t (_.arrayZ, _.length); }) ; return serialize (c, it); } @@ -209,13 +163,15 @@ struct CFFIndex TRACE_SERIALIZE (this); unsigned total = + it | hb_reduce (hb_add, 0); - unsigned off_size = calcOffSize (total); + unsigned off_size = (hb_bit_storage (total + 1) + 7) / 8; /* serialize CFFIndex header */ if (unlikely (!c->extend_min (this))) return_trace (false); this->count = it.len (); + if (!this->count) return_trace (true); + if (unlikely (!c->extend (this->offSize))) return_trace (false); this->offSize = off_size; - if (unlikely (!c->allocate_size<HBUINT8> (off_size * (it.len () + 1)))) + if (unlikely (!c->allocate_size<HBUINT8> (off_size * (this->count + 1)))) return_trace (false); /* serialize indices */ @@ -233,6 +189,7 @@ struct CFFIndex void set_offset_at (unsigned int index, unsigned int offset) { + assert (index <= count); HBUINT8 *p = offsets + offSize * index + offSize; unsigned int size = offSize; for (; size; size--) @@ -243,11 +200,13 @@ struct CFFIndex } } + private: unsigned int offset_at (unsigned int index) const { assert (index <= count); - const HBUINT8 *p = offsets + offSize * index; + unsigned int size = offSize; + const HBUINT8 *p = offsets + size * index; unsigned int offset = 0; for (; size; size--) offset = (offset << 8) + *p++; @@ -256,72 +215,57 @@ struct CFFIndex unsigned int length_at (unsigned int index) const { - if (unlikely ((offset_at (index + 1) < offset_at (index)) || - (offset_at (index + 1) > offset_at (count)))) + unsigned offset0 = offset_at (index); + unsigned offset1 = offset_at (index + 1); + if (unlikely (offset1 < offset0 || offset1 > offset_at (count))) return 0; - return offset_at (index + 1) - offset_at (index); + return offset1 - offset0; } const unsigned char *data_base () const - { return (const unsigned char *) this + min_size + offset_array_size (); } - - unsigned int data_size () const { return HBINT8::static_size; } + { return (const unsigned char *) this + min_size + offSize.static_size + offset_array_size (); } + public: - byte_str_t operator [] (unsigned int index) const + hb_ubytes_t operator [] (unsigned int index) const { - if (unlikely (index >= count)) return Null (byte_str_t); - return byte_str_t (data_base () + offset_at (index) - 1, length_at (index)); + if (unlikely (index >= count)) return hb_ubytes_t (); + unsigned length = length_at (index); + if (unlikely (!length)) return hb_ubytes_t (); + return hb_ubytes_t (data_base () + offset_at (index) - 1, length); } unsigned int get_size () const { - if (this == &Null (CFFIndex)) return 0; - if (count > 0) - return min_size + offset_array_size () + (offset_at (count) - 1); - return count.static_size; /* empty CFFIndex contains count only */ + if (count) + return min_size + offSize.static_size + offset_array_size () + (offset_at (count) - 1); + return min_size; /* empty CFFIndex contains count only */ } bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (likely ((c->check_struct (this) && count == 0) || /* empty INDEX */ - (c->check_struct (this) && offSize >= 1 && offSize <= 4 && - c->check_array (offsets, offSize, count + 1) && - c->check_array ((const HBUINT8*) data_base (), 1, max_offset () - 1)))); - } - - protected: - unsigned int max_offset () const - { - unsigned int max = 0; - for (unsigned int i = 0; i < count + 1u; i++) - { - unsigned int off = offset_at (i); - if (off > max) max = off; - } - return max; + return_trace (likely (c->check_struct (this) && + (count == 0 || /* empty INDEX */ + (count < count + 1u && + c->check_struct (&offSize) && offSize >= 1 && offSize <= 4 && + c->check_array (offsets, offSize, count + 1u) && + c->check_array ((const HBUINT8*) data_base (), 1, offset_at (count) - 1))))); } public: COUNT count; /* Number of object data. Note there are (count+1) offsets */ + private: HBUINT8 offSize; /* The byte size of each offset in the offsets array. */ HBUINT8 offsets[HB_VAR_ARRAY]; /* The array of (count + 1) offsets into objects array (1-base). */ /* HBUINT8 data[HB_VAR_ARRAY]; Object data */ public: - DEFINE_SIZE_ARRAY (COUNT::static_size + HBUINT8::static_size, offsets); + DEFINE_SIZE_MIN (COUNT::static_size); }; template <typename COUNT, typename TYPE> struct CFFIndexOf : CFFIndex<COUNT> { - const byte_str_t operator [] (unsigned int index) const - { - if (likely (index < CFFIndex<COUNT>::count)) - return byte_str_t (CFFIndex<COUNT>::data_base () + CFFIndex<COUNT>::offset_at (index) - 1, CFFIndex<COUNT>::length_at (index)); - return Null (byte_str_t); - } - template <typename DATA, typename PARAM1, typename PARAM2> bool serialize (hb_serialize_context_t *c, unsigned int offSize_, diff --git a/thirdparty/harfbuzz/src/hb-ot-cff1-table.cc b/thirdparty/harfbuzz/src/hb-ot-cff1-table.cc index df4554ac00..bd9fe5d6d4 100644 --- a/thirdparty/harfbuzz/src/hb-ot-cff1-table.cc +++ b/thirdparty/harfbuzz/src/hb-ot-cff1-table.cc @@ -311,10 +311,8 @@ struct bounds_t struct cff1_extents_param_t { - void init (const OT::cff1::accelerator_t *_cff) + cff1_extents_param_t (const OT::cff1::accelerator_t *_cff) : cff (_cff) { - path_open = false; - cff = _cff; bounds.init (); } @@ -322,7 +320,7 @@ struct cff1_extents_param_t void end_path () { path_open = false; } bool is_path_open () const { return path_open; } - bool path_open; + bool path_open = false; bounds_t bounds; const OT::cff1::accelerator_t *cff; @@ -395,12 +393,11 @@ bool _get_bounds (const OT::cff1::accelerator_t *cff, hb_codepoint_t glyph, boun if (unlikely (!cff->is_valid () || (glyph >= cff->num_glyphs))) return false; unsigned int fd = cff->fdSelect->get_fd (glyph); - cff1_cs_interpreter_t<cff1_cs_opset_extents_t, cff1_extents_param_t> interp; - const byte_str_t str = (*cff->charStrings)[glyph]; - interp.env.init (str, *cff, fd); - interp.env.set_in_seac (in_seac); - cff1_extents_param_t param; - param.init (cff); + const hb_ubytes_t str = (*cff->charStrings)[glyph]; + cff1_cs_interp_env_t env (str, *cff, fd); + env.set_in_seac (in_seac); + cff1_cs_interpreter_t<cff1_cs_opset_extents_t, cff1_extents_param_t> interp (env); + cff1_extents_param_t param (cff); if (unlikely (!interp.interpret (param))) return false; bounds = param.bounds; return true; @@ -541,10 +538,10 @@ bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoin if (unlikely (!cff->is_valid () || (glyph >= cff->num_glyphs))) return false; unsigned int fd = cff->fdSelect->get_fd (glyph); - cff1_cs_interpreter_t<cff1_cs_opset_path_t, cff1_path_param_t> interp; - const byte_str_t str = (*cff->charStrings)[glyph]; - interp.env.init (str, *cff, fd); - interp.env.set_in_seac (in_seac); + const hb_ubytes_t str = (*cff->charStrings)[glyph]; + cff1_cs_interp_env_t env (str, *cff, fd); + env.set_in_seac (in_seac); + cff1_cs_interpreter_t<cff1_cs_opset_path_t, cff1_path_param_t> interp (env); cff1_path_param_t param (cff, font, draw_session, delta); if (unlikely (!interp.interpret (param))) return false; @@ -566,18 +563,13 @@ bool OT::cff1::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, h struct get_seac_param_t { - void init (const OT::cff1::accelerator_t *_cff) - { - cff = _cff; - base = 0; - accent = 0; - } + get_seac_param_t (const OT::cff1::accelerator_t *_cff) : cff (_cff) {} bool has_seac () const { return base && accent; } const OT::cff1::accelerator_t *cff; - hb_codepoint_t base; - hb_codepoint_t accent; + hb_codepoint_t base = 0; + hb_codepoint_t accent = 0; }; struct cff1_cs_opset_seac_t : cff1_cs_opset_t<cff1_cs_opset_seac_t, get_seac_param_t> @@ -598,11 +590,10 @@ bool OT::cff1::accelerator_t::get_seac_components (hb_codepoint_t glyph, hb_code if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false; unsigned int fd = fdSelect->get_fd (glyph); - cff1_cs_interpreter_t<cff1_cs_opset_seac_t, get_seac_param_t> interp; - const byte_str_t str = (*charStrings)[glyph]; - interp.env.init (str, *this, fd); - get_seac_param_t param; - param.init (this); + const hb_ubytes_t str = (*charStrings)[glyph]; + cff1_cs_interp_env_t env (str, *this, fd); + cff1_cs_interpreter_t<cff1_cs_opset_seac_t, get_seac_param_t> interp (env); + get_seac_param_t param (this); if (unlikely (!interp.interpret (param))) return false; if (param.has_seac ()) diff --git a/thirdparty/harfbuzz/src/hb-ot-cff1-table.hh b/thirdparty/harfbuzz/src/hb-ot-cff1-table.hh index 542e3f4de3..4aa337f78b 100644 --- a/thirdparty/harfbuzz/src/hb-ot-cff1-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-cff1-table.hh @@ -318,14 +318,21 @@ struct Charset0 { return_trace (c->check_struct (this) && sids[num_glyphs - 1].sanitize (c)); } - hb_codepoint_t get_sid (hb_codepoint_t glyph) const + hb_codepoint_t get_sid (hb_codepoint_t glyph, unsigned num_glyphs) const { + if (unlikely (glyph >= num_glyphs)) return 0; if (glyph == 0) return 0; else return sids[glyph - 1]; } + void collect_glyph_to_sid_map (hb_map_t *mapping, unsigned int num_glyphs) const + { + for (hb_codepoint_t gid = 1; gid < num_glyphs; gid++) + mapping->set (gid, sids[gid - 1]); + } + hb_codepoint_t get_glyph (hb_codepoint_t sid, unsigned int num_glyphs) const { if (sid == 0) @@ -381,20 +388,38 @@ struct Charset1_2 { return_trace (true); } - hb_codepoint_t get_sid (hb_codepoint_t glyph) const + hb_codepoint_t get_sid (hb_codepoint_t glyph, unsigned num_glyphs) const { + if (unlikely (glyph >= num_glyphs)) return 0; if (glyph == 0) return 0; glyph--; for (unsigned int i = 0;; i++) { if (glyph <= ranges[i].nLeft) - return (hb_codepoint_t)ranges[i].first + glyph; + return (hb_codepoint_t) ranges[i].first + glyph; glyph -= (ranges[i].nLeft + 1); } return 0; } + void collect_glyph_to_sid_map (hb_map_t *mapping, unsigned int num_glyphs) const + { + hb_codepoint_t gid = 1; + if (gid >= num_glyphs) + return; + for (unsigned i = 0;; i++) + { + hb_codepoint_t sid = ranges[i].first; + unsigned count = ranges[i].nLeft + 1; + for (unsigned j = 0; j < count; j++) + mapping->set (gid++, sid++); + + if (gid >= num_glyphs) + break; + } + } + hb_codepoint_t get_glyph (hb_codepoint_t sid, unsigned int num_glyphs) const { if (sid == 0) return 0; @@ -521,16 +546,26 @@ struct Charset hb_codepoint_t get_sid (hb_codepoint_t glyph, unsigned int num_glyphs) const { - if (unlikely (glyph >= num_glyphs)) return 0; switch (format) { - case 0: return u.format0.get_sid (glyph); - case 1: return u.format1.get_sid (glyph); - case 2: return u.format2.get_sid (glyph); + case 0: return u.format0.get_sid (glyph, num_glyphs); + case 1: return u.format1.get_sid (glyph, num_glyphs); + case 2: return u.format2.get_sid (glyph, num_glyphs); default:return 0; } } + void collect_glyph_to_sid_map (hb_map_t *mapping, unsigned int num_glyphs) const + { + switch (format) + { + case 0: u.format0.collect_glyph_to_sid_map (mapping, num_glyphs); return; + case 1: u.format1.collect_glyph_to_sid_map (mapping, num_glyphs); return; + case 2: u.format2.collect_glyph_to_sid_map (mapping, num_glyphs); return; + default:return; + } + } + hb_codepoint_t get_glyph (hb_codepoint_t sid, unsigned int num_glyphs) const { switch (format) @@ -602,6 +637,8 @@ struct cff1_top_dict_interp_env_t : num_interp_env_t { cff1_top_dict_interp_env_t () : num_interp_env_t(), prev_offset(0), last_offset(0) {} + cff1_top_dict_interp_env_t (const hb_ubytes_t &bytes) + : num_interp_env_t(bytes), prev_offset(0), last_offset(0) {} unsigned int prev_offset; unsigned int last_offset; @@ -1024,11 +1061,10 @@ struct cff1 { fini (); return; } { /* parse top dict */ - const byte_str_t topDictStr = (*topDictIndex)[0]; + const hb_ubytes_t topDictStr = (*topDictIndex)[0]; if (unlikely (!topDictStr.sanitize (&sc))) { fini (); return; } - cff1_top_dict_interpreter_t top_interp; - top_interp.env.init (topDictStr); - topDict.init (); + cff1_top_dict_interp_env_t env (topDictStr); + cff1_top_dict_interpreter_t top_interp (env); if (unlikely (!top_interp.interpret (topDict))) { fini (); return; } } @@ -1098,20 +1134,21 @@ struct cff1 { for (unsigned int i = 0; i < fdCount; i++) { - byte_str_t fontDictStr = (*fdArray)[i]; + hb_ubytes_t fontDictStr = (*fdArray)[i]; if (unlikely (!fontDictStr.sanitize (&sc))) { fini (); return; } cff1_font_dict_values_t *font; - cff1_font_dict_interpreter_t font_interp; - font_interp.env.init (fontDictStr); + cff1_top_dict_interp_env_t env (fontDictStr); + cff1_font_dict_interpreter_t font_interp (env); font = fontDicts.push (); - if (unlikely (font == &Crap (cff1_font_dict_values_t))) { fini (); return; } + if (unlikely (fontDicts.in_error ())) { fini (); return; } + font->init (); if (unlikely (!font_interp.interpret (*font))) { fini (); return; } PRIVDICTVAL *priv = &privateDicts[i]; - const byte_str_t privDictStr (StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset), font->privateDictInfo.size); + const hb_ubytes_t privDictStr = StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size); if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; } - dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> priv_interp; - priv_interp.env.init (privDictStr); + num_interp_env_t env2 (privDictStr); + dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> priv_interp (env2); priv->init (); if (unlikely (!priv_interp.interpret (*priv))) { fini (); return; } @@ -1126,10 +1163,10 @@ struct cff1 cff1_top_dict_values_t *font = &topDict; PRIVDICTVAL *priv = &privateDicts[0]; - const byte_str_t privDictStr (StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset), font->privateDictInfo.size); + const hb_ubytes_t privDictStr = StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size); if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; } - dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> priv_interp; - priv_interp.env.init (privDictStr); + num_interp_env_t env (privDictStr); + dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> priv_interp (env); priv->init (); if (unlikely (!priv_interp.interpret (*priv))) { fini (); return; } @@ -1194,6 +1231,19 @@ struct cff1 } } + hb_map_t *create_glyph_to_sid_map () const + { + if (charset != &Null (Charset)) + { + hb_map_t *mapping = hb_map_create (); + mapping->set (0, 0); + charset->collect_glyph_to_sid_map (mapping, num_glyphs); + return mapping; + } + else + return nullptr; + } + hb_codepoint_t glyph_to_sid (hb_codepoint_t glyph) const { if (charset != &Null (Charset)) @@ -1274,30 +1324,20 @@ struct cff1 { SUPER::init (face); + glyph_names.set_relaxed (nullptr); + if (!is_valid ()) return; if (is_CID ()) return; - /* fill glyph_names */ - for (hb_codepoint_t gid = 0; gid < num_glyphs; gid++) - { - hb_codepoint_t sid = glyph_to_sid (gid); - gname_t gname; - gname.sid = sid; - if (sid < cff1_std_strings_length) - gname.name = cff1_std_strings (sid); - else - { - byte_str_t ustr = (*stringIndex)[sid - cff1_std_strings_length]; - gname.name = hb_bytes_t ((const char*)ustr.arrayZ, ustr.length); - } - if (unlikely (!gname.name.arrayZ)) { fini (); return; } - glyph_names.push (gname); - } - glyph_names.qsort (); } ~accelerator_t () { - glyph_names.fini (); + hb_sorted_vector_t<gname_t> *names = glyph_names.get_relaxed (); + if (names) + { + names->fini (); + hb_free (names); + } SUPER::fini (); } @@ -1305,9 +1345,9 @@ struct cff1 bool get_glyph_name (hb_codepoint_t glyph, char *buf, unsigned int buf_len) const { - if (!buf) return true; if (unlikely (!is_valid ())) return false; if (is_CID()) return false; + if (unlikely (!buf_len)) return true; hb_codepoint_t sid = glyph_to_sid (glyph); const char *str; size_t str_len; @@ -1319,7 +1359,7 @@ struct cff1 } else { - byte_str_t ubyte_str = (*stringIndex)[sid - cff1_std_strings_length]; + hb_ubytes_t ubyte_str = (*stringIndex)[sid - cff1_std_strings_length]; str = (const char *)ubyte_str.arrayZ; str_len = ubyte_str.length; } @@ -1333,11 +1373,53 @@ struct cff1 bool get_glyph_from_name (const char *name, int len, hb_codepoint_t *glyph) const { + if (unlikely (!is_valid ())) return false; + if (is_CID()) return false; if (len < 0) len = strlen (name); if (unlikely (!len)) return false; + retry: + hb_sorted_vector_t<gname_t> *names = glyph_names.get (); + if (unlikely (!names)) + { + names = (hb_sorted_vector_t<gname_t> *) hb_calloc (sizeof (hb_sorted_vector_t<gname_t>), 1); + if (likely (names)) + { + names->init (); + /* TODO */ + + /* fill glyph names */ + for (hb_codepoint_t gid = 0; gid < num_glyphs; gid++) + { + hb_codepoint_t sid = glyph_to_sid (gid); + gname_t gname; + gname.sid = sid; + if (sid < cff1_std_strings_length) + gname.name = cff1_std_strings (sid); + else + { + hb_ubytes_t ustr = (*stringIndex)[sid - cff1_std_strings_length]; + gname.name = hb_bytes_t ((const char*) ustr.arrayZ, ustr.length); + } + if (unlikely (!gname.name.arrayZ)) + gname.name = hb_bytes_t ("", 0); /* To avoid nullptr. */ + names->push (gname); + } + names->qsort (); + } + if (unlikely (!glyph_names.cmpexch (nullptr, names))) + { + if (names) + { + names->fini (); + hb_free (names); + } + goto retry; + } + } + gname_t key = { hb_bytes_t (name, len), 0 }; - const gname_t *gname = glyph_names.bsearch (key); + const gname_t *gname = names ? names->bsearch (key) : nullptr; if (!gname) return false; hb_codepoint_t gid = sid_to_glyph (gname->sid); if (!gid && gname->sid) return false; @@ -1359,7 +1441,7 @@ struct cff1 { const gname_t *a = (const gname_t *)a_; const gname_t *b = (const gname_t *)b_; - int minlen = hb_min (a->name.length, b->name.length); + unsigned minlen = hb_min (a->name.length, b->name.length); int ret = strncmp (a->name.arrayZ, b->name.arrayZ, minlen); if (ret) return ret; return a->name.length - b->name.length; @@ -1368,7 +1450,7 @@ struct cff1 int cmp (const gname_t &a) const { return cmp (&a, this); } }; - hb_sorted_vector_t<gname_t> glyph_names; + mutable hb_atomic_ptr_t<hb_sorted_vector_t<gname_t>> glyph_names; typedef accelerator_templ_t<cff1_private_dict_opset_t, cff1_private_dict_values_t> SUPER; }; diff --git a/thirdparty/harfbuzz/src/hb-ot-cff2-table.cc b/thirdparty/harfbuzz/src/hb-ot-cff2-table.cc index 817fe064ce..50c76daf93 100644 --- a/thirdparty/harfbuzz/src/hb-ot-cff2-table.cc +++ b/thirdparty/harfbuzz/src/hb-ot-cff2-table.cc @@ -36,9 +36,8 @@ using namespace CFF; struct cff2_extents_param_t { - void init () + cff2_extents_param_t () { - path_open = false; min_x.set_int (INT_MAX); min_y.set_int (INT_MAX); max_x.set_int (INT_MIN); @@ -57,22 +56,22 @@ struct cff2_extents_param_t if (pt.y > max_y) max_y = pt.y; } - bool path_open; + bool path_open = false; number_t min_x; number_t min_y; number_t max_x; number_t max_y; }; -struct cff2_path_procs_extents_t : path_procs_t<cff2_path_procs_extents_t, cff2_cs_interp_env_t, cff2_extents_param_t> +struct cff2_path_procs_extents_t : path_procs_t<cff2_path_procs_extents_t, cff2_cs_interp_env_t<number_t>, cff2_extents_param_t> { - static void moveto (cff2_cs_interp_env_t &env, cff2_extents_param_t& param, const point_t &pt) + static void moveto (cff2_cs_interp_env_t<number_t> &env, cff2_extents_param_t& param, const point_t &pt) { param.end_path (); env.moveto (pt); } - static void line (cff2_cs_interp_env_t &env, cff2_extents_param_t& param, const point_t &pt1) + static void line (cff2_cs_interp_env_t<number_t> &env, cff2_extents_param_t& param, const point_t &pt1) { if (!param.is_path_open ()) { @@ -83,7 +82,7 @@ struct cff2_path_procs_extents_t : path_procs_t<cff2_path_procs_extents_t, cff2_ param.update_bounds (env.get_pt ()); } - static void curve (cff2_cs_interp_env_t &env, cff2_extents_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3) + static void curve (cff2_cs_interp_env_t<number_t> &env, cff2_extents_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3) { if (!param.is_path_open ()) { @@ -98,7 +97,7 @@ struct cff2_path_procs_extents_t : path_procs_t<cff2_path_procs_extents_t, cff2_ } }; -struct cff2_cs_opset_extents_t : cff2_cs_opset_t<cff2_cs_opset_extents_t, cff2_extents_param_t, cff2_path_procs_extents_t> {}; +struct cff2_cs_opset_extents_t : cff2_cs_opset_t<cff2_cs_opset_extents_t, cff2_extents_param_t, number_t, cff2_path_procs_extents_t> {}; bool OT::cff2::accelerator_t::get_extents (hb_font_t *font, hb_codepoint_t glyph, @@ -112,11 +111,10 @@ bool OT::cff2::accelerator_t::get_extents (hb_font_t *font, if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false; unsigned int fd = fdSelect->get_fd (glyph); - cff2_cs_interpreter_t<cff2_cs_opset_extents_t, cff2_extents_param_t> interp; - const byte_str_t str = (*charStrings)[glyph]; - interp.env.init (str, *this, fd, font->coords, font->num_coords); + const hb_ubytes_t str = (*charStrings)[glyph]; + cff2_cs_interp_env_t<number_t> env (str, *this, fd, font->coords, font->num_coords); + cff2_cs_interpreter_t<cff2_cs_opset_extents_t, cff2_extents_param_t, number_t> interp (env); cff2_extents_param_t param; - param.init (); if (unlikely (!interp.interpret (param))) return false; if (param.min_x >= param.max_x) @@ -169,28 +167,28 @@ struct cff2_path_param_t hb_font_t *font; }; -struct cff2_path_procs_path_t : path_procs_t<cff2_path_procs_path_t, cff2_cs_interp_env_t, cff2_path_param_t> +struct cff2_path_procs_path_t : path_procs_t<cff2_path_procs_path_t, cff2_cs_interp_env_t<number_t>, cff2_path_param_t> { - static void moveto (cff2_cs_interp_env_t &env, cff2_path_param_t& param, const point_t &pt) + static void moveto (cff2_cs_interp_env_t<number_t> &env, cff2_path_param_t& param, const point_t &pt) { param.move_to (pt); env.moveto (pt); } - static void line (cff2_cs_interp_env_t &env, cff2_path_param_t& param, const point_t &pt1) + static void line (cff2_cs_interp_env_t<number_t> &env, cff2_path_param_t& param, const point_t &pt1) { param.line_to (pt1); env.moveto (pt1); } - static void curve (cff2_cs_interp_env_t &env, cff2_path_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3) + static void curve (cff2_cs_interp_env_t<number_t> &env, cff2_path_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3) { param.cubic_to (pt1, pt2, pt3); env.moveto (pt3); } }; -struct cff2_cs_opset_path_t : cff2_cs_opset_t<cff2_cs_opset_path_t, cff2_path_param_t, cff2_path_procs_path_t> {}; +struct cff2_cs_opset_path_t : cff2_cs_opset_t<cff2_cs_opset_path_t, cff2_path_param_t, number_t, cff2_path_procs_path_t> {}; bool OT::cff2::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const { @@ -202,9 +200,9 @@ bool OT::cff2::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, h if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false; unsigned int fd = fdSelect->get_fd (glyph); - cff2_cs_interpreter_t<cff2_cs_opset_path_t, cff2_path_param_t> interp; - const byte_str_t str = (*charStrings)[glyph]; - interp.env.init (str, *this, fd, font->coords, font->num_coords); + const hb_ubytes_t str = (*charStrings)[glyph]; + cff2_cs_interp_env_t<number_t> env (str, *this, fd, font->coords, font->num_coords); + cff2_cs_interpreter_t<cff2_cs_opset_path_t, cff2_path_param_t, number_t> interp (env); cff2_path_param_t param (font, draw_session); if (unlikely (!interp.interpret (param))) return false; return true; diff --git a/thirdparty/harfbuzz/src/hb-ot-cff2-table.hh b/thirdparty/harfbuzz/src/hb-ot-cff2-table.hh index b77e7f53fa..746160dc8e 100644 --- a/thirdparty/harfbuzz/src/hb-ot-cff2-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-cff2-table.hh @@ -247,12 +247,8 @@ typedef cff2_private_dict_values_base_t<num_dict_val_t> cff2_private_dict_values struct cff2_priv_dict_interp_env_t : num_interp_env_t { - void init (const byte_str_t &str) - { - num_interp_env_t::init (str); - ivs = 0; - seen_vsindex = false; - } + cff2_priv_dict_interp_env_t (const hb_ubytes_t &str) : + num_interp_env_t (str) {} void process_vsindex () { @@ -267,8 +263,8 @@ struct cff2_priv_dict_interp_env_t : num_interp_env_t void set_ivs (unsigned int ivs_) { ivs = ivs_; } protected: - unsigned int ivs; - bool seen_vsindex; + unsigned int ivs = 0; + bool seen_vsindex = false; }; struct cff2_private_dict_opset_t : dict_opset_t @@ -415,10 +411,10 @@ struct cff2 goto fail; { /* parse top dict */ - byte_str_t topDictStr (cff2 + cff2->topDict, cff2->topDictSize); + hb_ubytes_t topDictStr = (cff2 + cff2->topDict).as_ubytes (cff2->topDictSize); if (unlikely (!topDictStr.sanitize (&sc))) goto fail; - cff2_top_dict_interpreter_t top_interp; - top_interp.env.init (topDictStr); + num_interp_env_t env (topDictStr); + cff2_top_dict_interpreter_t top_interp (env); topDict.init (); if (unlikely (!top_interp.interpret (topDict))) goto fail; } @@ -447,20 +443,20 @@ struct cff2 /* parse font dicts and gather private dicts */ for (unsigned int i = 0; i < fdCount; i++) { - const byte_str_t fontDictStr = (*fdArray)[i]; + const hb_ubytes_t fontDictStr = (*fdArray)[i]; if (unlikely (!fontDictStr.sanitize (&sc))) goto fail; cff2_font_dict_values_t *font; - cff2_font_dict_interpreter_t font_interp; - font_interp.env.init (fontDictStr); + num_interp_env_t env (fontDictStr); + cff2_font_dict_interpreter_t font_interp (env); font = fontDicts.push (); if (unlikely (font == &Crap (cff2_font_dict_values_t))) goto fail; font->init (); if (unlikely (!font_interp.interpret (*font))) goto fail; - const byte_str_t privDictStr (StructAtOffsetOrNull<UnsizedByteStr> (cff2, font->privateDictInfo.offset), font->privateDictInfo.size); + const hb_ubytes_t privDictStr = StructAtOffsetOrNull<UnsizedByteStr> (cff2, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size); if (unlikely (!privDictStr.sanitize (&sc))) goto fail; - dict_interpreter_t<PRIVOPSET, PRIVDICTVAL, cff2_priv_dict_interp_env_t> priv_interp; - priv_interp.env.init(privDictStr); + cff2_priv_dict_interp_env_t env2 (privDictStr); + dict_interpreter_t<PRIVOPSET, PRIVDICTVAL, cff2_priv_dict_interp_env_t> priv_interp (env2); privateDicts[i].init (); if (unlikely (!priv_interp.interpret (privateDicts[i]))) goto fail; diff --git a/thirdparty/harfbuzz/src/hb-ot-cmap-table.hh b/thirdparty/harfbuzz/src/hb-ot-cmap-table.hh index a8747ee5a1..09c9fe93f3 100644 --- a/thirdparty/harfbuzz/src/hb-ot-cmap-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-cmap-table.hh @@ -27,6 +27,8 @@ #ifndef HB_OT_CMAP_TABLE_HH #define HB_OT_CMAP_TABLE_HH +#include "hb-ot-os2-table.hh" +#include "hb-ot-shaper-arabic-pua.hh" #include "hb-open-type.hh" #include "hb-set.hh" @@ -44,7 +46,7 @@ struct CmapSubtableFormat0 bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const { hb_codepoint_t gid = codepoint < 256 ? glyphIdArray[codepoint] : 0; - if (!gid) + if (unlikely (!gid)) return false; *glyph = gid; return true; @@ -109,22 +111,26 @@ struct CmapSubtableFormat4 while (it) { // Start a new range - start_cp = (*it).first; - prev_run_start_cp = (*it).first; - run_start_cp = (*it).first; - end_cp = (*it).first; - last_gid = (*it).second; - run_length = 1; - prev_delta = 0; - - delta = (*it).second - (*it).first; + { + const auto& pair = *it; + start_cp = pair.first; + prev_run_start_cp = start_cp; + run_start_cp = start_cp; + end_cp = start_cp; + last_gid = pair.second; + run_length = 1; + prev_delta = 0; + } + + delta = last_gid - start_cp; mode = FIRST_SUB_RANGE; it++; while (it) { // Process range - hb_codepoint_t next_cp = (*it).first; - hb_codepoint_t next_gid = (*it).second; + const auto& pair = *it; + hb_codepoint_t next_cp = pair.first; + hb_codepoint_t next_gid = pair.second; if (next_cp != end_cp + 1) { // Current range is over, stop processing. break; @@ -282,23 +288,22 @@ struct CmapSubtableFormat4 } template<typename Iterator, - hb_requires (hb_is_iterator (Iterator))> + hb_requires (hb_is_iterator (Iterator))> HBUINT16* serialize_rangeoffset_glyid (hb_serialize_context_t *c, - Iterator it, + Iterator it, HBUINT16 *endCode, HBUINT16 *startCode, HBINT16 *idDelta, unsigned segcount) { - hb_hashmap_t<hb_codepoint_t, hb_codepoint_t> cp_to_gid; - + it | hb_sink (cp_to_gid); + hb_map_t cp_to_gid { it }; HBUINT16 *idRangeOffset = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount); if (unlikely (!c->check_success (idRangeOffset))) return nullptr; if (unlikely ((char *)idRangeOffset - (char *)idDelta != (int) segcount * (int) HBINT16::static_size)) return nullptr; for (unsigned i : + hb_range (segcount) - | hb_filter ([&] (const unsigned _) { return idDelta[_] == 0; })) + | hb_filter ([&] (const unsigned _) { return idDelta[_] == 0; })) { idRangeOffset[i] = 2 * (c->start_embed<HBUINT16> () - idRangeOffset - i); for (hb_codepoint_t cp = startCode[i]; cp <= endCode[i]; cp++) @@ -323,22 +328,31 @@ struct CmapSubtableFormat4 { return _.first <= 0xFFFF; }) ; - if (format4_iter.len () == 0) return; + if (!format4_iter) return; unsigned table_initpos = c->length (); if (unlikely (!c->extend_min (this))) return; this->format = 4; + hb_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> cp_to_gid { + format4_iter + }; + //serialize endCode[], startCode[], idDelta[] HBUINT16* endCode = c->start_embed<HBUINT16> (); - unsigned segcount = serialize_find_segcount (format4_iter); - if (unlikely (!serialize_start_end_delta_arrays (c, format4_iter, segcount))) + unsigned segcount = serialize_find_segcount (cp_to_gid.iter()); + if (unlikely (!serialize_start_end_delta_arrays (c, cp_to_gid.iter(), segcount))) return; HBUINT16 *startCode = endCode + segcount + 1; HBINT16 *idDelta = ((HBINT16*)startCode) + segcount; - HBUINT16 *idRangeOffset = serialize_rangeoffset_glyid (c, format4_iter, endCode, startCode, idDelta, segcount); + HBUINT16 *idRangeOffset = serialize_rangeoffset_glyid (c, + cp_to_gid.iter (), + endCode, + startCode, + idDelta, + segcount); if (unlikely (!c->check_success (idRangeOffset))) return; this->length = c->length () - table_initpos; @@ -401,7 +415,7 @@ struct CmapSubtableFormat4 2, _hb_cmp_method<hb_codepoint_t, CustomRange, unsigned>, this->segCount + 1); - if (!found) + if (unlikely (!found)) return false; unsigned int i = found - endCount; @@ -421,7 +435,7 @@ struct CmapSubtableFormat4 gid += this->idDelta[i]; } gid &= 0xFFFFu; - if (!gid) + if (unlikely (!gid)) return false; *glyph = gid; return true; @@ -440,14 +454,14 @@ struct CmapSubtableFormat4 hb_codepoint_t start = this->startCount[i]; hb_codepoint_t end = this->endCount[i]; unsigned int rangeOffset = this->idRangeOffset[i]; + out->add_range(start, end); if (rangeOffset == 0) { for (hb_codepoint_t codepoint = start; codepoint <= end; codepoint++) { hb_codepoint_t gid = (codepoint + this->idDelta[i]) & 0xFFFFu; if (unlikely (!gid)) - continue; - out->add (codepoint); + out->del(codepoint); } } else @@ -456,11 +470,13 @@ struct CmapSubtableFormat4 { unsigned int index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount; if (unlikely (index >= this->glyphIdArrayLength)) + { + out->del_range (codepoint, end); break; + } hb_codepoint_t gid = this->glyphIdArray[index]; if (unlikely (!gid)) - continue; - out->add (codepoint); + out->del(codepoint); } } } @@ -469,6 +485,8 @@ struct CmapSubtableFormat4 void collect_mapping (hb_set_t *unicodes, /* OUT */ hb_map_t *mapping /* OUT */) const { + // TODO(grieger): optimize similar to collect_unicodes + // (ie. use add_range()) unsigned count = this->segCount; if (count && this->startCount[count - 1] == 0xFFFFu) count--; /* Skip sentinel segment. */ @@ -620,7 +638,7 @@ struct CmapSubtableTrimmed { /* Rely on our implicit array bound-checking. */ hb_codepoint_t gid = glyphIdArray[codepoint - startCharCode]; - if (!gid) + if (unlikely (!gid)) return false; *glyph = gid; return true; @@ -674,7 +692,7 @@ struct CmapSubtableTrimmed }; struct CmapSubtableFormat6 : CmapSubtableTrimmed<HBUINT16> {}; -struct CmapSubtableFormat10 : CmapSubtableTrimmed<HBUINT32 > {}; +struct CmapSubtableFormat10 : CmapSubtableTrimmed<HBUINT32> {}; template <typename T> struct CmapSubtableLongSegmented @@ -684,7 +702,7 @@ struct CmapSubtableLongSegmented bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const { hb_codepoint_t gid = T::group_get_glyph (groups.bsearch (codepoint), codepoint); - if (!gid) + if (unlikely (!gid)) return false; *glyph = gid; return true; @@ -722,11 +740,19 @@ struct CmapSubtableLongSegmented hb_map_t *mapping, /* OUT */ unsigned num_glyphs) const { + hb_codepoint_t last_end = 0; for (unsigned i = 0; i < this->groups.len; i++) { hb_codepoint_t start = this->groups[i].startCharCode; hb_codepoint_t end = hb_min ((hb_codepoint_t) this->groups[i].endCharCode, (hb_codepoint_t) HB_UNICODE_MAX); + if (unlikely (start > end || start < last_end)) { + // Range is not in order and is invalid, skip it. + continue; + } + last_end = end; + + hb_codepoint_t gid = this->groups[i].glyphID; if (!gid) { @@ -778,16 +804,16 @@ struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12> void serialize (hb_serialize_context_t *c, Iterator it) { - if (it.len () == 0) return; + if (!it) return; unsigned table_initpos = c->length (); if (unlikely (!c->extend_min (this))) return; - hb_codepoint_t startCharCode = 0xFFFF, endCharCode = 0xFFFF; + hb_codepoint_t startCharCode = (hb_codepoint_t) -1, endCharCode = (hb_codepoint_t) -1; hb_codepoint_t glyphID = 0; for (const auto& _ : +it) { - if (startCharCode == 0xFFFF) + if (startCharCode == (hb_codepoint_t) -1) { startCharCode = _.first; endCharCode = _.first; @@ -818,7 +844,7 @@ struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12> this->format = 12; this->reserved = 0; this->length = c->length () - table_initpos; - this->groups.len = (this->length - min_size)/CmapSubtableLongGroup::static_size; + this->groups.len = (this->length - min_size) / CmapSubtableLongGroup::static_size; } static size_t get_sub_table_size (const hb_sorted_vector_t<CmapSubtableLongGroup> &groups_data) @@ -1448,6 +1474,51 @@ struct EncodingRecord DEFINE_SIZE_STATIC (8); }; +struct SubtableUnicodesCache { + + private: + const void* base; + hb_hashmap_t<intptr_t, hb::unique_ptr<hb_set_t>> cached_unicodes; + + public: + SubtableUnicodesCache(const void* cmap_base) + : base(cmap_base), cached_unicodes() {} + + hb_set_t* set_for (const EncodingRecord* record) + { + if (!cached_unicodes.has ((intptr_t) record)) + { + hb_set_t *s = hb_set_create (); + if (unlikely (s->in_error ())) + return hb_set_get_empty (); + + (base+record->subtable).collect_unicodes (s); + + if (unlikely (!cached_unicodes.set ((intptr_t) record, hb::unique_ptr<hb_set_t> {s}))) + return hb_set_get_empty (); + + return s; + } + return cached_unicodes.get ((intptr_t) record); + } + +}; + +static inline uint_fast16_t +_hb_symbol_pua_map (unsigned codepoint) +{ + if (codepoint <= 0x00FFu) + { + /* For symbol-encoded OpenType fonts, we duplicate the + * U+F000..F0FF range at U+0000..U+00FF. That's what + * Windows seems to do, and that's hinted about at: + * https://docs.microsoft.com/en-us/typography/opentype/spec/recom + * under "Non-Standard (Symbol) Fonts". */ + return 0xF000u + codepoint; + } + return 0; +} + struct cmap { static constexpr hb_tag_t tableTag = HB_OT_TAG_cmap; @@ -1467,6 +1538,7 @@ struct cmap unsigned format4objidx = 0, format12objidx = 0, format14objidx = 0; auto snap = c->snapshot (); + SubtableUnicodesCache unicodes_cache (base); for (const EncodingRecord& _ : encodingrec_iter) { if (c->in_error ()) @@ -1475,12 +1547,11 @@ struct cmap unsigned format = (base+_.subtable).u.format; if (format != 4 && format != 12 && format != 14) continue; - hb_set_t unicodes_set; - (base+_.subtable).collect_unicodes (&unicodes_set); + hb_set_t* unicodes_set = unicodes_cache.set_for (&_); if (!drop_format_4 && format == 4) { - c->copy (_, + it | hb_filter (unicodes_set, hb_first), 4u, base, plan, &format4objidx); + c->copy (_, + it | hb_filter (*unicodes_set, hb_first), 4u, base, plan, &format4objidx); if (c->in_error () && c->only_overflow ()) { // cmap4 overflowed, reset and retry serialization without format 4 subtables. @@ -1495,8 +1566,8 @@ struct cmap else if (format == 12) { - if (_can_drop (_, unicodes_set, base, + it | hb_map (hb_first), encodingrec_iter)) continue; - c->copy (_, + it | hb_filter (unicodes_set, hb_first), 12u, base, plan, &format12objidx); + if (_can_drop (_, *unicodes_set, base, unicodes_cache, + it | hb_map (hb_first), encodingrec_iter)) continue; + c->copy (_, + it | hb_filter (*unicodes_set, hb_first), 12u, base, plan, &format12objidx); } else if (format == 14) c->copy (_, it, 14u, base, plan, &format14objidx); } @@ -1514,6 +1585,7 @@ struct cmap bool _can_drop (const EncodingRecord& cmap12, const hb_set_t& cmap12_unicodes, const void* base, + SubtableUnicodesCache& unicodes_cache, Iterator subset_unicodes, EncodingRecordIterator encoding_records) { @@ -1544,11 +1616,10 @@ struct cmap || (base+_.subtable).get_language() != target_language) continue; - hb_set_t sibling_unicodes; - (base+_.subtable).collect_unicodes (&sibling_unicodes); + hb_set_t* sibling_unicodes = unicodes_cache.set_for (&_); auto cmap12 = + subset_unicodes | hb_filter (cmap12_unicodes); - auto sibling = + subset_unicodes | hb_filter (sibling_unicodes); + auto sibling = + subset_unicodes | hb_filter (*sibling_unicodes); for (; cmap12 && sibling; cmap12++, sibling++) { unsigned a = *cmap12; @@ -1616,13 +1687,7 @@ struct cmap if (unlikely (has_format12 && (!unicode_ucs4 && !ms_ucs4))) return_trace (false); auto it = - + hb_iter (c->plan->unicodes) - | hb_map ([&] (hb_codepoint_t _) - { - hb_codepoint_t new_gid = HB_MAP_VALUE_INVALID; - c->plan->new_gid_for_codepoint (_, &new_gid); - return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (_, new_gid); - }) + + c->plan->unicode_to_new_gid_list.iter () | hb_filter ([&] (const hb_pair_t<hb_codepoint_t, hb_codepoint_t> _) { return (_.second != HB_MAP_VALUE_INVALID); }) ; @@ -1677,7 +1742,24 @@ struct cmap this->get_glyph_data = subtable; if (unlikely (symbol)) - this->get_glyph_funcZ = get_glyph_from_symbol<CmapSubtable>; + { + switch ((unsigned) face->table.OS2->get_font_page ()) { + case OS2::font_page_t::FONT_PAGE_NONE: + this->get_glyph_funcZ = get_glyph_from_symbol<CmapSubtable, _hb_symbol_pua_map>; + break; +#ifndef HB_NO_OT_SHAPER_ARABIC_FALLBACK + case OS2::font_page_t::FONT_PAGE_SIMP_ARABIC: + this->get_glyph_funcZ = get_glyph_from_symbol<CmapSubtable, _hb_arabic_pua_simp_map>; + break; + case OS2::font_page_t::FONT_PAGE_TRAD_ARABIC: + this->get_glyph_funcZ = get_glyph_from_symbol<CmapSubtable, _hb_arabic_pua_trad_map>; + break; +#endif + default: + this->get_glyph_funcZ = get_glyph_from<CmapSubtable>; + break; + } + } else { switch (subtable->u.format) { @@ -1759,6 +1841,7 @@ struct cmap typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph); + typedef uint_fast16_t (*hb_pua_remap_func_t) (unsigned); template <typename Type> HB_INTERNAL static bool get_glyph_from (const void *obj, @@ -1769,7 +1852,7 @@ struct cmap return typed_obj->get_glyph (codepoint, glyph); } - template <typename Type> + template <typename Type, hb_pua_remap_func_t remap> HB_INTERNAL static bool get_glyph_from_symbol (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph) @@ -1778,15 +1861,8 @@ struct cmap if (likely (typed_obj->get_glyph (codepoint, glyph))) return true; - if (codepoint <= 0x00FFu) - { - /* For symbol-encoded OpenType fonts, we duplicate the - * U+F000..F0FF range at U+0000..U+00FF. That's what - * Windows seems to do, and that's hinted about at: - * https://docs.microsoft.com/en-us/typography/opentype/spec/recom - * under "Non-Standard (Symbol) Fonts". */ - return typed_obj->get_glyph (0xF000u + codepoint, glyph); - } + if (hb_codepoint_t c = remap (codepoint)) + return typed_obj->get_glyph (c, glyph); return false; } diff --git a/thirdparty/harfbuzz/src/hb-ot-color-cpal-table.hh b/thirdparty/harfbuzz/src/hb-ot-color-cpal-table.hh index a9deeba9a7..bcab77f79d 100644 --- a/thirdparty/harfbuzz/src/hb-ot-color-cpal-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-color-cpal-table.hh @@ -97,9 +97,10 @@ struct CPALV1Tail c->push (); for (const auto _ : colorLabels) { - if (!color_index_map->has (_)) continue; + const hb_codepoint_t *v; + if (!color_index_map->has (_, &v)) continue; NameID new_color_idx; - new_color_idx = color_index_map->get (_); + new_color_idx = *v; if (!c->copy<NameID> (new_color_idx)) { c->pop_discard (); @@ -197,30 +198,38 @@ struct CPAL public: bool serialize (hb_serialize_context_t *c, - const hb_array_t<const BGRAColor> &color_records, const hb_array_t<const HBUINT16> &color_record_indices, - const hb_map_t &color_record_index_map, - const hb_set_t &retained_color_record_indices) const + const hb_array_t<const BGRAColor> &color_records, + const hb_vector_t<unsigned>& first_color_index_for_layer, + const hb_map_t& first_color_to_layer_index, + const hb_set_t &retained_color_indices) const { TRACE_SERIALIZE (this); + // TODO(grieger): limit total final size. + for (const auto idx : color_record_indices) { + hb_codepoint_t layer_index = first_color_to_layer_index[idx]; + HBUINT16 new_idx; - if (idx == 0) new_idx = 0; - else new_idx = color_record_index_map.get (idx); + new_idx = layer_index * retained_color_indices.get_population (); if (!c->copy<HBUINT16> (new_idx)) return_trace (false); } c->push (); - for (const auto _ : retained_color_record_indices.iter ()) + for (unsigned first_color_index : first_color_index_for_layer) { - if (!c->copy<BGRAColor> (color_records[_])) + for (hb_codepoint_t color_index : retained_color_indices) { - c->pop_discard (); - return_trace (false); + if (!c->copy<BGRAColor> (color_records[first_color_index + color_index])) + { + c->pop_discard (); + return_trace (false); + } } } + c->add_link (colorRecordsZ, c->pop_pack ()); return_trace (true); } @@ -228,6 +237,8 @@ struct CPAL bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); + if (!numPalettes) return_trace (false); + const hb_map_t *color_index_map = c->plan->colr_palettes; if (color_index_map->is_empty ()) return_trace (false); @@ -242,30 +253,34 @@ struct CPAL auto *out = c->serializer->start_embed (*this); if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + out->version = version; out->numColors = retained_color_indices.get_population (); out->numPalettes = numPalettes; - const hb_array_t<const HBUINT16> colorRecordIndices = colorRecordIndicesZ.as_array (numPalettes); - hb_map_t color_record_index_map; - hb_set_t retained_color_record_indices; + hb_vector_t<unsigned> first_color_index_for_layer; + hb_map_t first_color_to_layer_index; - unsigned record_count = 0; + const hb_array_t<const HBUINT16> colorRecordIndices = colorRecordIndicesZ.as_array (numPalettes); for (const auto first_color_record_idx : colorRecordIndices) { - for (unsigned retained_color_idx : retained_color_indices.iter ()) - { - unsigned color_record_idx = first_color_record_idx + retained_color_idx; - if (color_record_index_map.has (color_record_idx)) continue; - color_record_index_map.set (color_record_idx, record_count); - retained_color_record_indices.add (color_record_idx); - record_count++; - } + if (first_color_to_layer_index.has (first_color_record_idx)) continue; + + first_color_index_for_layer.push (first_color_record_idx); + first_color_to_layer_index.set (first_color_record_idx, + first_color_index_for_layer.length - 1); } - out->numColorRecords = record_count; + out->numColorRecords = first_color_index_for_layer.length + * retained_color_indices.get_population (); + const hb_array_t<const BGRAColor> color_records = (this+colorRecordsZ).as_array (numColorRecords); - if (!out->serialize (c->serializer, color_records, colorRecordIndices, color_record_index_map, retained_color_record_indices)) + if (!out->serialize (c->serializer, + colorRecordIndices, + color_records, + first_color_index_for_layer, + first_color_to_layer_index, + retained_color_indices)) return_trace (false); if (version == 1) diff --git a/thirdparty/harfbuzz/src/hb-ot-color-sbix-table.hh b/thirdparty/harfbuzz/src/hb-ot-color-sbix-table.hh index 9741ebd450..d0e2235fb2 100644 --- a/thirdparty/harfbuzz/src/hb-ot-color-sbix-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-color-sbix-table.hh @@ -298,6 +298,12 @@ struct sbix const PNGHeader &png = *blob->as<PNGHeader>(); + if (png.IHDR.height >= 65536 || png.IHDR.width >= 65536) + { + hb_blob_destroy (blob); + return false; + } + extents->x_bearing = x_offset; extents->y_bearing = png.IHDR.height + y_offset; extents->width = png.IHDR.width; diff --git a/thirdparty/harfbuzz/src/hb-ot-font.cc b/thirdparty/harfbuzz/src/hb-ot-font.cc index 0f44ee4d5f..af1bc86d48 100644 --- a/thirdparty/harfbuzz/src/hb-ot-font.cc +++ b/thirdparty/harfbuzz/src/hb-ot-font.cc @@ -30,6 +30,7 @@ #include "hb-ot.h" +#include "hb-cache.hh" #include "hb-font.hh" #include "hb-machinery.hh" #include "hb-ot-face.hh" @@ -58,6 +59,41 @@ * never need to call these functions directly. **/ +struct hb_ot_font_t +{ + const hb_ot_face_t *ot_face; + + /* h_advance caching */ + mutable hb_atomic_int_t cached_coords_serial; + mutable hb_atomic_ptr_t<hb_advance_cache_t> advance_cache; +}; + +static hb_ot_font_t * +_hb_ot_font_create (hb_font_t *font) +{ + hb_ot_font_t *ot_font = (hb_ot_font_t *) hb_calloc (1, sizeof (hb_ot_font_t)); + if (unlikely (!ot_font)) + return nullptr; + + ot_font->ot_face = &font->face->table; + + return ot_font; +} + +static void +_hb_ot_font_destroy (void *font_data) +{ + hb_ot_font_t *ot_font = (hb_ot_font_t *) font_data; + + auto *cache = ot_font->advance_cache.get_relaxed (); + if (cache) + { + cache->fini (); + hb_free (cache); + } + + hb_free (ot_font); +} static hb_bool_t hb_ot_get_nominal_glyph (hb_font_t *font HB_UNUSED, @@ -66,7 +102,8 @@ hb_ot_get_nominal_glyph (hb_font_t *font HB_UNUSED, hb_codepoint_t *glyph, void *user_data HB_UNUSED) { - const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data; + const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; + const hb_ot_face_t *ot_face = ot_font->ot_face; return ot_face->cmap->get_nominal_glyph (unicode, glyph); } @@ -80,7 +117,8 @@ hb_ot_get_nominal_glyphs (hb_font_t *font HB_UNUSED, unsigned int glyph_stride, void *user_data HB_UNUSED) { - const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data; + const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; + const hb_ot_face_t *ot_face = ot_font->ot_face; return ot_face->cmap->get_nominal_glyphs (count, first_unicode, unicode_stride, first_glyph, glyph_stride); @@ -94,7 +132,8 @@ hb_ot_get_variation_glyph (hb_font_t *font HB_UNUSED, hb_codepoint_t *glyph, void *user_data HB_UNUSED) { - const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data; + const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; + const hb_ot_face_t *ot_face = ot_font->ot_face; return ot_face->cmap->get_variation_glyph (unicode, variation_selector, glyph); } @@ -107,15 +146,83 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data, unsigned advance_stride, void *user_data HB_UNUSED) { - const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data; + const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; + const hb_ot_face_t *ot_face = ot_font->ot_face; const OT::hmtx_accelerator_t &hmtx = *ot_face->hmtx; - for (unsigned int i = 0; i < count; i++) +#ifndef HB_NO_VAR + const OT::HVARVVAR &HVAR = *hmtx.var_table; + const OT::VariationStore &varStore = &HVAR + HVAR.varStore; + OT::VariationStore::cache_t *varStore_cache = font->num_coords * count >= 128 ? varStore.create_cache () : nullptr; + + bool use_cache = font->num_coords; +#else + OT::VariationStore::cache_t *varStore_cache = nullptr; + bool use_cache = false; +#endif + + hb_advance_cache_t *cache = nullptr; + if (use_cache) { - *first_advance = font->em_scale_x (hmtx.get_advance (*first_glyph, font)); - first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride); - first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride); + retry: + cache = ot_font->advance_cache.get (); + if (unlikely (!cache)) + { + cache = (hb_advance_cache_t *) hb_malloc (sizeof (hb_advance_cache_t)); + if (unlikely (!cache)) + { + use_cache = false; + goto out; + } + + cache->init (); + if (unlikely (!ot_font->advance_cache.cmpexch (nullptr, cache))) + { + hb_free (cache); + goto retry; + } + ot_font->cached_coords_serial.set (font->serial_coords); + } + } + out: + + if (!use_cache) + { + for (unsigned int i = 0; i < count; i++) + { + *first_advance = font->em_scale_x (hmtx.get_advance (*first_glyph, font, varStore_cache)); + first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride); + first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride); + } } + else + { /* Use cache. */ + if (ot_font->cached_coords_serial.get () != (int) font->serial_coords) + { + ot_font->advance_cache->init (); + ot_font->cached_coords_serial.set (font->serial_coords); + } + + for (unsigned int i = 0; i < count; i++) + { + hb_position_t v; + unsigned cv; + if (ot_font->advance_cache->get (*first_glyph, &cv)) + v = cv; + else + { + v = hmtx.get_advance (*first_glyph, font, varStore_cache); + ot_font->advance_cache->set (*first_glyph, v); + } + *first_advance = font->em_scale_x (v); + first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride); + first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride); + } + } + +#ifndef HB_NO_VAR + OT::VariationStore::destroy_cache (varStore_cache); +#endif } #ifndef HB_NO_VERTICAL @@ -128,16 +235,31 @@ hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data, unsigned advance_stride, void *user_data HB_UNUSED) { - const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data; + const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; + const hb_ot_face_t *ot_face = ot_font->ot_face; const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx; if (vmtx.has_data ()) + { +#ifndef HB_NO_VAR + const OT::HVARVVAR &VVAR = *vmtx.var_table; + const OT::VariationStore &varStore = &VVAR + VVAR.varStore; + OT::VariationStore::cache_t *varStore_cache = font->num_coords ? varStore.create_cache () : nullptr; +#else + OT::VariationStore::cache_t *varStore_cache = nullptr; +#endif + for (unsigned int i = 0; i < count; i++) { - *first_advance = font->em_scale_y (-(int) vmtx.get_advance (*first_glyph, font)); + *first_advance = font->em_scale_y (-(int) vmtx.get_advance (*first_glyph, font, varStore_cache)); first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride); first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride); } + +#ifndef HB_NO_VAR + OT::VariationStore::destroy_cache (varStore_cache); +#endif + } else { hb_font_extents_t font_extents; @@ -163,7 +285,8 @@ hb_ot_get_glyph_v_origin (hb_font_t *font, hb_position_t *y, void *user_data HB_UNUSED) { - const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data; + const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; + const hb_ot_face_t *ot_face = ot_font->ot_face; *x = font->get_glyph_h_advance (glyph) / 2; @@ -208,7 +331,8 @@ hb_ot_get_glyph_extents (hb_font_t *font, hb_glyph_extents_t *extents, void *user_data HB_UNUSED) { - const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data; + const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; + const hb_ot_face_t *ot_face = ot_font->ot_face; #if !defined(HB_NO_OT_FONT_BITMAP) && !defined(HB_NO_COLOR) if (ot_face->sbix->get_extents (font, glyph, extents)) return true; @@ -234,7 +358,9 @@ hb_ot_get_glyph_name (hb_font_t *font HB_UNUSED, char *name, unsigned int size, void *user_data HB_UNUSED) { - const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data; + const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; + const hb_ot_face_t *ot_face = ot_font->ot_face; + if (ot_face->post->get_glyph_name (glyph, name, size)) return true; #ifndef HB_NO_OT_FONT_CFF if (ot_face->cff1->get_glyph_name (glyph, name, size)) return true; @@ -248,7 +374,9 @@ hb_ot_get_glyph_from_name (hb_font_t *font HB_UNUSED, hb_codepoint_t *glyph, void *user_data HB_UNUSED) { - const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data; + const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; + const hb_ot_face_t *ot_face = ot_font->ot_face; + if (ot_face->post->get_glyph_from_name (name, len, glyph)) return true; #ifndef HB_NO_OT_FONT_CFF if (ot_face->cff1->get_glyph_from_name (name, len, glyph)) return true; @@ -364,10 +492,14 @@ _hb_ot_get_font_funcs () void hb_ot_font_set_funcs (hb_font_t *font) { + hb_ot_font_t *ot_font = _hb_ot_font_create (font); + if (unlikely (!ot_font)) + return; + hb_font_set_funcs (font, _hb_ot_get_font_funcs (), - &font->face->table, - nullptr); + ot_font, + _hb_ot_font_destroy); } #ifndef HB_NO_VAR diff --git a/thirdparty/harfbuzz/src/hb-ot-glyf-table.hh b/thirdparty/harfbuzz/src/hb-ot-glyf-table.hh index b4ac688344..c32ff7636d 100644 --- a/thirdparty/harfbuzz/src/hb-ot-glyf-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-glyf-table.hh @@ -30,1332 +30,6 @@ #ifndef HB_OT_GLYF_TABLE_HH #define HB_OT_GLYF_TABLE_HH -#include "hb-open-type.hh" -#include "hb-ot-head-table.hh" -#include "hb-ot-hmtx-table.hh" -#include "hb-ot-var-gvar-table.hh" -#include "hb-draw.hh" - -namespace OT { - - -/* - * loca -- Index to Location - * https://docs.microsoft.com/en-us/typography/opentype/spec/loca - */ -#define HB_OT_TAG_loca HB_TAG('l','o','c','a') - -#ifndef HB_MAX_COMPOSITE_OPERATIONS -#define HB_MAX_COMPOSITE_OPERATIONS 100000 -#endif - - -struct loca -{ - friend struct glyf; - - static constexpr hb_tag_t tableTag = HB_OT_TAG_loca; - - bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const - { - TRACE_SANITIZE (this); - return_trace (true); - } - - protected: - UnsizedArrayOf<HBUINT8> - dataZ; /* Location data. */ - public: - DEFINE_SIZE_MIN (0); /* In reality, this is UNBOUNDED() type; but since we always - * check the size externally, allow Null() object of it by - * defining it _MIN instead. */ -}; - - -/* - * glyf -- TrueType Glyph Data - * https://docs.microsoft.com/en-us/typography/opentype/spec/glyf - */ -#define HB_OT_TAG_glyf HB_TAG('g','l','y','f') - - -struct glyf -{ - static constexpr hb_tag_t tableTag = HB_OT_TAG_glyf; - - bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const - { - TRACE_SANITIZE (this); - /* Runtime checks as eager sanitizing each glyph is costy */ - return_trace (true); - } - - template<typename Iterator, - hb_requires (hb_is_source_of (Iterator, unsigned int))> - static bool - _add_loca_and_head (hb_subset_plan_t * plan, Iterator padded_offsets, bool use_short_loca) - { - unsigned num_offsets = padded_offsets.len () + 1; - unsigned entry_size = use_short_loca ? 2 : 4; - char *loca_prime_data = (char *) hb_calloc (entry_size, num_offsets); - - if (unlikely (!loca_prime_data)) return false; - - DEBUG_MSG (SUBSET, nullptr, "loca entry_size %d num_offsets %d size %d", - entry_size, num_offsets, entry_size * num_offsets); - - if (use_short_loca) - _write_loca (padded_offsets, 1, hb_array ((HBUINT16 *) loca_prime_data, num_offsets)); - else - _write_loca (padded_offsets, 0, hb_array ((HBUINT32 *) loca_prime_data, num_offsets)); - - hb_blob_t *loca_blob = hb_blob_create (loca_prime_data, - entry_size * num_offsets, - HB_MEMORY_MODE_WRITABLE, - loca_prime_data, - hb_free); - - bool result = plan->add_table (HB_OT_TAG_loca, loca_blob) - && _add_head_and_set_loca_version (plan, use_short_loca); - - hb_blob_destroy (loca_blob); - return result; - } - - template<typename IteratorIn, typename IteratorOut, - hb_requires (hb_is_source_of (IteratorIn, unsigned int)), - hb_requires (hb_is_sink_of (IteratorOut, unsigned))> - static void - _write_loca (IteratorIn it, unsigned right_shift, IteratorOut dest) - { - unsigned int offset = 0; - dest << 0; - + it - | hb_map ([=, &offset] (unsigned int padded_size) - { - offset += padded_size; - DEBUG_MSG (SUBSET, nullptr, "loca entry offset %d", offset); - return offset >> right_shift; - }) - | hb_sink (dest) - ; - } - - /* requires source of SubsetGlyph complains the identifier isn't declared */ - template <typename Iterator> - bool serialize (hb_serialize_context_t *c, - Iterator it, - bool use_short_loca, - const hb_subset_plan_t *plan) - { - TRACE_SERIALIZE (this); - unsigned init_len = c->length (); - for (const auto &_ : it) _.serialize (c, use_short_loca, plan); - - /* As a special case when all glyph in the font are empty, add a zero byte - * to the table, so that OTS doesn’t reject it, and to make the table work - * on Windows as well. - * See https://github.com/khaledhosny/ots/issues/52 */ - if (init_len == c->length ()) - { - HBUINT8 empty_byte; - empty_byte = 0; - c->copy (empty_byte); - } - return_trace (true); - } - - /* Byte region(s) per glyph to output - unpadded, hints removed if so requested - If we fail to process a glyph we produce an empty (0-length) glyph */ - bool subset (hb_subset_context_t *c) const - { - TRACE_SUBSET (this); - - glyf *glyf_prime = c->serializer->start_embed <glyf> (); - if (unlikely (!c->serializer->check_success (glyf_prime))) return_trace (false); - - hb_vector_t<SubsetGlyph> glyphs; - _populate_subset_glyphs (c->plan, &glyphs); - - auto padded_offsets = - + hb_iter (glyphs) - | hb_map (&SubsetGlyph::padded_size) - ; - - unsigned max_offset = + padded_offsets | hb_reduce (hb_add, 0); - bool use_short_loca = max_offset < 0x1FFFF; - - - glyf_prime->serialize (c->serializer, hb_iter (glyphs), use_short_loca, c->plan); - if (!use_short_loca) { - padded_offsets = - + hb_iter (glyphs) - | hb_map (&SubsetGlyph::length) - ; - } - - - if (unlikely (c->serializer->in_error ())) return_trace (false); - return_trace (c->serializer->check_success (_add_loca_and_head (c->plan, - padded_offsets, - use_short_loca))); - } - - template <typename SubsetGlyph> - void - _populate_subset_glyphs (const hb_subset_plan_t *plan, - hb_vector_t<SubsetGlyph> *glyphs /* OUT */) const - { - OT::glyf::accelerator_t glyf (plan->source); - - + hb_range (plan->num_output_glyphs ()) - | hb_map ([&] (hb_codepoint_t new_gid) - { - SubsetGlyph subset_glyph = {0}; - subset_glyph.new_gid = new_gid; - - /* should never fail: all old gids should be mapped */ - if (!plan->old_gid_for_new_gid (new_gid, &subset_glyph.old_gid)) - return subset_glyph; - - if (new_gid == 0 && - !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)) - subset_glyph.source_glyph = Glyph (); - else - subset_glyph.source_glyph = glyf.glyph_for_gid (subset_glyph.old_gid, true); - if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING) - subset_glyph.drop_hints_bytes (); - else - subset_glyph.dest_start = subset_glyph.source_glyph.get_bytes (); - return subset_glyph; - }) - | hb_sink (glyphs) - ; - } - - static bool - _add_head_and_set_loca_version (hb_subset_plan_t *plan, bool use_short_loca) - { - hb_blob_t *head_blob = hb_sanitize_context_t ().reference_table<head> (plan->source); - hb_blob_t *head_prime_blob = hb_blob_copy_writable_or_fail (head_blob); - hb_blob_destroy (head_blob); - - if (unlikely (!head_prime_blob)) - return false; - - head *head_prime = (head *) hb_blob_get_data_writable (head_prime_blob, nullptr); - head_prime->indexToLocFormat = use_short_loca ? 0 : 1; - bool success = plan->add_table (HB_OT_TAG_head, head_prime_blob); - - hb_blob_destroy (head_prime_blob); - return success; - } - - struct CompositeGlyphChain - { - protected: - enum composite_glyph_flag_t - { - ARG_1_AND_2_ARE_WORDS = 0x0001, - ARGS_ARE_XY_VALUES = 0x0002, - ROUND_XY_TO_GRID = 0x0004, - WE_HAVE_A_SCALE = 0x0008, - MORE_COMPONENTS = 0x0020, - WE_HAVE_AN_X_AND_Y_SCALE = 0x0040, - WE_HAVE_A_TWO_BY_TWO = 0x0080, - WE_HAVE_INSTRUCTIONS = 0x0100, - USE_MY_METRICS = 0x0200, - OVERLAP_COMPOUND = 0x0400, - SCALED_COMPONENT_OFFSET = 0x0800, - UNSCALED_COMPONENT_OFFSET = 0x1000 - }; - - public: - unsigned int get_size () const - { - unsigned int size = min_size; - /* arg1 and 2 are int16 */ - if (flags & ARG_1_AND_2_ARE_WORDS) size += 4; - /* arg1 and 2 are int8 */ - else size += 2; - - /* One x 16 bit (scale) */ - if (flags & WE_HAVE_A_SCALE) size += 2; - /* Two x 16 bit (xscale, yscale) */ - else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) size += 4; - /* Four x 16 bit (xscale, scale01, scale10, yscale) */ - else if (flags & WE_HAVE_A_TWO_BY_TWO) size += 8; - - return size; - } - - void set_glyph_index (hb_codepoint_t new_gid) { glyphIndex = new_gid; } - hb_codepoint_t get_glyph_index () const { return glyphIndex; } - - void drop_instructions_flag () { flags = (uint16_t) flags & ~WE_HAVE_INSTRUCTIONS; } - void set_overlaps_flag () - { - flags = (uint16_t) flags | OVERLAP_COMPOUND; - } - - bool has_instructions () const { return flags & WE_HAVE_INSTRUCTIONS; } - - bool has_more () const { return flags & MORE_COMPONENTS; } - bool is_use_my_metrics () const { return flags & USE_MY_METRICS; } - bool is_anchored () const { return !(flags & ARGS_ARE_XY_VALUES); } - void get_anchor_points (unsigned int &point1, unsigned int &point2) const - { - const HBUINT8 *p = &StructAfter<const HBUINT8> (glyphIndex); - if (flags & ARG_1_AND_2_ARE_WORDS) - { - point1 = ((const HBUINT16 *) p)[0]; - point2 = ((const HBUINT16 *) p)[1]; - } - else - { - point1 = p[0]; - point2 = p[1]; - } - } - - void transform_points (contour_point_vector_t &points) const - { - float matrix[4]; - contour_point_t trans; - if (get_transformation (matrix, trans)) - { - if (scaled_offsets ()) - { - points.translate (trans); - points.transform (matrix); - } - else - { - points.transform (matrix); - points.translate (trans); - } - } - } - - protected: - bool scaled_offsets () const - { return (flags & (SCALED_COMPONENT_OFFSET | UNSCALED_COMPONENT_OFFSET)) == SCALED_COMPONENT_OFFSET; } - - bool get_transformation (float (&matrix)[4], contour_point_t &trans) const - { - matrix[0] = matrix[3] = 1.f; - matrix[1] = matrix[2] = 0.f; - - int tx, ty; - const HBINT8 *p = &StructAfter<const HBINT8> (glyphIndex); - if (flags & ARG_1_AND_2_ARE_WORDS) - { - tx = *(const HBINT16 *) p; - p += HBINT16::static_size; - ty = *(const HBINT16 *) p; - p += HBINT16::static_size; - } - else - { - tx = *p++; - ty = *p++; - } - if (is_anchored ()) tx = ty = 0; - - trans.init ((float) tx, (float) ty); - - { - const F2DOT14 *points = (const F2DOT14 *) p; - if (flags & WE_HAVE_A_SCALE) - { - matrix[0] = matrix[3] = points[0].to_float (); - return true; - } - else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) - { - matrix[0] = points[0].to_float (); - matrix[3] = points[1].to_float (); - return true; - } - else if (flags & WE_HAVE_A_TWO_BY_TWO) - { - matrix[0] = points[0].to_float (); - matrix[1] = points[1].to_float (); - matrix[2] = points[2].to_float (); - matrix[3] = points[3].to_float (); - return true; - } - } - return tx || ty; - } - - protected: - HBUINT16 flags; - HBGlyphID16 glyphIndex; - public: - DEFINE_SIZE_MIN (4); - }; - - struct composite_iter_t : hb_iter_with_fallback_t<composite_iter_t, const CompositeGlyphChain &> - { - typedef const CompositeGlyphChain *__item_t__; - composite_iter_t (hb_bytes_t glyph_, __item_t__ current_) : - glyph (glyph_), current (nullptr), current_size (0) - { - set_next (current_); - } - - composite_iter_t () : glyph (hb_bytes_t ()), current (nullptr), current_size (0) {} - - const CompositeGlyphChain &__item__ () const { return *current; } - bool __more__ () const { return current; } - void __next__ () - { - if (!current->has_more ()) { current = nullptr; return; } - - set_next (&StructAtOffset<CompositeGlyphChain> (current, current_size)); - } - bool operator != (const composite_iter_t& o) const - { return glyph != o.glyph || current != o.current; } - - - void set_next (const CompositeGlyphChain *composite) - { - if (!glyph.check_range (composite, CompositeGlyphChain::min_size)) - { - current = nullptr; - current_size = 0; - return; - } - unsigned size = composite->get_size (); - if (!glyph.check_range (composite, size)) - { - current = nullptr; - current_size = 0; - return; - } - - current = composite; - current_size = size; - } - - private: - hb_bytes_t glyph; - __item_t__ current; - unsigned current_size; - }; - - enum phantom_point_index_t - { - PHANTOM_LEFT = 0, - PHANTOM_RIGHT = 1, - PHANTOM_TOP = 2, - PHANTOM_BOTTOM = 3, - PHANTOM_COUNT = 4 - }; - - struct accelerator_t; - - struct Glyph - { - enum simple_glyph_flag_t - { - FLAG_ON_CURVE = 0x01, - FLAG_X_SHORT = 0x02, - FLAG_Y_SHORT = 0x04, - FLAG_REPEAT = 0x08, - FLAG_X_SAME = 0x10, - FLAG_Y_SAME = 0x20, - FLAG_OVERLAP_SIMPLE = 0x40, - FLAG_RESERVED2 = 0x80 - }; - - private: - struct GlyphHeader - { - bool has_data () const { return numberOfContours; } - - bool get_extents (hb_font_t *font, const accelerator_t &glyf_accelerator, - hb_codepoint_t gid, hb_glyph_extents_t *extents) const - { - /* Undocumented rasterizer behavior: shift glyph to the left by (lsb - xMin), i.e., xMin = lsb */ - /* extents->x_bearing = hb_min (glyph_header.xMin, glyph_header.xMax); */ - extents->x_bearing = font->em_scale_x (glyf_accelerator.hmtx->get_side_bearing (gid)); - extents->y_bearing = font->em_scale_y (hb_max (yMin, yMax)); - extents->width = font->em_scale_x (hb_max (xMin, xMax) - hb_min (xMin, xMax)); - extents->height = font->em_scale_y (hb_min (yMin, yMax) - hb_max (yMin, yMax)); - - return true; - } - - HBINT16 numberOfContours; - /* If the number of contours is - * greater than or equal to zero, - * this is a simple glyph; if negative, - * this is a composite glyph. */ - FWORD xMin; /* Minimum x for coordinate data. */ - FWORD yMin; /* Minimum y for coordinate data. */ - FWORD xMax; /* Maximum x for coordinate data. */ - FWORD yMax; /* Maximum y for coordinate data. */ - public: - DEFINE_SIZE_STATIC (10); - }; - - struct SimpleGlyph - { - const GlyphHeader &header; - hb_bytes_t bytes; - SimpleGlyph (const GlyphHeader &header_, hb_bytes_t bytes_) : - header (header_), bytes (bytes_) {} - - unsigned int instruction_len_offset () const - { return GlyphHeader::static_size + 2 * header.numberOfContours; } - - unsigned int length (unsigned int instruction_len) const - { return instruction_len_offset () + 2 + instruction_len; } - - unsigned int instructions_length () const - { - unsigned int instruction_length_offset = instruction_len_offset (); - if (unlikely (instruction_length_offset + 2 > bytes.length)) return 0; - - const HBUINT16 &instructionLength = StructAtOffset<HBUINT16> (&bytes, instruction_length_offset); - /* Out of bounds of the current glyph */ - if (unlikely (length (instructionLength) > bytes.length)) return 0; - return instructionLength; - } - - const Glyph trim_padding () const - { - /* based on FontTools _g_l_y_f.py::trim */ - const uint8_t *glyph = (uint8_t*) bytes.arrayZ; - const uint8_t *glyph_end = glyph + bytes.length; - /* simple glyph w/contours, possibly trimmable */ - glyph += instruction_len_offset (); - - if (unlikely (glyph + 2 >= glyph_end)) return Glyph (); - unsigned int num_coordinates = StructAtOffset<HBUINT16> (glyph - 2, 0) + 1; - unsigned int num_instructions = StructAtOffset<HBUINT16> (glyph, 0); - - glyph += 2 + num_instructions; - - unsigned int coord_bytes = 0; - unsigned int coords_with_flags = 0; - while (glyph < glyph_end) - { - uint8_t flag = *glyph; - glyph++; - - unsigned int repeat = 1; - if (flag & FLAG_REPEAT) - { - if (unlikely (glyph >= glyph_end)) return Glyph (); - repeat = *glyph + 1; - glyph++; - } - - unsigned int xBytes, yBytes; - xBytes = yBytes = 0; - if (flag & FLAG_X_SHORT) xBytes = 1; - else if ((flag & FLAG_X_SAME) == 0) xBytes = 2; - - if (flag & FLAG_Y_SHORT) yBytes = 1; - else if ((flag & FLAG_Y_SAME) == 0) yBytes = 2; - - coord_bytes += (xBytes + yBytes) * repeat; - coords_with_flags += repeat; - if (coords_with_flags >= num_coordinates) break; - } - - if (unlikely (coords_with_flags != num_coordinates)) return Glyph (); - return Glyph (bytes.sub_array (0, bytes.length + coord_bytes - (glyph_end - glyph))); - } - - /* zero instruction length */ - void drop_hints () - { - GlyphHeader &glyph_header = const_cast<GlyphHeader &> (header); - (HBUINT16 &) StructAtOffset<HBUINT16> (&glyph_header, instruction_len_offset ()) = 0; - } - - void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const - { - unsigned int instructions_len = instructions_length (); - unsigned int glyph_length = length (instructions_len); - dest_start = bytes.sub_array (0, glyph_length - instructions_len); - dest_end = bytes.sub_array (glyph_length, bytes.length - glyph_length); - } - - void set_overlaps_flag () - { - if (unlikely (!header.numberOfContours)) return; - - unsigned flags_offset = length (instructions_length ()); - if (unlikely (flags_offset + 1 > bytes.length)) return; - - HBUINT8 &first_flag = (HBUINT8 &) StructAtOffset<HBUINT16> (&bytes, flags_offset); - first_flag = (uint8_t) first_flag | FLAG_OVERLAP_SIMPLE; - } - - static bool read_points (const HBUINT8 *&p /* IN/OUT */, - contour_point_vector_t &points_ /* IN/OUT */, - const hb_bytes_t &bytes, - void (* setter) (contour_point_t &_, float v), - const simple_glyph_flag_t short_flag, - const simple_glyph_flag_t same_flag) - { - float v = 0; - for (unsigned i = 0; i < points_.length; i++) - { - uint8_t flag = points_[i].flag; - if (flag & short_flag) - { - if (unlikely (!bytes.check_range (p))) return false; - if (flag & same_flag) - v += *p++; - else - v -= *p++; - } - else - { - if (!(flag & same_flag)) - { - if (unlikely (!bytes.check_range ((const HBUINT16 *) p))) return false; - v += *(const HBINT16 *) p; - p += HBINT16::static_size; - } - } - setter (points_[i], v); - } - return true; - } - - bool get_contour_points (contour_point_vector_t &points_ /* OUT */, - bool phantom_only = false) const - { - const HBUINT16 *endPtsOfContours = &StructAfter<HBUINT16> (header); - int num_contours = header.numberOfContours; - if (unlikely (!bytes.check_range (&endPtsOfContours[num_contours + 1]))) return false; - unsigned int num_points = endPtsOfContours[num_contours - 1] + 1; - - points_.resize (num_points); - for (unsigned int i = 0; i < points_.length; i++) points_[i].init (); - if (phantom_only) return true; - - for (int i = 0; i < num_contours; i++) - points_[endPtsOfContours[i]].is_end_point = true; - - /* Skip instructions */ - const HBUINT8 *p = &StructAtOffset<HBUINT8> (&endPtsOfContours[num_contours + 1], - endPtsOfContours[num_contours]); - - /* Read flags */ - for (unsigned int i = 0; i < num_points; i++) - { - if (unlikely (!bytes.check_range (p))) return false; - uint8_t flag = *p++; - points_[i].flag = flag; - if (flag & FLAG_REPEAT) - { - if (unlikely (!bytes.check_range (p))) return false; - unsigned int repeat_count = *p++; - while ((repeat_count-- > 0) && (++i < num_points)) - points_[i].flag = flag; - } - } - - /* Read x & y coordinates */ - return read_points (p, points_, bytes, [] (contour_point_t &p, float v) { p.x = v; }, - FLAG_X_SHORT, FLAG_X_SAME) - && read_points (p, points_, bytes, [] (contour_point_t &p, float v) { p.y = v; }, - FLAG_Y_SHORT, FLAG_Y_SAME); - } - }; - - struct CompositeGlyph - { - const GlyphHeader &header; - hb_bytes_t bytes; - CompositeGlyph (const GlyphHeader &header_, hb_bytes_t bytes_) : - header (header_), bytes (bytes_) {} - - composite_iter_t get_iterator () const - { return composite_iter_t (bytes, &StructAfter<CompositeGlyphChain, GlyphHeader> (header)); } - - unsigned int instructions_length (hb_bytes_t bytes) const - { - unsigned int start = bytes.length; - unsigned int end = bytes.length; - const CompositeGlyphChain *last = nullptr; - for (auto &item : get_iterator ()) - last = &item; - if (unlikely (!last)) return 0; - - if (last->has_instructions ()) - start = (char *) last - &bytes + last->get_size (); - if (unlikely (start > end)) return 0; - return end - start; - } - - /* Trimming for composites not implemented. - * If removing hints it falls out of that. */ - const Glyph trim_padding () const { return Glyph (bytes); } - - void drop_hints () - { - for (const auto &_ : get_iterator ()) - const_cast<CompositeGlyphChain &> (_).drop_instructions_flag (); - } - - /* Chop instructions off the end */ - void drop_hints_bytes (hb_bytes_t &dest_start) const - { dest_start = bytes.sub_array (0, bytes.length - instructions_length (bytes)); } - - void set_overlaps_flag () - { - const_cast<CompositeGlyphChain &> (StructAfter<CompositeGlyphChain, GlyphHeader> (header)) - .set_overlaps_flag (); - } - }; - - enum glyph_type_t { EMPTY, SIMPLE, COMPOSITE }; - - public: - composite_iter_t get_composite_iterator () const - { - if (type != COMPOSITE) return composite_iter_t (); - return CompositeGlyph (*header, bytes).get_iterator (); - } - - const Glyph trim_padding () const - { - switch (type) { - case COMPOSITE: return CompositeGlyph (*header, bytes).trim_padding (); - case SIMPLE: return SimpleGlyph (*header, bytes).trim_padding (); - default: return bytes; - } - } - - void drop_hints () - { - switch (type) { - case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints (); return; - case SIMPLE: SimpleGlyph (*header, bytes).drop_hints (); return; - default: return; - } - } - - void set_overlaps_flag () - { - switch (type) { - case COMPOSITE: CompositeGlyph (*header, bytes).set_overlaps_flag (); return; - case SIMPLE: SimpleGlyph (*header, bytes).set_overlaps_flag (); return; - default: return; - } - } - - void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const - { - switch (type) { - case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints_bytes (dest_start); return; - case SIMPLE: SimpleGlyph (*header, bytes).drop_hints_bytes (dest_start, dest_end); return; - default: return; - } - } - - /* Note: Recursively calls itself. - * all_points includes phantom points - */ - bool get_points (hb_font_t *font, const accelerator_t &glyf_accelerator, - contour_point_vector_t &all_points /* OUT */, - bool phantom_only = false, - unsigned int depth = 0) const - { - if (unlikely (depth > HB_MAX_NESTING_LEVEL)) return false; - contour_point_vector_t points; - - switch (type) { - case COMPOSITE: - { - /* pseudo component points for each component in composite glyph */ - unsigned num_points = hb_len (CompositeGlyph (*header, bytes).get_iterator ()); - if (unlikely (!points.resize (num_points))) return false; - for (unsigned i = 0; i < points.length; i++) - points[i].init (); - break; - } - case SIMPLE: - if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (points, phantom_only))) - return false; - break; - } - - /* Init phantom points */ - if (unlikely (!points.resize (points.length + PHANTOM_COUNT))) return false; - hb_array_t<contour_point_t> phantoms = points.sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT); - { - for (unsigned i = 0; i < PHANTOM_COUNT; ++i) phantoms[i].init (); - int h_delta = (int) header->xMin - - glyf_accelerator.hmtx->get_side_bearing (gid); - int v_orig = (int) header->yMax + -#ifndef HB_NO_VERTICAL - glyf_accelerator.vmtx->get_side_bearing (gid) -#else - 0 -#endif - ; - unsigned h_adv = glyf_accelerator.hmtx->get_advance (gid); - unsigned v_adv = -#ifndef HB_NO_VERTICAL - glyf_accelerator.vmtx->get_advance (gid) -#else - - font->face->get_upem () -#endif - ; - phantoms[PHANTOM_LEFT].x = h_delta; - phantoms[PHANTOM_RIGHT].x = h_adv + h_delta; - phantoms[PHANTOM_TOP].y = v_orig; - phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv; - } - -#ifndef HB_NO_VAR - glyf_accelerator.gvar->apply_deltas_to_points (gid, font, points.as_array ()); -#endif - - switch (type) { - case SIMPLE: - all_points.extend (points.as_array ()); - break; - case COMPOSITE: - { - unsigned int comp_index = 0; - for (auto &item : get_composite_iterator ()) - { - contour_point_vector_t comp_points; - if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_glyph_index ()) - .get_points (font, glyf_accelerator, comp_points, - phantom_only, depth + 1) - || comp_points.length < PHANTOM_COUNT)) - return false; - - /* Copy phantom points from component if USE_MY_METRICS flag set */ - if (item.is_use_my_metrics ()) - for (unsigned int i = 0; i < PHANTOM_COUNT; i++) - phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i]; - - /* Apply component transformation & translation */ - item.transform_points (comp_points); - - /* Apply translation from gvar */ - comp_points.translate (points[comp_index]); - - if (item.is_anchored ()) - { - unsigned int p1, p2; - item.get_anchor_points (p1, p2); - if (likely (p1 < all_points.length && p2 < comp_points.length)) - { - contour_point_t delta; - delta.init (all_points[p1].x - comp_points[p2].x, - all_points[p1].y - comp_points[p2].y); - - comp_points.translate (delta); - } - } - - all_points.extend (comp_points.sub_array (0, comp_points.length - PHANTOM_COUNT)); - - comp_index++; - } - - all_points.extend (phantoms); - } break; - default: - all_points.extend (phantoms); - } - - if (depth == 0) /* Apply at top level */ - { - /* Undocumented rasterizer behavior: - * Shift points horizontally by the updated left side bearing - */ - contour_point_t delta; - delta.init (-phantoms[PHANTOM_LEFT].x, 0.f); - if (delta.x) all_points.translate (delta); - } - - return true; - } - - bool get_extents (hb_font_t *font, const accelerator_t &glyf_accelerator, - hb_glyph_extents_t *extents) const - { - if (type == EMPTY) return true; /* Empty glyph; zero extents. */ - return header->get_extents (font, glyf_accelerator, gid, extents); - } - - hb_bytes_t get_bytes () const { return bytes; } - - Glyph (hb_bytes_t bytes_ = hb_bytes_t (), - hb_codepoint_t gid_ = (hb_codepoint_t) -1) : bytes (bytes_), gid (gid_), - header (bytes.as<GlyphHeader> ()) - { - int num_contours = header->numberOfContours; - if (unlikely (num_contours == 0)) type = EMPTY; - else if (num_contours > 0) type = SIMPLE; - else type = COMPOSITE; /* negative numbers */ - } - - protected: - hb_bytes_t bytes; - hb_codepoint_t gid; - const GlyphHeader *header; - unsigned type; - }; - - struct accelerator_t - { - accelerator_t (hb_face_t *face) - { - short_offset = false; - num_glyphs = 0; - loca_table = nullptr; - glyf_table = nullptr; -#ifndef HB_NO_VAR - gvar = nullptr; -#endif - hmtx = nullptr; -#ifndef HB_NO_VERTICAL - vmtx = nullptr; -#endif - const OT::head &head = *face->table.head; - if (head.indexToLocFormat > 1 || head.glyphDataFormat > 0) - /* Unknown format. Leave num_glyphs=0, that takes care of disabling us. */ - return; - short_offset = 0 == head.indexToLocFormat; - - loca_table = face->table.loca.get_blob (); // Needs no destruct! - glyf_table = hb_sanitize_context_t ().reference_table<glyf> (face); -#ifndef HB_NO_VAR - gvar = face->table.gvar; -#endif - hmtx = face->table.hmtx; -#ifndef HB_NO_VERTICAL - vmtx = face->table.vmtx; -#endif - - num_glyphs = hb_max (1u, loca_table.get_length () / (short_offset ? 2 : 4)) - 1; - num_glyphs = hb_min (num_glyphs, face->get_num_glyphs ()); - } - ~accelerator_t () - { - glyf_table.destroy (); - } - - protected: - template<typename T> - bool get_points (hb_font_t *font, hb_codepoint_t gid, T consumer) const - { - if (gid >= num_glyphs) return false; - - /* Making this allocfree is not that easy - https://github.com/harfbuzz/harfbuzz/issues/2095 - mostly because of gvar handling in VF fonts, - perhaps a separate path for non-VF fonts can be considered */ - contour_point_vector_t all_points; - - bool phantom_only = !consumer.is_consuming_contour_points (); - if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, phantom_only))) - return false; - - if (consumer.is_consuming_contour_points ()) - { - for (unsigned point_index = 0; point_index + 4 < all_points.length; ++point_index) - consumer.consume_point (all_points[point_index]); - consumer.points_end (); - } - - /* Where to write phantoms, nullptr if not requested */ - contour_point_t *phantoms = consumer.get_phantoms_sink (); - if (phantoms) - for (unsigned i = 0; i < PHANTOM_COUNT; ++i) - phantoms[i] = all_points[all_points.length - PHANTOM_COUNT + i]; - - return true; - } - -#ifndef HB_NO_VAR - struct points_aggregator_t - { - hb_font_t *font; - hb_glyph_extents_t *extents; - contour_point_t *phantoms; - - struct contour_bounds_t - { - contour_bounds_t () { min_x = min_y = FLT_MAX; max_x = max_y = -FLT_MAX; } - - void add (const contour_point_t &p) - { - min_x = hb_min (min_x, p.x); - min_y = hb_min (min_y, p.y); - max_x = hb_max (max_x, p.x); - max_y = hb_max (max_y, p.y); - } - - bool empty () const { return (min_x >= max_x) || (min_y >= max_y); } - - void get_extents (hb_font_t *font, hb_glyph_extents_t *extents) - { - if (unlikely (empty ())) - { - extents->width = 0; - extents->x_bearing = 0; - extents->height = 0; - extents->y_bearing = 0; - return; - } - extents->x_bearing = font->em_scalef_x (min_x); - extents->width = font->em_scalef_x (max_x) - extents->x_bearing; - extents->y_bearing = font->em_scalef_y (max_y); - extents->height = font->em_scalef_y (min_y) - extents->y_bearing; - } - - protected: - float min_x, min_y, max_x, max_y; - } bounds; - - points_aggregator_t (hb_font_t *font_, hb_glyph_extents_t *extents_, contour_point_t *phantoms_) - { - font = font_; - extents = extents_; - phantoms = phantoms_; - if (extents) bounds = contour_bounds_t (); - } - - void consume_point (const contour_point_t &point) { bounds.add (point); } - void points_end () { bounds.get_extents (font, extents); } - - bool is_consuming_contour_points () { return extents; } - contour_point_t *get_phantoms_sink () { return phantoms; } - }; - - public: - unsigned - get_advance_var (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const - { - if (unlikely (gid >= num_glyphs)) return 0; - - bool success = false; - - contour_point_t phantoms[PHANTOM_COUNT]; - if (likely (font->num_coords == gvar->get_axis_count ())) - success = get_points (font, gid, points_aggregator_t (font, nullptr, phantoms)); - - if (unlikely (!success)) - return -#ifndef HB_NO_VERTICAL - is_vertical ? vmtx->get_advance (gid) : -#endif - hmtx->get_advance (gid); - - float result = is_vertical - ? phantoms[PHANTOM_TOP].y - phantoms[PHANTOM_BOTTOM].y - : phantoms[PHANTOM_RIGHT].x - phantoms[PHANTOM_LEFT].x; - return hb_clamp (roundf (result), 0.f, (float) UINT_MAX / 2); - } - - int get_side_bearing_var (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const - { - if (unlikely (gid >= num_glyphs)) return 0; - - hb_glyph_extents_t extents; - - contour_point_t phantoms[PHANTOM_COUNT]; - if (unlikely (!get_points (font, gid, points_aggregator_t (font, &extents, phantoms)))) - return -#ifndef HB_NO_VERTICAL - is_vertical ? vmtx->get_side_bearing (gid) : -#endif - hmtx->get_side_bearing (gid); - - return is_vertical - ? ceilf (phantoms[PHANTOM_TOP].y) - extents.y_bearing - : floorf (phantoms[PHANTOM_LEFT].x); - } -#endif - - public: - bool get_extents (hb_font_t *font, hb_codepoint_t gid, hb_glyph_extents_t *extents) const - { - if (unlikely (gid >= num_glyphs)) return false; - -#ifndef HB_NO_VAR - if (font->num_coords && font->num_coords == gvar->get_axis_count ()) - return get_points (font, gid, points_aggregator_t (font, extents, nullptr)); -#endif - return glyph_for_gid (gid).get_extents (font, *this, extents); - } - - const Glyph - glyph_for_gid (hb_codepoint_t gid, bool needs_padding_removal = false) const - { - if (unlikely (gid >= num_glyphs)) return Glyph (); - - unsigned int start_offset, end_offset; - - if (short_offset) - { - const HBUINT16 *offsets = (const HBUINT16 *) loca_table->dataZ.arrayZ; - start_offset = 2 * offsets[gid]; - end_offset = 2 * offsets[gid + 1]; - } - else - { - const HBUINT32 *offsets = (const HBUINT32 *) loca_table->dataZ.arrayZ; - start_offset = offsets[gid]; - end_offset = offsets[gid + 1]; - } - - if (unlikely (start_offset > end_offset || end_offset > glyf_table.get_length ())) - return Glyph (); - - Glyph glyph (hb_bytes_t ((const char *) this->glyf_table + start_offset, - end_offset - start_offset), gid); - return needs_padding_removal ? glyph.trim_padding () : glyph; - } - - unsigned - add_gid_and_children (hb_codepoint_t gid, - hb_set_t *gids_to_retain, - unsigned depth = 0, - unsigned operation_count = 0) const - { - if (unlikely (depth++ > HB_MAX_NESTING_LEVEL)) return operation_count; - if (unlikely (operation_count++ > HB_MAX_COMPOSITE_OPERATIONS)) return operation_count; - /* Check if is already visited */ - if (gids_to_retain->has (gid)) return operation_count; - - gids_to_retain->add (gid); - - auto it = glyph_for_gid (gid).get_composite_iterator (); - while (it) - { - auto item = *(it++); - operation_count = - add_gid_and_children (item.get_glyph_index (), gids_to_retain, depth, operation_count); - } - - return operation_count; - } - - struct path_builder_t - { - hb_font_t *font; - hb_draw_session_t *draw_session; - - struct optional_point_t - { - optional_point_t () { has_data = false; } - optional_point_t (float x_, float y_) { x = x_; y = y_; has_data = true; } - - bool has_data; - float x; - float y; - - optional_point_t lerp (optional_point_t p, float t) - { return optional_point_t (x + t * (p.x - x), y + t * (p.y - y)); } - } first_oncurve, first_offcurve, last_offcurve; - - path_builder_t (hb_font_t *font_, hb_draw_session_t &draw_session_) - { - font = font_; - draw_session = &draw_session_; - first_oncurve = first_offcurve = last_offcurve = optional_point_t (); - } - - /* based on https://github.com/RazrFalcon/ttf-parser/blob/4f32821/src/glyf.rs#L287 - See also: - * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM01/Chap1.html - * https://stackoverflow.com/a/20772557 */ - void consume_point (const contour_point_t &point) - { - bool is_on_curve = point.flag & Glyph::FLAG_ON_CURVE; - optional_point_t p (point.x, point.y); - if (!first_oncurve.has_data) - { - if (is_on_curve) - { - first_oncurve = p; - draw_session->move_to (font->em_fscalef_x (p.x), font->em_fscalef_y (p.y)); - } - else - { - if (first_offcurve.has_data) - { - optional_point_t mid = first_offcurve.lerp (p, .5f); - first_oncurve = mid; - last_offcurve = p; - draw_session->move_to (font->em_fscalef_x (mid.x), font->em_fscalef_y (mid.y)); - } - else - first_offcurve = p; - } - } - else - { - if (last_offcurve.has_data) - { - if (is_on_curve) - { - draw_session->quadratic_to (font->em_fscalef_x (last_offcurve.x), font->em_fscalef_y (last_offcurve.y), - font->em_fscalef_x (p.x), font->em_fscalef_y (p.y)); - last_offcurve = optional_point_t (); - } - else - { - optional_point_t mid = last_offcurve.lerp (p, .5f); - draw_session->quadratic_to (font->em_fscalef_x (last_offcurve.x), font->em_fscalef_y (last_offcurve.y), - font->em_fscalef_x (mid.x), font->em_fscalef_y (mid.y)); - last_offcurve = p; - } - } - else - { - if (is_on_curve) - draw_session->line_to (font->em_fscalef_x (p.x), font->em_fscalef_y (p.y)); - else - last_offcurve = p; - } - } - - if (point.is_end_point) - { - if (first_offcurve.has_data && last_offcurve.has_data) - { - optional_point_t mid = last_offcurve.lerp (first_offcurve, .5f); - draw_session->quadratic_to (font->em_fscalef_x (last_offcurve.x), font->em_fscalef_y (last_offcurve.y), - font->em_fscalef_x (mid.x), font->em_fscalef_y (mid.y)); - last_offcurve = optional_point_t (); - /* now check the rest */ - } - - if (first_offcurve.has_data && first_oncurve.has_data) - draw_session->quadratic_to (font->em_fscalef_x (first_offcurve.x), font->em_fscalef_y (first_offcurve.y), - font->em_fscalef_x (first_oncurve.x), font->em_fscalef_y (first_oncurve.y)); - else if (last_offcurve.has_data && first_oncurve.has_data) - draw_session->quadratic_to (font->em_fscalef_x (last_offcurve.x), font->em_fscalef_y (last_offcurve.y), - font->em_fscalef_x (first_oncurve.x), font->em_fscalef_y (first_oncurve.y)); - else if (first_oncurve.has_data) - draw_session->line_to (font->em_fscalef_x (first_oncurve.x), font->em_fscalef_y (first_oncurve.y)); - else if (first_offcurve.has_data) - { - float x = font->em_fscalef_x (first_offcurve.x), y = font->em_fscalef_x (first_offcurve.y); - draw_session->move_to (x, y); - draw_session->quadratic_to (x, y, x, y); - } - - /* Getting ready for the next contour */ - first_oncurve = first_offcurve = last_offcurve = optional_point_t (); - draw_session->close_path (); - } - } - void points_end () {} - - bool is_consuming_contour_points () { return true; } - contour_point_t *get_phantoms_sink () { return nullptr; } - }; - - bool - get_path (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session) const - { return get_points (font, gid, path_builder_t (font, draw_session)); } - -#ifndef HB_NO_VAR - const gvar_accelerator_t *gvar; -#endif - const hmtx_accelerator_t *hmtx; -#ifndef HB_NO_VERTICAL - const vmtx_accelerator_t *vmtx; -#endif - - private: - bool short_offset; - unsigned int num_glyphs; - hb_blob_ptr_t<loca> loca_table; - hb_blob_ptr_t<glyf> glyf_table; - }; - - struct SubsetGlyph - { - hb_codepoint_t new_gid; - hb_codepoint_t old_gid; - Glyph source_glyph; - hb_bytes_t dest_start; /* region of source_glyph to copy first */ - hb_bytes_t dest_end; /* region of source_glyph to copy second */ - - bool serialize (hb_serialize_context_t *c, - bool use_short_loca, - const hb_subset_plan_t *plan) const - { - TRACE_SERIALIZE (this); - - hb_bytes_t dest_glyph = dest_start.copy (c); - dest_glyph = hb_bytes_t (&dest_glyph, dest_glyph.length + dest_end.copy (c).length); - unsigned int pad_length = use_short_loca ? padding () : 0; - DEBUG_MSG (SUBSET, nullptr, "serialize %d byte glyph, width %d pad %d", dest_glyph.length, dest_glyph.length + pad_length, pad_length); - - HBUINT8 pad; - pad = 0; - while (pad_length > 0) - { - c->embed (pad); - pad_length--; - } - - if (unlikely (!dest_glyph.length)) return_trace (true); - - /* update components gids */ - for (auto &_ : Glyph (dest_glyph).get_composite_iterator ()) - { - hb_codepoint_t new_gid; - if (plan->new_gid_for_old_gid (_.get_glyph_index (), &new_gid)) - const_cast<CompositeGlyphChain &> (_).set_glyph_index (new_gid); - } - - if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING) - Glyph (dest_glyph).drop_hints (); - - if (plan->flags & HB_SUBSET_FLAGS_SET_OVERLAPS_FLAG) - Glyph (dest_glyph).set_overlaps_flag (); - - return_trace (true); - } - - void drop_hints_bytes () - { source_glyph.drop_hints_bytes (dest_start, dest_end); } - - unsigned int length () const { return dest_start.length + dest_end.length; } - /* pad to 2 to ensure 2-byte loca will be ok */ - unsigned int padding () const { return length () % 2; } - unsigned int padded_size () const { return length () + padding (); } - }; - - protected: - UnsizedArrayOf<HBUINT8> - dataZ; /* Glyphs data. */ - public: - DEFINE_SIZE_MIN (0); /* In reality, this is UNBOUNDED() type; but since we always - * check the size externally, allow Null() object of it by - * defining it _MIN instead. */ -}; - -struct glyf_accelerator_t : glyf::accelerator_t { - glyf_accelerator_t (hb_face_t *face) : glyf::accelerator_t (face) {} -}; - - -} /* namespace OT */ - +#include "OT/glyf/glyf.hh" #endif /* HB_OT_GLYF_TABLE_HH */ diff --git a/thirdparty/harfbuzz/src/hb-ot-hmtx-table.hh b/thirdparty/harfbuzz/src/hb-ot-hmtx-table.hh index d5e1fc91d2..d0e46e0b0f 100644 --- a/thirdparty/harfbuzz/src/hb-ot-hmtx-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-hmtx-table.hh @@ -242,7 +242,7 @@ struct hmtxvmtx return side_bearing; if (var_table.get_length ()) - return side_bearing + var_table->get_side_bearing_var (glyph, font->coords, font->num_coords); // TODO Optimize?! + return side_bearing + var_table->get_side_bearing_var (glyph, font->coords, font->num_coords); return _glyf_get_side_bearing_var (font, glyph, T::tableTag == HB_OT_TAG_vmtx); #else @@ -284,7 +284,8 @@ struct hmtxvmtx } unsigned int get_advance (hb_codepoint_t glyph, - hb_font_t *font) const + hb_font_t *font, + VariationStore::cache_t *store_cache = nullptr) const { unsigned int advance = get_advance (glyph); @@ -293,7 +294,7 @@ struct hmtxvmtx return advance; if (var_table.get_length ()) - return advance + roundf (var_table->get_advance_var (glyph, font)); // TODO Optimize?! + return advance + roundf (var_table->get_advance_var (glyph, font, store_cache)); // TODO Optimize?! return _glyf_get_advance_var (font, glyph, T::tableTag == HB_OT_TAG_vmtx); #else @@ -310,7 +311,7 @@ struct hmtxvmtx unsigned int default_advance; - private: + public: hb_blob_ptr_t<hmtxvmtx> table; hb_blob_ptr_t<HVARVVAR> var_table; }; diff --git a/thirdparty/harfbuzz/src/hb-ot-layout-common.hh b/thirdparty/harfbuzz/src/hb-ot-layout-common.hh index f2a58028e3..d343805346 100644 --- a/thirdparty/harfbuzz/src/hb-ot-layout-common.hh +++ b/thirdparty/harfbuzz/src/hb-ot-layout-common.hh @@ -91,18 +91,18 @@ template<typename Iterator> static inline void ClassDef_serialize (hb_serialize_context_t *c, Iterator it); -static void ClassDef_remap_and_serialize (hb_serialize_context_t *c, - const hb_map_t &gid_klass_map, - hb_sorted_vector_t<HBGlyphID16> &glyphs, - const hb_set_t &klasses, - bool use_class_zero, - hb_map_t *klass_map /*INOUT*/); +static void ClassDef_remap_and_serialize ( + hb_serialize_context_t *c, + const hb_set_t &klasses, + bool use_class_zero, + hb_sorted_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> &glyph_and_klass, /* IN/OUT */ + hb_map_t *klass_map /*IN/OUT*/); struct hb_prune_langsys_context_t { hb_prune_langsys_context_t (const void *table_, - hb_hashmap_t<unsigned, hb_set_t *> *script_langsys_map_, + hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *script_langsys_map_, const hb_map_t *duplicate_feature_map_, hb_set_t *new_collected_feature_indexes_) :table (table_), @@ -122,7 +122,7 @@ struct hb_prune_langsys_context_t public: const void *table; - hb_hashmap_t<unsigned, hb_set_t *> *script_langsys_map; + hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *script_langsys_map; const hb_map_t *duplicate_feature_map; hb_set_t *new_feature_indexes; @@ -162,14 +162,14 @@ struct hb_subset_layout_context_t : hb_subset_context_t *subset_context; const hb_tag_t table_tag; const hb_map_t *lookup_index_map; - const hb_hashmap_t<unsigned, hb_set_t *> *script_langsys_map; + const hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *script_langsys_map; const hb_map_t *feature_index_map; unsigned cur_script_index; hb_subset_layout_context_t (hb_subset_context_t *c_, hb_tag_t tag_, hb_map_t *lookup_map_, - hb_hashmap_t<unsigned, hb_set_t *> *script_langsys_map_, + hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *script_langsys_map_, hb_map_t *feature_index_map_) : subset_context (c_), table_tag (tag_), @@ -659,7 +659,8 @@ struct LangSys auto *out = c->serializer->start_embed (*this); if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); - out->reqFeatureIndex = l->feature_index_map->has (reqFeatureIndex) ? l->feature_index_map->get (reqFeatureIndex) : 0xFFFFu; + const unsigned *v; + out->reqFeatureIndex = l->feature_index_map->has (reqFeatureIndex, &v) ? *v : 0xFFFFu; if (!l->visitFeatureIndex (featureIndex.len)) return_trace (false); @@ -722,12 +723,8 @@ struct Script if (!c->script_langsys_map->has (script_index)) { - hb_set_t* empty_set = hb_set_create (); - if (unlikely (!c->script_langsys_map->set (script_index, empty_set))) - { - hb_set_destroy (empty_set); + if (unlikely (!c->script_langsys_map->set (script_index, hb::unique_ptr<hb_set_t> {hb_set_create ()}))) return; - } } unsigned langsys_count = get_lang_sys_count (); @@ -1470,7 +1467,8 @@ struct CoverageFormat1 void next () { i++; } hb_codepoint_t get_glyph () const { return c->glyphArray[i]; } bool operator != (const iter_t& o) const - { return i != o.i || c != o.c; } + { return i != o.i; } + iter_t __end__ () const { iter_t it; it.init (*c); it.i = c->glyphArray.len; return it; } private: const struct CoverageFormat1 *c; @@ -1506,12 +1504,6 @@ struct CoverageFormat2 TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (this))) return_trace (false); - if (unlikely (!glyphs)) - { - rangeRecord.len = 0; - return_trace (true); - } - /* TODO(iter) Write more efficiently? */ unsigned num_ranges = 0; @@ -1524,6 +1516,7 @@ struct CoverageFormat2 } if (unlikely (!rangeRecord.serialize (c, num_ranges))) return_trace (false); + if (!num_ranges) return_trace (true); unsigned count = 0; unsigned range = (unsigned) -1; @@ -1552,25 +1545,26 @@ struct CoverageFormat2 bool intersects (const hb_set_t *glyphs) const { - /* TODO Speed up, using hb_set_next() and bsearch()? */ - /* TODO(iter) Rewrite as dagger. */ - for (const auto& range : rangeRecord.as_array ()) - if (range.intersects (glyphs)) - return true; - return false; + return hb_any (+ hb_iter (rangeRecord.as_array ()) + | hb_map ([glyphs] (const RangeRecord &range) { return range.intersects (glyphs); })); } bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const { - /* TODO(iter) Rewrite as dagger. */ - for (const auto& range : rangeRecord.as_array ()) + auto cmp = [] (const void *pk, const void *pr) -> int { - if (range.value <= index && - index < (unsigned int) range.value + (range.last - range.first) && - range.intersects (glyphs)) - return true; - else if (index < range.value) - return false; - } + unsigned index = * (const unsigned *) pk; + const RangeRecord &range = * (const RangeRecord *) pr; + if (index < range.value) return -1; + if (index > (unsigned int) range.value + (range.last - range.first)) return +1; + return 0; + }; + + auto arr = rangeRecord.as_array (); + unsigned idx; + if (hb_bsearch_impl (&idx, index, + arr.arrayZ, arr.length, sizeof (arr[0]), + (int (*)(const void *_key, const void *_item)) cmp)) + return arr.arrayZ[idx].intersects (glyphs); return false; } @@ -1579,8 +1573,10 @@ struct CoverageFormat2 for (const auto& range : rangeRecord.as_array ()) { if (!range.intersects (glyphs)) continue; - for (hb_codepoint_t g = range.first; g <= range.last; g++) - if (glyphs->has (g)) intersect_glyphs->add (g); + unsigned last = range.last; + for (hb_codepoint_t g = range.first - 1; + glyphs->next (&g) && g <= last;) + intersect_glyphs->add (g); } } @@ -1632,6 +1628,8 @@ struct CoverageFormat2 return; } } + else + j = 0; return; } coverage++; @@ -1639,7 +1637,15 @@ struct CoverageFormat2 } hb_codepoint_t get_glyph () const { return j; } bool operator != (const iter_t& o) const - { return i != o.i || j != o.j || c != o.c; } + { return i != o.i || j != o.j; } + iter_t __end__ () const + { + iter_t it; + it.init (*c); + it.i = c->rangeRecord.len; + it.j = 0; + return it; + } private: const struct CoverageFormat2 *c; @@ -1708,18 +1714,17 @@ struct Coverage bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - const hb_set_t &glyphset = *c->plan->glyphset_gsub (); - const hb_map_t &glyph_map = *c->plan->glyph_map; - auto it = + iter () - | hb_filter (glyphset) - | hb_map_retains_sorting (glyph_map) + | hb_filter (c->plan->glyph_map_gsub) + | hb_map_retains_sorting (c->plan->glyph_map_gsub) ; - bool ret = bool (it); - Coverage_serialize (c->serializer, it); - return_trace (ret); + // Cache the iterator result as it will be iterated multiple times + // by the serialize code below. + hb_sorted_vector_t<hb_codepoint_t> glyphs (it); + Coverage_serialize (c->serializer, glyphs.iter ()); + return_trace (bool (glyphs)); } bool sanitize (hb_sanitize_context_t *c) const @@ -1822,7 +1827,7 @@ struct Coverage } bool operator != (const iter_t& o) const { - if (format != o.format) return true; + if (unlikely (format != o.format)) return true; switch (format) { case 1: return u.format1 != o.u.format1; @@ -1830,6 +1835,18 @@ struct Coverage default:return false; } } + iter_t __end__ () const + { + iter_t it = {}; + it.format = format; + switch (format) + { + case 1: it.u.format1 = u.format1.__end__ (); break; + case 2: it.u.format2 = u.format2.__end__ (); break; + default: break; + } + return it; + } private: unsigned int format; @@ -1857,16 +1874,14 @@ Coverage_serialize (hb_serialize_context_t *c, { c->start_embed<Coverage> ()->serialize (c, it); } static void ClassDef_remap_and_serialize (hb_serialize_context_t *c, - const hb_map_t &gid_klass_map, - hb_sorted_vector_t<HBGlyphID16> &glyphs, const hb_set_t &klasses, bool use_class_zero, - hb_map_t *klass_map /*INOUT*/) + hb_sorted_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> &glyph_and_klass, /* IN/OUT */ + hb_map_t *klass_map /*IN/OUT*/) { if (!klass_map) { - ClassDef_serialize (c, hb_zip (glyphs.iter (), + glyphs.iter () - | hb_map (gid_klass_map))); + ClassDef_serialize (c, glyph_and_klass.iter ()); return; } @@ -1883,17 +1898,15 @@ static void ClassDef_remap_and_serialize (hb_serialize_context_t *c, idx++; } - auto it = - + glyphs.iter () - | hb_map_retains_sorting ([&] (const HBGlyphID16& gid) -> hb_pair_t<hb_codepoint_t, unsigned> - { - unsigned new_klass = klass_map->get (gid_klass_map[gid]); - return hb_pair ((hb_codepoint_t)gid, new_klass); - }) - ; - c->propagate_error (glyphs, klasses); - ClassDef_serialize (c, it); + for (unsigned i = 0; i < glyph_and_klass.length; i++) + { + hb_codepoint_t klass = glyph_and_klass[i].second; + glyph_and_klass[i].second = klass_map->get (klass); + } + + c->propagate_error (glyph_and_klass, klasses); + ClassDef_serialize (c, glyph_and_klass.iter ()); } /* @@ -1949,36 +1962,37 @@ struct ClassDefFormat1 const Coverage* glyph_filter = nullptr) const { TRACE_SUBSET (this); - const hb_set_t &glyphset = *c->plan->glyphset_gsub (); - const hb_map_t &glyph_map = *c->plan->glyph_map; + const hb_map_t &glyph_map = *c->plan->glyph_map_gsub; - hb_sorted_vector_t<HBGlyphID16> glyphs; + hb_sorted_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> glyph_and_klass; hb_set_t orig_klasses; - hb_map_t gid_org_klass_map; hb_codepoint_t start = startGlyph; hb_codepoint_t end = start + classValue.len; - for (const hb_codepoint_t gid : + hb_range (start, end) - | hb_filter (glyphset)) + for (const hb_codepoint_t gid : + hb_range (start, end)) { + hb_codepoint_t new_gid = glyph_map[gid]; + if (new_gid == HB_MAP_VALUE_INVALID) continue; if (glyph_filter && !glyph_filter->has(gid)) continue; unsigned klass = classValue[gid - start]; if (!klass) continue; - glyphs.push (glyph_map[gid]); - gid_org_klass_map.set (glyph_map[gid], klass); + glyph_and_klass.push (hb_pair (new_gid, klass)); orig_klasses.add (klass); } unsigned glyph_count = glyph_filter - ? hb_len (hb_iter (glyphset) | hb_filter (glyph_filter)) - : glyphset.get_population (); - use_class_zero = use_class_zero && glyph_count <= gid_org_klass_map.get_population (); - ClassDef_remap_and_serialize (c->serializer, gid_org_klass_map, - glyphs, orig_klasses, use_class_zero, klass_map); - return_trace (keep_empty_table || (bool) glyphs); + ? hb_len (hb_iter (glyph_map.keys()) | hb_filter (glyph_filter)) + : glyph_map.get_population (); + use_class_zero = use_class_zero && glyph_count <= glyph_and_klass.length; + ClassDef_remap_and_serialize (c->serializer, + orig_klasses, + use_class_zero, + glyph_and_klass, + klass_map); + return_trace (keep_empty_table || (bool) glyph_and_klass); } bool sanitize (hb_sanitize_context_t *c) const @@ -1987,6 +2001,8 @@ struct ClassDefFormat1 return_trace (c->check_struct (this) && classValue.sanitize (c)); } + unsigned cost () const { return 1; } + template <typename set_t> bool collect_coverage (set_t *glyphs) const { @@ -2044,10 +2060,9 @@ struct ClassDefFormat1 } /* TODO Speed up, using set overlap first? */ /* TODO(iter) Rewrite as dagger. */ - HBUINT16 k {klass}; const HBUINT16 *arr = classValue.arrayZ; for (unsigned int i = 0; i < count; i++) - if (arr[i] == k && glyphs->has (startGlyph + i)) + if (arr[i] == klass && glyphs->has (startGlyph + i)) return true; return false; } @@ -2057,17 +2072,32 @@ struct ClassDefFormat1 unsigned count = classValue.len; if (klass == 0) { - hb_codepoint_t endGlyph = startGlyph + count -1; - for (hb_codepoint_t g : glyphs->iter ()) - if (g < startGlyph || g > endGlyph) - intersect_glyphs->add (g); + unsigned start_glyph = startGlyph; + for (unsigned g = HB_SET_VALUE_INVALID; + hb_set_next (glyphs, &g) && g < start_glyph;) + intersect_glyphs->add (g); + + for (unsigned g = startGlyph + count - 1; + hb_set_next (glyphs, &g);) + intersect_glyphs->add (g); return; } for (unsigned i = 0; i < count; i++) if (classValue[i] == klass && glyphs->has (startGlyph + i)) - intersect_glyphs->add (startGlyph + i); + intersect_glyphs->add (startGlyph + i); + +#if 0 + /* The following implementation is faster asymptotically, but slower + * in practice. */ + unsigned start_glyph = startGlyph; + unsigned end_glyph = start_glyph + count; + for (unsigned g = startGlyph - 1; + hb_set_next (glyphs, &g) && g < end_glyph;) + if (classValue.arrayZ[g - start_glyph] == klass) + intersect_glyphs->add (g); +#endif } void intersected_classes (const hb_set_t *glyphs, hb_set_t *intersect_classes) const @@ -2167,12 +2197,10 @@ struct ClassDefFormat2 const Coverage* glyph_filter = nullptr) const { TRACE_SUBSET (this); - const hb_set_t &glyphset = *c->plan->glyphset_gsub (); - const hb_map_t &glyph_map = *c->plan->glyph_map; + const hb_map_t &glyph_map = *c->plan->glyph_map_gsub; - hb_sorted_vector_t<HBGlyphID16> glyphs; + hb_sorted_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> glyph_and_klass; hb_set_t orig_klasses; - hb_map_t gid_org_klass_map; unsigned count = rangeRecord.len; for (unsigned i = 0; i < count; i++) @@ -2183,21 +2211,26 @@ struct ClassDefFormat2 hb_codepoint_t end = rangeRecord[i].last + 1; for (hb_codepoint_t g = start; g < end; g++) { - if (!glyphset.has (g)) continue; + hb_codepoint_t new_gid = glyph_map[g]; + if (new_gid == HB_MAP_VALUE_INVALID) continue; if (glyph_filter && !glyph_filter->has (g)) continue; - glyphs.push (glyph_map[g]); - gid_org_klass_map.set (glyph_map[g], klass); + + glyph_and_klass.push (hb_pair (new_gid, klass)); orig_klasses.add (klass); } } + const hb_set_t& glyphset = *c->plan->glyphset_gsub (); unsigned glyph_count = glyph_filter ? hb_len (hb_iter (glyphset) | hb_filter (glyph_filter)) - : glyphset.get_population (); - use_class_zero = use_class_zero && glyph_count <= gid_org_klass_map.get_population (); - ClassDef_remap_and_serialize (c->serializer, gid_org_klass_map, - glyphs, orig_klasses, use_class_zero, klass_map); - return_trace (keep_empty_table || (bool) glyphs); + : glyph_map.get_population (); + use_class_zero = use_class_zero && glyph_count <= glyph_and_klass.length; + ClassDef_remap_and_serialize (c->serializer, + orig_klasses, + use_class_zero, + glyph_and_klass, + klass_map); + return_trace (keep_empty_table || (bool) glyph_and_klass); } bool sanitize (hb_sanitize_context_t *c) const @@ -2206,6 +2239,8 @@ struct ClassDefFormat2 return_trace (rangeRecord.sanitize (c)); } + unsigned cost () const { return hb_bit_storage ((unsigned) rangeRecord.len); /* bsearch cost */ } + template <typename set_t> bool collect_coverage (set_t *glyphs) const { @@ -2263,10 +2298,9 @@ struct ClassDefFormat2 } /* TODO Speed up, using set overlap first? */ /* TODO(iter) Rewrite as dagger. */ - HBUINT16 k {klass}; const RangeRecord *arr = rangeRecord.arrayZ; for (unsigned int i = 0; i < count; i++) - if (arr[i].value == k && arr[i].intersects (glyphs)) + if (arr[i].value == klass && arr[i].intersects (glyphs)) return true; return false; } @@ -2279,43 +2313,44 @@ struct ClassDefFormat2 hb_codepoint_t g = HB_SET_VALUE_INVALID; for (unsigned int i = 0; i < count; i++) { - if (!hb_set_next (glyphs, &g)) - break; - while (g != HB_SET_VALUE_INVALID && g < rangeRecord[i].first) - { - intersect_glyphs->add (g); - hb_set_next (glyphs, &g); + if (!hb_set_next (glyphs, &g)) + goto done; + while (g < rangeRecord[i].first) + { + intersect_glyphs->add (g); + if (!hb_set_next (glyphs, &g)) + goto done; } g = rangeRecord[i].last; } - while (g != HB_SET_VALUE_INVALID && hb_set_next (glyphs, &g)) - intersect_glyphs->add (g); + while (hb_set_next (glyphs, &g)) + intersect_glyphs->add (g); + done: return; } - hb_codepoint_t g = HB_SET_VALUE_INVALID; +#if 0 + /* The following implementation is faster asymptotically, but slower + * in practice. */ + if ((count >> 3) > glyphs->get_population ()) + { + for (hb_codepoint_t g = HB_SET_VALUE_INVALID; + hb_set_next (glyphs, &g);) + if (rangeRecord.as_array ().bfind (g)) + intersect_glyphs->add (g); + return; + } +#endif + for (unsigned int i = 0; i < count; i++) { if (rangeRecord[i].value != klass) continue; - if (g != HB_SET_VALUE_INVALID) - { - if (g >= rangeRecord[i].first && - g <= rangeRecord[i].last) - intersect_glyphs->add (g); - if (g > rangeRecord[i].last) - continue; - } - - g = rangeRecord[i].first - 1; - while (hb_set_next (glyphs, &g)) - { - if (g >= rangeRecord[i].first && g <= rangeRecord[i].last) - intersect_glyphs->add (g); - else if (g > rangeRecord[i].last) - break; - } + unsigned end = rangeRecord[i].last + 1; + for (hb_codepoint_t g = rangeRecord[i].first - 1; + hb_set_next (glyphs, &g) && g < end;) + intersect_glyphs->add (g); } } @@ -2446,6 +2481,15 @@ struct ClassDef } } + unsigned cost () const + { + switch (u.format) { + case 1: return u.format1.cost (); + case 2: return u.format2.cost (); + default:return 0u; + } + } + /* Might return false if array looks unsorted. * Used for faster rejection of corrupt data. */ template <typename set_t> @@ -2567,14 +2611,27 @@ struct VarRegionAxis DEFINE_SIZE_STATIC (6); }; +#define REGION_CACHE_ITEM_CACHE_INVALID 2.f + struct VarRegionList { + using cache_t = float; + float evaluate (unsigned int region_index, - const int *coords, unsigned int coord_len) const + const int *coords, unsigned int coord_len, + cache_t *cache = nullptr) const { if (unlikely (region_index >= regionCount)) return 0.; + float *cached_value = nullptr; + if (cache) + { + cached_value = &(cache[region_index]); + if (likely (*cached_value != REGION_CACHE_ITEM_CACHE_INVALID)) + return *cached_value; + } + const VarRegionAxis *axes = axesZ.arrayZ + (region_index * axisCount); float v = 1.; @@ -2584,9 +2641,16 @@ struct VarRegionList int coord = i < coord_len ? coords[i] : 0; float factor = axes[i].evaluate (coord); if (factor == 0.f) + { + if (cache) + *cached_value = 0.; return 0.; + } v *= factor; } + + if (cache) + *cached_value = v; return v; } @@ -2634,7 +2698,7 @@ struct VarData { return regionIndices.len; } unsigned int get_row_size () const - { return shortCount + regionIndices.len; } + { return (wordCount () + regionIndices.len) * (longWords () ? 2 : 1); } unsigned int get_size () const { return min_size @@ -2644,13 +2708,17 @@ struct VarData float get_delta (unsigned int inner, const int *coords, unsigned int coord_count, - const VarRegionList ®ions) const + const VarRegionList ®ions, + VarRegionList::cache_t *cache = nullptr) const { if (unlikely (inner >= itemCount)) return 0.; unsigned int count = regionIndices.len; - unsigned int scount = shortCount; + bool is_long = longWords (); + unsigned word_count = wordCount (); + unsigned int scount = is_long ? count - word_count : word_count; + unsigned int lcount = is_long ? word_count : 0; const HBUINT8 *bytes = get_delta_bytes (); const HBUINT8 *row = bytes + inner * (scount + count); @@ -2658,16 +2726,22 @@ struct VarData float delta = 0.; unsigned int i = 0; - const HBINT16 *scursor = reinterpret_cast<const HBINT16 *> (row); + const HBINT16 *lcursor = reinterpret_cast<const HBINT16 *> (row); + for (; i < lcount; i++) + { + float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count, cache); + delta += scalar * *lcursor++; + } + const HBINT16 *scursor = reinterpret_cast<const HBINT16 *> (lcursor); for (; i < scount; i++) { - float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count); + float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count, cache); delta += scalar * *scursor++; } const HBINT8 *bcursor = reinterpret_cast<const HBINT8 *> (scursor); for (; i < count; i++) { - float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count); + float scalar = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count, cache); delta += scalar * *bcursor++; } @@ -2691,7 +2765,7 @@ struct VarData TRACE_SANITIZE (this); return_trace (c->check_struct (this) && regionIndices.sanitize (c) && - shortCount <= regionIndices.len && + wordCount () <= regionIndices.len && c->check_range (get_delta_bytes (), itemCount, get_row_size ())); @@ -2706,43 +2780,66 @@ struct VarData if (unlikely (!c->extend_min (this))) return_trace (false); itemCount = inner_map.get_next_value (); - /* Optimize short count */ - unsigned short ri_count = src->regionIndices.len; - enum delta_size_t { kZero=0, kByte, kShort }; + /* Optimize word count */ + unsigned ri_count = src->regionIndices.len; + enum delta_size_t { kZero=0, kNonWord, kWord }; hb_vector_t<delta_size_t> delta_sz; hb_vector_t<unsigned int> ri_map; /* maps old index to new index */ delta_sz.resize (ri_count); ri_map.resize (ri_count); - unsigned int new_short_count = 0; + unsigned int new_word_count = 0; unsigned int r; + + bool has_long = false; + if (src->longWords ()) + { + for (r = 0; r < ri_count; r++) + { + for (unsigned int i = 0; i < inner_map.get_next_value (); i++) + { + unsigned int old = inner_map.backward (i); + int32_t delta = src->get_item_delta (old, r); + if (delta < -65536 || 65535 < delta) + { + has_long = true; + break; + } + } + } + } + + signed min_threshold = has_long ? -65536 : -128; + signed max_threshold = has_long ? +65535 : +127; for (r = 0; r < ri_count; r++) { delta_sz[r] = kZero; for (unsigned int i = 0; i < inner_map.get_next_value (); i++) { unsigned int old = inner_map.backward (i); - int16_t delta = src->get_item_delta (old, r); - if (delta < -128 || 127 < delta) + int32_t delta = src->get_item_delta (old, r); + if (delta < min_threshold || max_threshold < delta) { - delta_sz[r] = kShort; - new_short_count++; + delta_sz[r] = kWord; + new_word_count++; break; } else if (delta != 0) - delta_sz[r] = kByte; + delta_sz[r] = kNonWord; } } - unsigned int short_index = 0; - unsigned int byte_index = new_short_count; + + unsigned int word_index = 0; + unsigned int non_word_index = new_word_count; unsigned int new_ri_count = 0; for (r = 0; r < ri_count; r++) if (delta_sz[r]) { - ri_map[r] = (delta_sz[r] == kShort)? short_index++ : byte_index++; + ri_map[r] = (delta_sz[r] == kWord)? word_index++ : non_word_index++; new_ri_count++; } - shortCount = new_short_count; + wordSizeCount = new_word_count | (has_long ? 0x8000u /* LONG_WORDS */ : 0); + regionIndices.len = new_ri_count; if (unlikely (!c->extend (this))) return_trace (false); @@ -2782,28 +2879,55 @@ struct VarData HBUINT8 *get_delta_bytes () { return &StructAfter<HBUINT8> (regionIndices); } - int16_t get_item_delta (unsigned int item, unsigned int region) const + int32_t get_item_delta (unsigned int item, unsigned int region) const { if ( item >= itemCount || unlikely (region >= regionIndices.len)) return 0; - const HBINT8 *p = (const HBINT8 *)get_delta_bytes () + item * get_row_size (); - if (region < shortCount) - return ((const HBINT16 *)p)[region]; + const HBINT8 *p = (const HBINT8 *) get_delta_bytes () + item * get_row_size (); + unsigned word_count = wordCount (); + bool is_long = longWords (); + if (is_long) + { + if (region < word_count) + return ((const HBINT32 *) p)[region]; + else + return ((const HBINT16 *)(p + HBINT32::static_size * word_count))[region - word_count]; + } else - return (p + HBINT16::static_size * shortCount)[region - shortCount]; + { + if (region < word_count) + return ((const HBINT16 *) p)[region]; + else + return (p + HBINT16::static_size * word_count)[region - word_count]; + } } - void set_item_delta (unsigned int item, unsigned int region, int16_t delta) + void set_item_delta (unsigned int item, unsigned int region, int32_t delta) { HBINT8 *p = (HBINT8 *)get_delta_bytes () + item * get_row_size (); - if (region < shortCount) - ((HBINT16 *)p)[region] = delta; + unsigned word_count = wordCount (); + bool is_long = longWords (); + if (is_long) + { + if (region < word_count) + ((HBINT32 *) p)[region] = delta; + else + ((HBINT16 *)(p + HBINT32::static_size * word_count))[region - word_count] = delta; + } else - (p + HBINT16::static_size * shortCount)[region - shortCount] = delta; + { + if (region < word_count) + ((HBINT16 *) p)[region] = delta; + else + (p + HBINT16::static_size * word_count)[region - word_count] = delta; + } } + bool longWords () const { return wordSizeCount & 0x8000u /* LONG_WORDS */; } + unsigned wordCount () const { return wordSizeCount & 0x7FFFu /* WORD_DELTA_COUNT_MASK */; } + protected: HBUINT16 itemCount; - HBUINT16 shortCount; + HBUINT16 wordSizeCount; Array16Of<HBUINT16> regionIndices; /*UnsizedArrayOf<HBUINT8>bytesX;*/ public: @@ -2812,9 +2936,28 @@ struct VarData struct VariationStore { + using cache_t = VarRegionList::cache_t; + + cache_t *create_cache () const + { + auto &r = this+regions; + unsigned count = r.regionCount; + + float *cache = (float *) hb_malloc (sizeof (float) * count); + if (unlikely (!cache)) return nullptr; + + for (unsigned i = 0; i < count; i++) + cache[i] = REGION_CACHE_ITEM_CACHE_INVALID; + + return cache; + } + + static void destroy_cache (cache_t *cache) { hb_free (cache); } + private: float get_delta (unsigned int outer, unsigned int inner, - const int *coords, unsigned int coord_count) const + const int *coords, unsigned int coord_count, + VarRegionList::cache_t *cache = nullptr) const { #ifdef HB_NO_VAR return 0.f; @@ -2825,16 +2968,18 @@ struct VariationStore return (this+dataSets[outer]).get_delta (inner, coords, coord_count, - this+regions); + this+regions, + cache); } public: float get_delta (unsigned int index, - const int *coords, unsigned int coord_count) const + const int *coords, unsigned int coord_count, + VarRegionList::cache_t *cache = nullptr) const { unsigned int outer = index >> 16; unsigned int inner = index & 0xFFFF; - return get_delta (outer, inner, coords, coord_count); + return get_delta (outer, inner, coords, coord_count, cache); } bool sanitize (hb_sanitize_context_t *c) const @@ -2961,6 +3106,8 @@ struct VariationStore DEFINE_SIZE_ARRAY_SIZED (8, dataSets); }; +#undef REGION_CACHE_ITEM_CACHE_INVALID + /* * Feature Variations */ @@ -3428,11 +3575,15 @@ struct VariationDevice private: - hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store) const - { return font->em_scalef_x (get_delta (font, store)); } + hb_position_t get_x_delta (hb_font_t *font, + const VariationStore &store, + VariationStore::cache_t *store_cache = nullptr) const + { return font->em_scalef_x (get_delta (font, store, store_cache)); } - hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store) const - { return font->em_scalef_y (get_delta (font, store)); } + hb_position_t get_y_delta (hb_font_t *font, + const VariationStore &store, + VariationStore::cache_t *store_cache = nullptr) const + { return font->em_scalef_y (get_delta (font, store, store_cache)); } VariationDevice* copy (hb_serialize_context_t *c, const hb_map_t *layout_variation_idx_map) const { @@ -3466,9 +3617,11 @@ struct VariationDevice private: - float get_delta (hb_font_t *font, const VariationStore &store) const + float get_delta (hb_font_t *font, + const VariationStore &store, + VariationStore::cache_t *store_cache = nullptr) const { - return store.get_delta (varIdx, font->coords, font->num_coords); + return store.get_delta (varIdx, font->coords, font->num_coords, (VariationStore::cache_t *) store_cache); } protected: @@ -3491,7 +3644,9 @@ struct DeviceHeader struct Device { - hb_position_t get_x_delta (hb_font_t *font, const VariationStore &store=Null (VariationStore)) const + hb_position_t get_x_delta (hb_font_t *font, + const VariationStore &store=Null (VariationStore), + VariationStore::cache_t *store_cache = nullptr) const { switch (u.b.format) { @@ -3501,13 +3656,15 @@ struct Device #endif #ifndef HB_NO_VAR case 0x8000: - return u.variation.get_x_delta (font, store); + return u.variation.get_x_delta (font, store, store_cache); #endif default: return 0; } } - hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store=Null (VariationStore)) const + hb_position_t get_y_delta (hb_font_t *font, + const VariationStore &store=Null (VariationStore), + VariationStore::cache_t *store_cache = nullptr) const { switch (u.b.format) { @@ -3517,7 +3674,7 @@ struct Device #endif #ifndef HB_NO_VAR case 0x8000: - return u.variation.get_y_delta (font, store); + return u.variation.get_y_delta (font, store, store_cache); #endif default: return 0; diff --git a/thirdparty/harfbuzz/src/hb-ot-layout-gdef-table.hh b/thirdparty/harfbuzz/src/hb-ot-layout-gdef-table.hh index a76d644c4b..9d47bac2b9 100644 --- a/thirdparty/harfbuzz/src/hb-ot-layout-gdef-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-layout-gdef-table.hh @@ -571,7 +571,7 @@ struct GDEF static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_MARK == (unsigned int) LookupFlag::IgnoreMarks), ""); switch (klass) { - default: return 0; + default: return HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED; case BaseGlyph: return HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH; case LigatureGlyph: return HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE; case MarkGlyph: diff --git a/thirdparty/harfbuzz/src/hb-ot-layout-gpos-table.hh b/thirdparty/harfbuzz/src/hb-ot-layout-gpos-table.hh index 2f9186a2a7..064d31cdff 100644 --- a/thirdparty/harfbuzz/src/hb-ot-layout-gpos-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-layout-gpos-table.hh @@ -29,3090 +29,14 @@ #ifndef HB_OT_LAYOUT_GPOS_TABLE_HH #define HB_OT_LAYOUT_GPOS_TABLE_HH -#include "hb-ot-layout-gsubgpos.hh" - +#include "OT/Layout/GPOS.hh" namespace OT { -struct MarkArray; -static void Markclass_closure_and_remap_indexes (const Coverage &mark_coverage, - const MarkArray &mark_array, - const hb_set_t &glyphset, - hb_map_t* klass_mapping /* INOUT */); - -/* buffer **position** var allocations */ -#define attach_chain() var.i16[0] /* glyph to which this attaches to, relative to current glyphs; negative for going back, positive for forward. */ -#define attach_type() var.u8[2] /* attachment type */ -/* Note! if attach_chain() is zero, the value of attach_type() is irrelevant. */ - -enum attach_type_t { - ATTACH_TYPE_NONE = 0X00, - - /* Each attachment should be either a mark or a cursive; can't be both. */ - ATTACH_TYPE_MARK = 0X01, - ATTACH_TYPE_CURSIVE = 0X02, -}; - - -/* Shared Tables: ValueRecord, Anchor Table, and MarkArray */ - -typedef HBUINT16 Value; - -typedef UnsizedArrayOf<Value> ValueRecord; - -struct ValueFormat : HBUINT16 -{ - enum Flags { - xPlacement = 0x0001u, /* Includes horizontal adjustment for placement */ - yPlacement = 0x0002u, /* Includes vertical adjustment for placement */ - xAdvance = 0x0004u, /* Includes horizontal adjustment for advance */ - yAdvance = 0x0008u, /* Includes vertical adjustment for advance */ - xPlaDevice = 0x0010u, /* Includes horizontal Device table for placement */ - yPlaDevice = 0x0020u, /* Includes vertical Device table for placement */ - xAdvDevice = 0x0040u, /* Includes horizontal Device table for advance */ - yAdvDevice = 0x0080u, /* Includes vertical Device table for advance */ - ignored = 0x0F00u, /* Was used in TrueType Open for MM fonts */ - reserved = 0xF000u, /* For future use */ - - devices = 0x00F0u /* Mask for having any Device table */ - }; - -/* All fields are options. Only those available advance the value pointer. */ -#if 0 - HBINT16 xPlacement; /* Horizontal adjustment for - * placement--in design units */ - HBINT16 yPlacement; /* Vertical adjustment for - * placement--in design units */ - HBINT16 xAdvance; /* Horizontal adjustment for - * advance--in design units (only used - * for horizontal writing) */ - HBINT16 yAdvance; /* Vertical adjustment for advance--in - * design units (only used for vertical - * writing) */ - Offset16To<Device> xPlaDevice; /* Offset to Device table for - * horizontal placement--measured from - * beginning of PosTable (may be NULL) */ - Offset16To<Device> yPlaDevice; /* Offset to Device table for vertical - * placement--measured from beginning - * of PosTable (may be NULL) */ - Offset16To<Device> xAdvDevice; /* Offset to Device table for - * horizontal advance--measured from - * beginning of PosTable (may be NULL) */ - Offset16To<Device> yAdvDevice; /* Offset to Device table for vertical - * advance--measured from beginning of - * PosTable (may be NULL) */ -#endif - - IntType& operator = (uint16_t i) { v = i; return *this; } - - unsigned int get_len () const { return hb_popcount ((unsigned int) *this); } - unsigned int get_size () const { return get_len () * Value::static_size; } - - bool apply_value (hb_ot_apply_context_t *c, - const void *base, - const Value *values, - hb_glyph_position_t &glyph_pos) const - { - bool ret = false; - unsigned int format = *this; - if (!format) return ret; - - hb_font_t *font = c->font; - bool horizontal = -#ifndef HB_NO_VERTICAL - HB_DIRECTION_IS_HORIZONTAL (c->direction) -#else - true -#endif - ; - - if (format & xPlacement) glyph_pos.x_offset += font->em_scale_x (get_short (values++, &ret)); - if (format & yPlacement) glyph_pos.y_offset += font->em_scale_y (get_short (values++, &ret)); - if (format & xAdvance) { - if (likely (horizontal)) glyph_pos.x_advance += font->em_scale_x (get_short (values, &ret)); - values++; - } - /* y_advance values grow downward but font-space grows upward, hence negation */ - if (format & yAdvance) { - if (unlikely (!horizontal)) glyph_pos.y_advance -= font->em_scale_y (get_short (values, &ret)); - values++; - } - - if (!has_device ()) return ret; - - bool use_x_device = font->x_ppem || font->num_coords; - bool use_y_device = font->y_ppem || font->num_coords; - - if (!use_x_device && !use_y_device) return ret; - - const VariationStore &store = c->var_store; - - /* pixel -> fractional pixel */ - if (format & xPlaDevice) { - if (use_x_device) glyph_pos.x_offset += (base + get_device (values, &ret)).get_x_delta (font, store); - values++; - } - if (format & yPlaDevice) { - if (use_y_device) glyph_pos.y_offset += (base + get_device (values, &ret)).get_y_delta (font, store); - values++; - } - if (format & xAdvDevice) { - if (horizontal && use_x_device) glyph_pos.x_advance += (base + get_device (values, &ret)).get_x_delta (font, store); - values++; - } - if (format & yAdvDevice) { - /* y_advance values grow downward but font-space grows upward, hence negation */ - if (!horizontal && use_y_device) glyph_pos.y_advance -= (base + get_device (values, &ret)).get_y_delta (font, store); - values++; - } - return ret; - } - - unsigned int get_effective_format (const Value *values) const - { - unsigned int format = *this; - for (unsigned flag = xPlacement; flag <= yAdvDevice; flag = flag << 1) { - if (format & flag) should_drop (*values++, (Flags) flag, &format); - } - - return format; - } - - template<typename Iterator, - hb_requires (hb_is_iterator (Iterator))> - unsigned int get_effective_format (Iterator it) const { - unsigned int new_format = 0; - - for (const hb_array_t<const Value>& values : it) - new_format = new_format | get_effective_format (&values); - - return new_format; - } - - void copy_values (hb_serialize_context_t *c, - unsigned int new_format, - const void *base, - const Value *values, - const hb_map_t *layout_variation_idx_map) const - { - unsigned int format = *this; - if (!format) return; - - if (format & xPlacement) copy_value (c, new_format, xPlacement, *values++); - if (format & yPlacement) copy_value (c, new_format, yPlacement, *values++); - if (format & xAdvance) copy_value (c, new_format, xAdvance, *values++); - if (format & yAdvance) copy_value (c, new_format, yAdvance, *values++); - - if (format & xPlaDevice) copy_device (c, base, values++, layout_variation_idx_map); - if (format & yPlaDevice) copy_device (c, base, values++, layout_variation_idx_map); - if (format & xAdvDevice) copy_device (c, base, values++, layout_variation_idx_map); - if (format & yAdvDevice) copy_device (c, base, values++, layout_variation_idx_map); - } - - void copy_value (hb_serialize_context_t *c, - unsigned int new_format, - Flags flag, - Value value) const - { - // Filter by new format. - if (!(new_format & flag)) return; - c->copy (value); - } - - void collect_variation_indices (hb_collect_variation_indices_context_t *c, - const void *base, - const hb_array_t<const Value>& values) const - { - unsigned format = *this; - unsigned i = 0; - if (format & xPlacement) i++; - if (format & yPlacement) i++; - if (format & xAdvance) i++; - if (format & yAdvance) i++; - if (format & xPlaDevice) - { - (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices); - i++; - } - - if (format & ValueFormat::yPlaDevice) - { - (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices); - i++; - } - - if (format & ValueFormat::xAdvDevice) - { - - (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices); - i++; - } - - if (format & ValueFormat::yAdvDevice) - { - - (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices); - i++; - } - } - - private: - bool sanitize_value_devices (hb_sanitize_context_t *c, const void *base, const Value *values) const - { - unsigned int format = *this; - - if (format & xPlacement) values++; - if (format & yPlacement) values++; - if (format & xAdvance) values++; - if (format & yAdvance) values++; - - if ((format & xPlaDevice) && !get_device (values++).sanitize (c, base)) return false; - if ((format & yPlaDevice) && !get_device (values++).sanitize (c, base)) return false; - if ((format & xAdvDevice) && !get_device (values++).sanitize (c, base)) return false; - if ((format & yAdvDevice) && !get_device (values++).sanitize (c, base)) return false; - - return true; - } - - static inline Offset16To<Device>& get_device (Value* value) - { - return *static_cast<Offset16To<Device> *> (value); - } - static inline const Offset16To<Device>& get_device (const Value* value, bool *worked=nullptr) - { - if (worked) *worked |= bool (*value); - return *static_cast<const Offset16To<Device> *> (value); - } - - bool copy_device (hb_serialize_context_t *c, const void *base, - const Value *src_value, const hb_map_t *layout_variation_idx_map) const - { - Value *dst_value = c->copy (*src_value); - - if (!dst_value) return false; - if (*dst_value == 0) return true; - - *dst_value = 0; - c->push (); - if ((base + get_device (src_value)).copy (c, layout_variation_idx_map)) - { - c->add_link (*dst_value, c->pop_pack ()); - return true; - } - else - { - c->pop_discard (); - return false; - } - } - - static inline const HBINT16& get_short (const Value* value, bool *worked=nullptr) - { - if (worked) *worked |= bool (*value); - return *reinterpret_cast<const HBINT16 *> (value); - } - - public: - - bool has_device () const - { - unsigned int format = *this; - return (format & devices) != 0; - } - - bool sanitize_value (hb_sanitize_context_t *c, const void *base, const Value *values) const - { - TRACE_SANITIZE (this); - return_trace (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values))); - } - - bool sanitize_values (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count) const - { - TRACE_SANITIZE (this); - unsigned int len = get_len (); - - if (!c->check_range (values, count, get_size ())) return_trace (false); - - if (!has_device ()) return_trace (true); - - for (unsigned int i = 0; i < count; i++) { - if (!sanitize_value_devices (c, base, values)) - return_trace (false); - values += len; - } - - return_trace (true); - } - - /* Just sanitize referenced Device tables. Doesn't check the values themselves. */ - bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count, unsigned int stride) const - { - TRACE_SANITIZE (this); - - if (!has_device ()) return_trace (true); - - for (unsigned int i = 0; i < count; i++) { - if (!sanitize_value_devices (c, base, values)) - return_trace (false); - values += stride; - } - - return_trace (true); - } - - private: - - void should_drop (Value value, Flags flag, unsigned int* format) const - { - if (value) return; - *format = *format & ~flag; - } - -}; - -template<typename Iterator, typename SrcLookup> -static void SinglePos_serialize (hb_serialize_context_t *c, - const SrcLookup *src, - Iterator it, - const hb_map_t *layout_variation_idx_map); - - -struct AnchorFormat1 -{ - void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id HB_UNUSED, - float *x, float *y) const - { - hb_font_t *font = c->font; - *x = font->em_fscale_x (xCoordinate); - *y = font->em_fscale_y (yCoordinate); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this)); - } - - AnchorFormat1* copy (hb_serialize_context_t *c) const - { - TRACE_SERIALIZE (this); - AnchorFormat1* out = c->embed<AnchorFormat1> (this); - if (!out) return_trace (out); - out->format = 1; - return_trace (out); - } - - protected: - HBUINT16 format; /* Format identifier--format = 1 */ - FWORD xCoordinate; /* Horizontal value--in design units */ - FWORD yCoordinate; /* Vertical value--in design units */ - public: - DEFINE_SIZE_STATIC (6); -}; - -struct AnchorFormat2 -{ - void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id, - float *x, float *y) const - { - hb_font_t *font = c->font; - -#ifdef HB_NO_HINTING - *x = font->em_fscale_x (xCoordinate); - *y = font->em_fscale_y (yCoordinate); - return; -#endif - - unsigned int x_ppem = font->x_ppem; - unsigned int y_ppem = font->y_ppem; - hb_position_t cx = 0, cy = 0; - bool ret; - - ret = (x_ppem || y_ppem) && - font->get_glyph_contour_point_for_origin (glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy); - *x = ret && x_ppem ? cx : font->em_fscale_x (xCoordinate); - *y = ret && y_ppem ? cy : font->em_fscale_y (yCoordinate); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this)); - } - - AnchorFormat2* copy (hb_serialize_context_t *c) const - { - TRACE_SERIALIZE (this); - return_trace (c->embed<AnchorFormat2> (this)); - } - - protected: - HBUINT16 format; /* Format identifier--format = 2 */ - FWORD xCoordinate; /* Horizontal value--in design units */ - FWORD yCoordinate; /* Vertical value--in design units */ - HBUINT16 anchorPoint; /* Index to glyph contour point */ - public: - DEFINE_SIZE_STATIC (8); -}; - -struct AnchorFormat3 -{ - void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id HB_UNUSED, - float *x, float *y) const - { - hb_font_t *font = c->font; - *x = font->em_fscale_x (xCoordinate); - *y = font->em_fscale_y (yCoordinate); - - if (font->x_ppem || font->num_coords) - *x += (this+xDeviceTable).get_x_delta (font, c->var_store); - if (font->y_ppem || font->num_coords) - *y += (this+yDeviceTable).get_y_delta (font, c->var_store); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this)); - } - - AnchorFormat3* copy (hb_serialize_context_t *c, - const hb_map_t *layout_variation_idx_map) const - { - TRACE_SERIALIZE (this); - if (!layout_variation_idx_map) return_trace (nullptr); - - auto *out = c->embed<AnchorFormat3> (this); - if (unlikely (!out)) return_trace (nullptr); - - out->xDeviceTable.serialize_copy (c, xDeviceTable, this, 0, hb_serialize_context_t::Head, layout_variation_idx_map); - out->yDeviceTable.serialize_copy (c, yDeviceTable, this, 0, hb_serialize_context_t::Head, layout_variation_idx_map); - return_trace (out); - } - - void collect_variation_indices (hb_collect_variation_indices_context_t *c) const - { - (this+xDeviceTable).collect_variation_indices (c->layout_variation_indices); - (this+yDeviceTable).collect_variation_indices (c->layout_variation_indices); - } - - protected: - HBUINT16 format; /* Format identifier--format = 3 */ - FWORD xCoordinate; /* Horizontal value--in design units */ - FWORD yCoordinate; /* Vertical value--in design units */ - Offset16To<Device> - xDeviceTable; /* Offset to Device table for X - * coordinate-- from beginning of - * Anchor table (may be NULL) */ - Offset16To<Device> - yDeviceTable; /* Offset to Device table for Y - * coordinate-- from beginning of - * Anchor table (may be NULL) */ - public: - DEFINE_SIZE_STATIC (10); -}; - -struct Anchor -{ - void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id, - float *x, float *y) const - { - *x = *y = 0; - switch (u.format) { - case 1: u.format1.get_anchor (c, glyph_id, x, y); return; - case 2: u.format2.get_anchor (c, glyph_id, x, y); return; - case 3: u.format3.get_anchor (c, glyph_id, x, y); return; - default: return; - } - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - if (!u.format.sanitize (c)) return_trace (false); - switch (u.format) { - case 1: return_trace (u.format1.sanitize (c)); - case 2: return_trace (u.format2.sanitize (c)); - case 3: return_trace (u.format3.sanitize (c)); - default:return_trace (true); - } - } - - bool subset (hb_subset_context_t *c) const - { - TRACE_SUBSET (this); - switch (u.format) { - case 1: return_trace (bool (reinterpret_cast<Anchor *> (u.format1.copy (c->serializer)))); - case 2: - if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING) - { - // AnchorFormat 2 just containins extra hinting information, so - // if hints are being dropped convert to format 1. - return_trace (bool (reinterpret_cast<Anchor *> (u.format1.copy (c->serializer)))); - } - return_trace (bool (reinterpret_cast<Anchor *> (u.format2.copy (c->serializer)))); - case 3: return_trace (bool (reinterpret_cast<Anchor *> (u.format3.copy (c->serializer, - c->plan->layout_variation_idx_map)))); - default:return_trace (false); - } - } - - void collect_variation_indices (hb_collect_variation_indices_context_t *c) const - { - switch (u.format) { - case 1: case 2: - return; - case 3: - u.format3.collect_variation_indices (c); - return; - default: return; - } - } - - protected: - union { - HBUINT16 format; /* Format identifier */ - AnchorFormat1 format1; - AnchorFormat2 format2; - AnchorFormat3 format3; - } u; - public: - DEFINE_SIZE_UNION (2, format); -}; - - -struct AnchorMatrix -{ - const Anchor& get_anchor (unsigned int row, unsigned int col, - unsigned int cols, bool *found) const - { - *found = false; - if (unlikely (row >= rows || col >= cols)) return Null (Anchor); - *found = !matrixZ[row * cols + col].is_null (); - return this+matrixZ[row * cols + col]; - } - - template <typename Iterator, - hb_requires (hb_is_iterator (Iterator))> - void collect_variation_indices (hb_collect_variation_indices_context_t *c, - Iterator index_iter) const - { - for (unsigned i : index_iter) - (this+matrixZ[i]).collect_variation_indices (c); - } - - template <typename Iterator, - hb_requires (hb_is_iterator (Iterator))> - bool subset (hb_subset_context_t *c, - unsigned num_rows, - Iterator index_iter) const - { - TRACE_SUBSET (this); - - auto *out = c->serializer->start_embed (this); - - if (!index_iter) return_trace (false); - if (unlikely (!c->serializer->extend_min (out))) return_trace (false); - - out->rows = num_rows; - for (const unsigned i : index_iter) - { - auto *offset = c->serializer->embed (matrixZ[i]); - if (!offset) return_trace (false); - offset->serialize_subset (c, matrixZ[i], this); - } - - return_trace (true); - } - - bool sanitize (hb_sanitize_context_t *c, unsigned int cols) const - { - TRACE_SANITIZE (this); - if (!c->check_struct (this)) return_trace (false); - if (unlikely (hb_unsigned_mul_overflows (rows, cols))) return_trace (false); - unsigned int count = rows * cols; - if (!c->check_array (matrixZ.arrayZ, count)) return_trace (false); - for (unsigned int i = 0; i < count; i++) - if (!matrixZ[i].sanitize (c, this)) return_trace (false); - return_trace (true); - } - - HBUINT16 rows; /* Number of rows */ - UnsizedArrayOf<Offset16To<Anchor>> - matrixZ; /* Matrix of offsets to Anchor tables-- - * from beginning of AnchorMatrix table */ - public: - DEFINE_SIZE_ARRAY (2, matrixZ); -}; - - -struct MarkRecord -{ - friend struct MarkArray; - - unsigned get_class () const { return (unsigned) klass; } - bool sanitize (hb_sanitize_context_t *c, const void *base) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && markAnchor.sanitize (c, base)); - } - - MarkRecord *subset (hb_subset_context_t *c, - const void *src_base, - const hb_map_t *klass_mapping) const - { - TRACE_SUBSET (this); - auto *out = c->serializer->embed (this); - if (unlikely (!out)) return_trace (nullptr); - - out->klass = klass_mapping->get (klass); - out->markAnchor.serialize_subset (c, markAnchor, src_base); - return_trace (out); - } - - void collect_variation_indices (hb_collect_variation_indices_context_t *c, - const void *src_base) const - { - (src_base+markAnchor).collect_variation_indices (c); - } - - protected: - HBUINT16 klass; /* Class defined for this mark */ - Offset16To<Anchor> - markAnchor; /* Offset to Anchor table--from - * beginning of MarkArray table */ - public: - DEFINE_SIZE_STATIC (4); -}; - -struct MarkArray : Array16Of<MarkRecord> /* Array of MarkRecords--in Coverage order */ -{ - bool apply (hb_ot_apply_context_t *c, - unsigned int mark_index, unsigned int glyph_index, - const AnchorMatrix &anchors, unsigned int class_count, - unsigned int glyph_pos) const - { - TRACE_APPLY (this); - hb_buffer_t *buffer = c->buffer; - const MarkRecord &record = Array16Of<MarkRecord>::operator[](mark_index); - unsigned int mark_class = record.klass; - - const Anchor& mark_anchor = this + record.markAnchor; - bool found; - const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count, &found); - /* If this subtable doesn't have an anchor for this base and this class, - * return false such that the subsequent subtables have a chance at it. */ - if (unlikely (!found)) return_trace (false); - - float mark_x, mark_y, base_x, base_y; - - buffer->unsafe_to_break (glyph_pos, buffer->idx + 1); - mark_anchor.get_anchor (c, buffer->cur().codepoint, &mark_x, &mark_y); - glyph_anchor.get_anchor (c, buffer->info[glyph_pos].codepoint, &base_x, &base_y); - - hb_glyph_position_t &o = buffer->cur_pos(); - o.x_offset = roundf (base_x - mark_x); - o.y_offset = roundf (base_y - mark_y); - o.attach_type() = ATTACH_TYPE_MARK; - o.attach_chain() = (int) glyph_pos - (int) buffer->idx; - buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT; - - buffer->idx++; - return_trace (true); - } - - template <typename Iterator, - hb_requires (hb_is_iterator (Iterator))> - bool subset (hb_subset_context_t *c, - Iterator coverage, - const hb_map_t *klass_mapping) const - { - TRACE_SUBSET (this); - const hb_set_t &glyphset = *c->plan->glyphset_gsub (); - - auto* out = c->serializer->start_embed (this); - if (unlikely (!c->serializer->extend_min (out))) return_trace (false); - - auto mark_iter = - + hb_zip (coverage, this->iter ()) - | hb_filter (glyphset, hb_first) - | hb_map (hb_second) - ; - - unsigned new_length = 0; - for (const auto& mark_record : mark_iter) { - if (unlikely (!mark_record.subset (c, this, klass_mapping))) - return_trace (false); - new_length++; - } - - if (unlikely (!c->serializer->check_assign (out->len, new_length, - HB_SERIALIZE_ERROR_ARRAY_OVERFLOW))) - return_trace (false); - - return_trace (true); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (Array16Of<MarkRecord>::sanitize (c, this)); - } -}; - - -/* Lookups */ - -struct SinglePosFormat1 -{ - bool intersects (const hb_set_t *glyphs) const - { return (this+coverage).intersects (glyphs); } - - void closure_lookups (hb_closure_lookups_context_t *c) const {} - void collect_variation_indices (hb_collect_variation_indices_context_t *c) const - { - if (!valueFormat.has_device ()) return; - - auto it = - + hb_iter (this+coverage) - | hb_filter (c->glyph_set) - ; - - if (!it) return; - valueFormat.collect_variation_indices (c, this, values.as_array (valueFormat.get_len ())); - } - - void collect_glyphs (hb_collect_glyphs_context_t *c) const - { if (unlikely (!(this+coverage).collect_coverage (c->input))) return; } - - const Coverage &get_coverage () const { return this+coverage; } - - ValueFormat get_value_format () const { return valueFormat; } - - bool apply (hb_ot_apply_context_t *c) const - { - TRACE_APPLY (this); - hb_buffer_t *buffer = c->buffer; - unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint); - if (likely (index == NOT_COVERED)) return_trace (false); - - valueFormat.apply_value (c, this, values, buffer->cur_pos()); - - buffer->idx++; - return_trace (true); - } - - template<typename Iterator, - typename SrcLookup, - hb_requires (hb_is_iterator (Iterator))> - void serialize (hb_serialize_context_t *c, - const SrcLookup *src, - Iterator it, - ValueFormat newFormat, - const hb_map_t *layout_variation_idx_map) - { - if (unlikely (!c->extend_min (this))) return; - if (unlikely (!c->check_assign (valueFormat, - newFormat, - HB_SERIALIZE_ERROR_INT_OVERFLOW))) return; - - for (const hb_array_t<const Value>& _ : + it | hb_map (hb_second)) - { - src->get_value_format ().copy_values (c, newFormat, src, &_, layout_variation_idx_map); - // Only serialize the first entry in the iterator, the rest are assumed to - // be the same. - break; - } - - auto glyphs = - + it - | hb_map_retains_sorting (hb_first) - ; - - coverage.serialize_serialize (c, glyphs); - } - - bool subset (hb_subset_context_t *c) const - { - TRACE_SUBSET (this); - const hb_set_t &glyphset = *c->plan->glyphset_gsub (); - const hb_map_t &glyph_map = *c->plan->glyph_map; - - auto it = - + hb_iter (this+coverage) - | hb_filter (glyphset) - | hb_map_retains_sorting (glyph_map) - | hb_zip (hb_repeat (values.as_array (valueFormat.get_len ()))) - ; - - bool ret = bool (it); - SinglePos_serialize (c->serializer, this, it, c->plan->layout_variation_idx_map); - return_trace (ret); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && - coverage.sanitize (c, this) && - valueFormat.sanitize_value (c, this, values)); - } - - protected: - HBUINT16 format; /* Format identifier--format = 1 */ - Offset16To<Coverage> - coverage; /* Offset to Coverage table--from - * beginning of subtable */ - ValueFormat valueFormat; /* Defines the types of data in the - * ValueRecord */ - ValueRecord values; /* Defines positioning - * value(s)--applied to all glyphs in - * the Coverage table */ - public: - DEFINE_SIZE_ARRAY (6, values); -}; - -struct SinglePosFormat2 -{ - bool intersects (const hb_set_t *glyphs) const - { return (this+coverage).intersects (glyphs); } - - void closure_lookups (hb_closure_lookups_context_t *c) const {} - void collect_variation_indices (hb_collect_variation_indices_context_t *c) const - { - if (!valueFormat.has_device ()) return; - - auto it = - + hb_zip (this+coverage, hb_range ((unsigned) valueCount)) - | hb_filter (c->glyph_set, hb_first) - ; - - if (!it) return; - - unsigned sub_length = valueFormat.get_len (); - const hb_array_t<const Value> values_array = values.as_array (valueCount * sub_length); - - for (unsigned i : + it - | hb_map (hb_second)) - valueFormat.collect_variation_indices (c, this, values_array.sub_array (i * sub_length, sub_length)); - - } - - void collect_glyphs (hb_collect_glyphs_context_t *c) const - { if (unlikely (!(this+coverage).collect_coverage (c->input))) return; } - - const Coverage &get_coverage () const { return this+coverage; } - - ValueFormat get_value_format () const { return valueFormat; } - - bool apply (hb_ot_apply_context_t *c) const - { - TRACE_APPLY (this); - hb_buffer_t *buffer = c->buffer; - unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint); - if (likely (index == NOT_COVERED)) return_trace (false); - - if (likely (index >= valueCount)) return_trace (false); - - valueFormat.apply_value (c, this, - &values[index * valueFormat.get_len ()], - buffer->cur_pos()); - - buffer->idx++; - return_trace (true); - } - - template<typename Iterator, - typename SrcLookup, - hb_requires (hb_is_iterator (Iterator))> - void serialize (hb_serialize_context_t *c, - const SrcLookup *src, - Iterator it, - ValueFormat newFormat, - const hb_map_t *layout_variation_idx_map) - { - auto out = c->extend_min (this); - if (unlikely (!out)) return; - if (unlikely (!c->check_assign (valueFormat, newFormat, HB_SERIALIZE_ERROR_INT_OVERFLOW))) return; - if (unlikely (!c->check_assign (valueCount, it.len (), HB_SERIALIZE_ERROR_ARRAY_OVERFLOW))) return; - - + it - | hb_map (hb_second) - | hb_apply ([&] (hb_array_t<const Value> _) - { src->get_value_format ().copy_values (c, newFormat, src, &_, layout_variation_idx_map); }) - ; - - auto glyphs = - + it - | hb_map_retains_sorting (hb_first) - ; - - coverage.serialize_serialize (c, glyphs); - } - - bool subset (hb_subset_context_t *c) const - { - TRACE_SUBSET (this); - const hb_set_t &glyphset = *c->plan->glyphset_gsub (); - const hb_map_t &glyph_map = *c->plan->glyph_map; - - unsigned sub_length = valueFormat.get_len (); - auto values_array = values.as_array (valueCount * sub_length); - - auto it = - + hb_zip (this+coverage, hb_range ((unsigned) valueCount)) - | hb_filter (glyphset, hb_first) - | hb_map_retains_sorting ([&] (const hb_pair_t<hb_codepoint_t, unsigned>& _) - { - return hb_pair (glyph_map[_.first], - values_array.sub_array (_.second * sub_length, - sub_length)); - }) - ; - - bool ret = bool (it); - SinglePos_serialize (c->serializer, this, it, c->plan->layout_variation_idx_map); - return_trace (ret); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && - coverage.sanitize (c, this) && - valueFormat.sanitize_values (c, this, values, valueCount)); - } - - protected: - HBUINT16 format; /* Format identifier--format = 2 */ - Offset16To<Coverage> - coverage; /* Offset to Coverage table--from - * beginning of subtable */ - ValueFormat valueFormat; /* Defines the types of data in the - * ValueRecord */ - HBUINT16 valueCount; /* Number of ValueRecords */ - ValueRecord values; /* Array of ValueRecords--positioning - * values applied to glyphs */ - public: - DEFINE_SIZE_ARRAY (8, values); -}; - -struct SinglePos -{ - template<typename Iterator, - hb_requires (hb_is_iterator (Iterator))> - unsigned get_format (Iterator glyph_val_iter_pairs) - { - hb_array_t<const Value> first_val_iter = hb_second (*glyph_val_iter_pairs); - - for (const auto iter : glyph_val_iter_pairs) - for (const auto _ : hb_zip (iter.second, first_val_iter)) - if (_.first != _.second) - return 2; - - return 1; - } - - - template<typename Iterator, - typename SrcLookup, - hb_requires (hb_is_iterator (Iterator))> - void serialize (hb_serialize_context_t *c, - const SrcLookup* src, - Iterator glyph_val_iter_pairs, - const hb_map_t *layout_variation_idx_map) - { - if (unlikely (!c->extend_min (u.format))) return; - unsigned format = 2; - ValueFormat new_format = src->get_value_format (); - - if (glyph_val_iter_pairs) - { - format = get_format (glyph_val_iter_pairs); - new_format = src->get_value_format ().get_effective_format (+ glyph_val_iter_pairs | hb_map (hb_second)); - } - - u.format = format; - switch (u.format) { - case 1: u.format1.serialize (c, - src, - glyph_val_iter_pairs, - new_format, - layout_variation_idx_map); - return; - case 2: u.format2.serialize (c, - src, - glyph_val_iter_pairs, - new_format, - layout_variation_idx_map); - return; - default:return; - } - } - - template <typename context_t, typename ...Ts> - typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const - { - TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); - switch (u.format) { - case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...)); - case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...)); - default:return_trace (c->default_return_value ()); - } - } - - protected: - union { - HBUINT16 format; /* Format identifier */ - SinglePosFormat1 format1; - SinglePosFormat2 format2; - } u; -}; - -template<typename Iterator, typename SrcLookup> -static void -SinglePos_serialize (hb_serialize_context_t *c, - const SrcLookup *src, - Iterator it, - const hb_map_t *layout_variation_idx_map) -{ c->start_embed<SinglePos> ()->serialize (c, src, it, layout_variation_idx_map); } - - -struct PairValueRecord -{ - friend struct PairSet; - - int cmp (hb_codepoint_t k) const - { return secondGlyph.cmp (k); } - - struct context_t - { - const void *base; - const ValueFormat *valueFormats; - const ValueFormat *newFormats; - unsigned len1; /* valueFormats[0].get_len() */ - const hb_map_t *glyph_map; - const hb_map_t *layout_variation_idx_map; - }; - - bool subset (hb_subset_context_t *c, - context_t *closure) const - { - TRACE_SERIALIZE (this); - auto *s = c->serializer; - auto *out = s->start_embed (*this); - if (unlikely (!s->extend_min (out))) return_trace (false); - - out->secondGlyph = (*closure->glyph_map)[secondGlyph]; - - closure->valueFormats[0].copy_values (s, - closure->newFormats[0], - closure->base, &values[0], - closure->layout_variation_idx_map); - closure->valueFormats[1].copy_values (s, - closure->newFormats[1], - closure->base, - &values[closure->len1], - closure->layout_variation_idx_map); - - return_trace (true); - } - - void collect_variation_indices (hb_collect_variation_indices_context_t *c, - const ValueFormat *valueFormats, - const void *base) const - { - unsigned record1_len = valueFormats[0].get_len (); - unsigned record2_len = valueFormats[1].get_len (); - const hb_array_t<const Value> values_array = values.as_array (record1_len + record2_len); - - if (valueFormats[0].has_device ()) - valueFormats[0].collect_variation_indices (c, base, values_array.sub_array (0, record1_len)); - - if (valueFormats[1].has_device ()) - valueFormats[1].collect_variation_indices (c, base, values_array.sub_array (record1_len, record2_len)); - } - - bool intersects (const hb_set_t& glyphset) const - { - return glyphset.has(secondGlyph); - } - - const Value* get_values_1 () const - { - return &values[0]; - } - - const Value* get_values_2 (ValueFormat format1) const - { - return &values[format1.get_len ()]; - } - - protected: - HBGlyphID16 secondGlyph; /* GlyphID of second glyph in the - * pair--first glyph is listed in the - * Coverage table */ - ValueRecord values; /* Positioning data for the first glyph - * followed by for second glyph */ - public: - DEFINE_SIZE_ARRAY (2, values); -}; - -struct PairSet -{ - friend struct PairPosFormat1; - - bool intersects (const hb_set_t *glyphs, - const ValueFormat *valueFormats) const - { - unsigned int len1 = valueFormats[0].get_len (); - unsigned int len2 = valueFormats[1].get_len (); - unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2); - - const PairValueRecord *record = &firstPairValueRecord; - unsigned int count = len; - for (unsigned int i = 0; i < count; i++) - { - if (glyphs->has (record->secondGlyph)) - return true; - record = &StructAtOffset<const PairValueRecord> (record, record_size); - } - return false; - } - - void collect_glyphs (hb_collect_glyphs_context_t *c, - const ValueFormat *valueFormats) const - { - unsigned int len1 = valueFormats[0].get_len (); - unsigned int len2 = valueFormats[1].get_len (); - unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2); - - const PairValueRecord *record = &firstPairValueRecord; - c->input->add_array (&record->secondGlyph, len, record_size); - } - - void collect_variation_indices (hb_collect_variation_indices_context_t *c, - const ValueFormat *valueFormats) const - { - unsigned len1 = valueFormats[0].get_len (); - unsigned len2 = valueFormats[1].get_len (); - unsigned record_size = HBUINT16::static_size * (1 + len1 + len2); - - const PairValueRecord *record = &firstPairValueRecord; - unsigned count = len; - for (unsigned i = 0; i < count; i++) - { - if (c->glyph_set->has (record->secondGlyph)) - { record->collect_variation_indices (c, valueFormats, this); } - - record = &StructAtOffset<const PairValueRecord> (record, record_size); - } - } - - bool apply (hb_ot_apply_context_t *c, - const ValueFormat *valueFormats, - unsigned int pos) const - { - TRACE_APPLY (this); - hb_buffer_t *buffer = c->buffer; - unsigned int len1 = valueFormats[0].get_len (); - unsigned int len2 = valueFormats[1].get_len (); - unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2); - - const PairValueRecord *record = hb_bsearch (buffer->info[pos].codepoint, - &firstPairValueRecord, - len, - record_size); - if (record) - { - bool applied_first = valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos()); - bool applied_second = valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]); - if (applied_first || applied_second) - buffer->unsafe_to_break (buffer->idx, pos + 1); - if (len2) - pos++; - buffer->idx = pos; - return_trace (true); - } - buffer->unsafe_to_concat (buffer->idx, pos + 1); - return_trace (false); - } - - bool subset (hb_subset_context_t *c, - const ValueFormat valueFormats[2], - const ValueFormat newFormats[2]) const - { - TRACE_SUBSET (this); - auto snap = c->serializer->snapshot (); - - auto *out = c->serializer->start_embed (*this); - if (unlikely (!c->serializer->extend_min (out))) return_trace (false); - out->len = 0; - - const hb_set_t &glyphset = *c->plan->glyphset_gsub (); - const hb_map_t &glyph_map = *c->plan->glyph_map; - - unsigned len1 = valueFormats[0].get_len (); - unsigned len2 = valueFormats[1].get_len (); - unsigned record_size = HBUINT16::static_size + Value::static_size * (len1 + len2); - - PairValueRecord::context_t context = - { - this, - valueFormats, - newFormats, - len1, - &glyph_map, - c->plan->layout_variation_idx_map - }; - - const PairValueRecord *record = &firstPairValueRecord; - unsigned count = len, num = 0; - for (unsigned i = 0; i < count; i++) - { - if (glyphset.has (record->secondGlyph) - && record->subset (c, &context)) num++; - record = &StructAtOffset<const PairValueRecord> (record, record_size); - } - - out->len = num; - if (!num) c->serializer->revert (snap); - return_trace (num); - } - - struct sanitize_closure_t - { - const ValueFormat *valueFormats; - unsigned int len1; /* valueFormats[0].get_len() */ - unsigned int stride; /* 1 + len1 + len2 */ - }; - - bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const - { - TRACE_SANITIZE (this); - if (!(c->check_struct (this) - && c->check_range (&firstPairValueRecord, - len, - HBUINT16::static_size, - closure->stride))) return_trace (false); - - unsigned int count = len; - const PairValueRecord *record = &firstPairValueRecord; - return_trace (closure->valueFormats[0].sanitize_values_stride_unsafe (c, this, &record->values[0], count, closure->stride) && - closure->valueFormats[1].sanitize_values_stride_unsafe (c, this, &record->values[closure->len1], count, closure->stride)); - } - - protected: - HBUINT16 len; /* Number of PairValueRecords */ - PairValueRecord firstPairValueRecord; - /* Array of PairValueRecords--ordered - * by GlyphID of the second glyph */ - public: - DEFINE_SIZE_MIN (2); -}; - -struct PairPosFormat1 -{ - bool intersects (const hb_set_t *glyphs) const - { - return - + hb_zip (this+coverage, pairSet) - | hb_filter (*glyphs, hb_first) - | hb_map (hb_second) - | hb_map ([glyphs, this] (const Offset16To<PairSet> &_) - { return (this+_).intersects (glyphs, valueFormat); }) - | hb_any - ; - } - - void closure_lookups (hb_closure_lookups_context_t *c) const {} - void collect_variation_indices (hb_collect_variation_indices_context_t *c) const - { - if ((!valueFormat[0].has_device ()) && (!valueFormat[1].has_device ())) return; - - auto it = - + hb_zip (this+coverage, pairSet) - | hb_filter (c->glyph_set, hb_first) - | hb_map (hb_second) - ; - - if (!it) return; - + it - | hb_map (hb_add (this)) - | hb_apply ([&] (const PairSet& _) { _.collect_variation_indices (c, valueFormat); }) - ; - } - - void collect_glyphs (hb_collect_glyphs_context_t *c) const - { - if (unlikely (!(this+coverage).collect_coverage (c->input))) return; - unsigned int count = pairSet.len; - for (unsigned int i = 0; i < count; i++) - (this+pairSet[i]).collect_glyphs (c, valueFormat); - } - - const Coverage &get_coverage () const { return this+coverage; } - - bool apply (hb_ot_apply_context_t *c) const - { - TRACE_APPLY (this); - hb_buffer_t *buffer = c->buffer; - unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint); - if (likely (index == NOT_COVERED)) return_trace (false); - - hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; - skippy_iter.reset (buffer->idx, 1); - unsigned unsafe_to; - if (!skippy_iter.next (&unsafe_to)) - { - buffer->unsafe_to_concat (buffer->idx, unsafe_to); - return_trace (false); - } - - return_trace ((this+pairSet[index]).apply (c, valueFormat, skippy_iter.idx)); - } - - bool subset (hb_subset_context_t *c) const - { - TRACE_SUBSET (this); - - const hb_set_t &glyphset = *c->plan->glyphset_gsub (); - const hb_map_t &glyph_map = *c->plan->glyph_map; - - auto *out = c->serializer->start_embed (*this); - if (unlikely (!c->serializer->extend_min (out))) return_trace (false); - out->format = format; - out->valueFormat[0] = valueFormat[0]; - out->valueFormat[1] = valueFormat[1]; - if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING) - { - hb_pair_t<unsigned, unsigned> newFormats = compute_effective_value_formats (glyphset); - out->valueFormat[0] = newFormats.first; - out->valueFormat[1] = newFormats.second; - } - - hb_sorted_vector_t<hb_codepoint_t> new_coverage; - - + hb_zip (this+coverage, pairSet) - | hb_filter (glyphset, hb_first) - | hb_filter ([this, c, out] (const Offset16To<PairSet>& _) - { - auto snap = c->serializer->snapshot (); - auto *o = out->pairSet.serialize_append (c->serializer); - if (unlikely (!o)) return false; - bool ret = o->serialize_subset (c, _, this, valueFormat, out->valueFormat); - if (!ret) - { - out->pairSet.pop (); - c->serializer->revert (snap); - } - return ret; - }, - hb_second) - | hb_map (hb_first) - | hb_map (glyph_map) - | hb_sink (new_coverage) - ; - - out->coverage.serialize_serialize (c->serializer, new_coverage.iter ()); - - return_trace (bool (new_coverage)); - } - - - hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_set_t& glyphset) const - { - unsigned len1 = valueFormat[0].get_len (); - unsigned len2 = valueFormat[1].get_len (); - unsigned record_size = HBUINT16::static_size + Value::static_size * (len1 + len2); - - unsigned format1 = 0; - unsigned format2 = 0; - for (const Offset16To<PairSet>& _ : - + hb_zip (this+coverage, pairSet) | hb_filter (glyphset, hb_first) | hb_map (hb_second)) - { - const PairSet& set = (this + _); - const PairValueRecord *record = &set.firstPairValueRecord; - - for (unsigned i = 0; i < set.len; i++) - { - if (record->intersects (glyphset)) - { - format1 = format1 | valueFormat[0].get_effective_format (record->get_values_1 ()); - format2 = format2 | valueFormat[1].get_effective_format (record->get_values_2 (valueFormat[0])); - } - record = &StructAtOffset<const PairValueRecord> (record, record_size); - } - } - - return hb_pair (format1, format2); - } - - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - - if (!c->check_struct (this)) return_trace (false); - - unsigned int len1 = valueFormat[0].get_len (); - unsigned int len2 = valueFormat[1].get_len (); - PairSet::sanitize_closure_t closure = - { - valueFormat, - len1, - 1 + len1 + len2 - }; - - return_trace (coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure)); - } - - protected: - HBUINT16 format; /* Format identifier--format = 1 */ - Offset16To<Coverage> - coverage; /* Offset to Coverage table--from - * beginning of subtable */ - ValueFormat valueFormat[2]; /* [0] Defines the types of data in - * ValueRecord1--for the first glyph - * in the pair--may be zero (0) */ - /* [1] Defines the types of data in - * ValueRecord2--for the second glyph - * in the pair--may be zero (0) */ - Array16OfOffset16To<PairSet> - pairSet; /* Array of PairSet tables - * ordered by Coverage Index */ - public: - DEFINE_SIZE_ARRAY (10, pairSet); -}; - -struct PairPosFormat2 -{ - bool intersects (const hb_set_t *glyphs) const - { - return (this+coverage).intersects (glyphs) && - (this+classDef2).intersects (glyphs); - } - - void closure_lookups (hb_closure_lookups_context_t *c) const {} - void collect_variation_indices (hb_collect_variation_indices_context_t *c) const - { - if (!intersects (c->glyph_set)) return; - if ((!valueFormat1.has_device ()) && (!valueFormat2.has_device ())) return; - - hb_set_t klass1_glyphs, klass2_glyphs; - if (!(this+classDef1).collect_coverage (&klass1_glyphs)) return; - if (!(this+classDef2).collect_coverage (&klass2_glyphs)) return; - - hb_set_t class1_set, class2_set; - for (const unsigned cp : + c->glyph_set->iter () | hb_filter (this + coverage)) - { - if (!klass1_glyphs.has (cp)) class1_set.add (0); - else - { - unsigned klass1 = (this+classDef1).get (cp); - class1_set.add (klass1); - } - } - - class2_set.add (0); - for (const unsigned cp : + c->glyph_set->iter () | hb_filter (klass2_glyphs)) - { - unsigned klass2 = (this+classDef2).get (cp); - class2_set.add (klass2); - } - - if (class1_set.is_empty () - || class2_set.is_empty () - || (class2_set.get_population() == 1 && class2_set.has(0))) - return; - - unsigned len1 = valueFormat1.get_len (); - unsigned len2 = valueFormat2.get_len (); - const hb_array_t<const Value> values_array = values.as_array ((unsigned)class1Count * (unsigned) class2Count * (len1 + len2)); - for (const unsigned class1_idx : class1_set.iter ()) - { - for (const unsigned class2_idx : class2_set.iter ()) - { - unsigned start_offset = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2); - if (valueFormat1.has_device ()) - valueFormat1.collect_variation_indices (c, this, values_array.sub_array (start_offset, len1)); - - if (valueFormat2.has_device ()) - valueFormat2.collect_variation_indices (c, this, values_array.sub_array (start_offset+len1, len2)); - } - } - } - - void collect_glyphs (hb_collect_glyphs_context_t *c) const - { - if (unlikely (!(this+coverage).collect_coverage (c->input))) return; - if (unlikely (!(this+classDef2).collect_coverage (c->input))) return; - } - - const Coverage &get_coverage () const { return this+coverage; } - - bool apply (hb_ot_apply_context_t *c) const - { - TRACE_APPLY (this); - hb_buffer_t *buffer = c->buffer; - unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint); - if (likely (index == NOT_COVERED)) return_trace (false); - - hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; - skippy_iter.reset (buffer->idx, 1); - unsigned unsafe_to; - if (!skippy_iter.next (&unsafe_to)) - { - buffer->unsafe_to_concat (buffer->idx, unsafe_to); - return_trace (false); - } - - unsigned int len1 = valueFormat1.get_len (); - unsigned int len2 = valueFormat2.get_len (); - unsigned int record_len = len1 + len2; - - unsigned int klass1 = (this+classDef1).get_class (buffer->cur().codepoint); - unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint); - if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) - { - buffer->unsafe_to_concat (buffer->idx, skippy_iter.idx + 1); - return_trace (false); - } - - const Value *v = &values[record_len * (klass1 * class2Count + klass2)]; - - bool applied_first = false, applied_second = false; - - - /* Isolate simple kerning and apply it half to each side. - * Results in better cursor positinoing / underline drawing. - * - * Disabled, because causes issues... :-( - * https://github.com/harfbuzz/harfbuzz/issues/3408 - * https://github.com/harfbuzz/harfbuzz/pull/3235#issuecomment-1029814978 - */ -#ifndef HB_SPLIT_KERN - if (0) -#endif - { - if (!len2) - { - const hb_direction_t dir = buffer->props.direction; - const bool horizontal = HB_DIRECTION_IS_HORIZONTAL (dir); - const bool backward = HB_DIRECTION_IS_BACKWARD (dir); - unsigned mask = horizontal ? ValueFormat::xAdvance : ValueFormat::yAdvance; - if (backward) - mask |= mask >> 2; /* Add eg. xPlacement in RTL. */ - /* Add Devices. */ - mask |= mask << 4; - - if (valueFormat1 & ~mask) - goto bail; - - /* Is simple kern. Apply value on an empty position slot, - * then split it between sides. */ - - hb_glyph_position_t pos{}; - if (valueFormat1.apply_value (c, this, v, pos)) - { - hb_position_t *src = &pos.x_advance; - hb_position_t *dst1 = &buffer->cur_pos().x_advance; - hb_position_t *dst2 = &buffer->pos[skippy_iter.idx].x_advance; - unsigned i = horizontal ? 0 : 1; - - hb_position_t kern = src[i]; - hb_position_t kern1 = kern >> 1; - hb_position_t kern2 = kern - kern1; - - if (!backward) - { - dst1[i] += kern1; - dst2[i] += kern2; - dst2[i + 2] += kern2; - } - else - { - dst1[i] += kern1; - dst1[i + 2] += src[i + 2] - kern2; - dst2[i] += kern2; - } - - applied_first = applied_second = kern != 0; - goto success; - } - goto boring; - } - } - bail: - - - applied_first = valueFormat1.apply_value (c, this, v, buffer->cur_pos()); - applied_second = valueFormat2.apply_value (c, this, v + len1, buffer->pos[skippy_iter.idx]); - - success: - if (applied_first || applied_second) - buffer->unsafe_to_break (buffer->idx, skippy_iter.idx + 1); - else - boring: - buffer->unsafe_to_concat (buffer->idx, skippy_iter.idx + 1); - - - buffer->idx = skippy_iter.idx; - if (len2) - buffer->idx++; - - return_trace (true); - } - - bool subset (hb_subset_context_t *c) const - { - TRACE_SUBSET (this); - auto *out = c->serializer->start_embed (*this); - if (unlikely (!c->serializer->extend_min (out))) return_trace (false); - out->format = format; - - hb_map_t klass1_map; - out->classDef1.serialize_subset (c, classDef1, this, &klass1_map, true, true, &(this + coverage)); - out->class1Count = klass1_map.get_population (); - - hb_map_t klass2_map; - out->classDef2.serialize_subset (c, classDef2, this, &klass2_map, true, false); - out->class2Count = klass2_map.get_population (); - - unsigned len1 = valueFormat1.get_len (); - unsigned len2 = valueFormat2.get_len (); - - hb_pair_t<unsigned, unsigned> newFormats = hb_pair (valueFormat1, valueFormat2); - if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING) - newFormats = compute_effective_value_formats (klass1_map, klass2_map); - - out->valueFormat1 = newFormats.first; - out->valueFormat2 = newFormats.second; - - for (unsigned class1_idx : + hb_range ((unsigned) class1Count) | hb_filter (klass1_map)) - { - for (unsigned class2_idx : + hb_range ((unsigned) class2Count) | hb_filter (klass2_map)) - { - unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2); - valueFormat1.copy_values (c->serializer, newFormats.first, this, &values[idx], c->plan->layout_variation_idx_map); - valueFormat2.copy_values (c->serializer, newFormats.second, this, &values[idx + len1], c->plan->layout_variation_idx_map); - } - } - - const hb_set_t &glyphset = *c->plan->glyphset_gsub (); - const hb_map_t &glyph_map = *c->plan->glyph_map; - - auto it = - + hb_iter (this+coverage) - | hb_filter (glyphset) - | hb_map_retains_sorting (glyph_map) - ; - - out->coverage.serialize_serialize (c->serializer, it); - return_trace (out->class1Count && out->class2Count && bool (it)); - } - - - hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_map_t& klass1_map, - const hb_map_t& klass2_map) const - { - unsigned len1 = valueFormat1.get_len (); - unsigned len2 = valueFormat2.get_len (); - - unsigned format1 = 0; - unsigned format2 = 0; - - for (unsigned class1_idx : + hb_range ((unsigned) class1Count) | hb_filter (klass1_map)) - { - for (unsigned class2_idx : + hb_range ((unsigned) class2Count) | hb_filter (klass2_map)) - { - unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2); - format1 = format1 | valueFormat1.get_effective_format (&values[idx]); - format2 = format2 | valueFormat2.get_effective_format (&values[idx + len1]); - } - } - - return hb_pair (format1, format2); - } - - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - if (!(c->check_struct (this) - && coverage.sanitize (c, this) - && classDef1.sanitize (c, this) - && classDef2.sanitize (c, this))) return_trace (false); - - unsigned int len1 = valueFormat1.get_len (); - unsigned int len2 = valueFormat2.get_len (); - unsigned int stride = len1 + len2; - unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size (); - unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count; - return_trace (c->check_range ((const void *) values, - count, - record_size) && - valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) && - valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride)); - } - - protected: - HBUINT16 format; /* Format identifier--format = 2 */ - Offset16To<Coverage> - coverage; /* Offset to Coverage table--from - * beginning of subtable */ - ValueFormat valueFormat1; /* ValueRecord definition--for the - * first glyph of the pair--may be zero - * (0) */ - ValueFormat valueFormat2; /* ValueRecord definition--for the - * second glyph of the pair--may be - * zero (0) */ - Offset16To<ClassDef> - classDef1; /* Offset to ClassDef table--from - * beginning of PairPos subtable--for - * the first glyph of the pair */ - Offset16To<ClassDef> - classDef2; /* Offset to ClassDef table--from - * beginning of PairPos subtable--for - * the second glyph of the pair */ - HBUINT16 class1Count; /* Number of classes in ClassDef1 - * table--includes Class0 */ - HBUINT16 class2Count; /* Number of classes in ClassDef2 - * table--includes Class0 */ - ValueRecord values; /* Matrix of value pairs: - * class1-major, class2-minor, - * Each entry has value1 and value2 */ - public: - DEFINE_SIZE_ARRAY (16, values); -}; - -struct PairPos -{ - template <typename context_t, typename ...Ts> - typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const - { - TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); - switch (u.format) { - case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...)); - case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...)); - default:return_trace (c->default_return_value ()); - } - } - - protected: - union { - HBUINT16 format; /* Format identifier */ - PairPosFormat1 format1; - PairPosFormat2 format2; - } u; -}; - - -struct EntryExitRecord -{ - friend struct CursivePosFormat1; - - bool sanitize (hb_sanitize_context_t *c, const void *base) const - { - TRACE_SANITIZE (this); - return_trace (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base)); - } - - void collect_variation_indices (hb_collect_variation_indices_context_t *c, - const void *src_base) const - { - (src_base+entryAnchor).collect_variation_indices (c); - (src_base+exitAnchor).collect_variation_indices (c); - } - - EntryExitRecord* subset (hb_subset_context_t *c, - const void *src_base) const - { - TRACE_SERIALIZE (this); - auto *out = c->serializer->embed (this); - if (unlikely (!out)) return_trace (nullptr); - - out->entryAnchor.serialize_subset (c, entryAnchor, src_base); - out->exitAnchor.serialize_subset (c, exitAnchor, src_base); - return_trace (out); - } - - protected: - Offset16To<Anchor> - entryAnchor; /* Offset to EntryAnchor table--from - * beginning of CursivePos - * subtable--may be NULL */ - Offset16To<Anchor> - exitAnchor; /* Offset to ExitAnchor table--from - * beginning of CursivePos - * subtable--may be NULL */ - public: - DEFINE_SIZE_STATIC (4); -}; - -static void -reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent); - -struct CursivePosFormat1 -{ - bool intersects (const hb_set_t *glyphs) const - { return (this+coverage).intersects (glyphs); } - - void closure_lookups (hb_closure_lookups_context_t *c) const {} - - void collect_variation_indices (hb_collect_variation_indices_context_t *c) const - { - + hb_zip (this+coverage, entryExitRecord) - | hb_filter (c->glyph_set, hb_first) - | hb_map (hb_second) - | hb_apply ([&] (const EntryExitRecord& record) { record.collect_variation_indices (c, this); }) - ; - } - - void collect_glyphs (hb_collect_glyphs_context_t *c) const - { if (unlikely (!(this+coverage).collect_coverage (c->input))) return; } - - const Coverage &get_coverage () const { return this+coverage; } - - bool apply (hb_ot_apply_context_t *c) const - { - TRACE_APPLY (this); - hb_buffer_t *buffer = c->buffer; - - const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage (buffer->cur().codepoint)]; - if (!this_record.entryAnchor) return_trace (false); - - hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; - skippy_iter.reset (buffer->idx, 1); - unsigned unsafe_from; - if (!skippy_iter.prev (&unsafe_from)) - { - buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1); - return_trace (false); - } - - const EntryExitRecord &prev_record = entryExitRecord[(this+coverage).get_coverage (buffer->info[skippy_iter.idx].codepoint)]; - if (!prev_record.exitAnchor) - { - buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); - return_trace (false); - } - - unsigned int i = skippy_iter.idx; - unsigned int j = buffer->idx; - - buffer->unsafe_to_break (i, j); - float entry_x, entry_y, exit_x, exit_y; - (this+prev_record.exitAnchor).get_anchor (c, buffer->info[i].codepoint, &exit_x, &exit_y); - (this+this_record.entryAnchor).get_anchor (c, buffer->info[j].codepoint, &entry_x, &entry_y); - - hb_glyph_position_t *pos = buffer->pos; - - hb_position_t d; - /* Main-direction adjustment */ - switch (c->direction) { - case HB_DIRECTION_LTR: - pos[i].x_advance = roundf (exit_x) + pos[i].x_offset; - - d = roundf (entry_x) + pos[j].x_offset; - pos[j].x_advance -= d; - pos[j].x_offset -= d; - break; - case HB_DIRECTION_RTL: - d = roundf (exit_x) + pos[i].x_offset; - pos[i].x_advance -= d; - pos[i].x_offset -= d; - - pos[j].x_advance = roundf (entry_x) + pos[j].x_offset; - break; - case HB_DIRECTION_TTB: - pos[i].y_advance = roundf (exit_y) + pos[i].y_offset; - - d = roundf (entry_y) + pos[j].y_offset; - pos[j].y_advance -= d; - pos[j].y_offset -= d; - break; - case HB_DIRECTION_BTT: - d = roundf (exit_y) + pos[i].y_offset; - pos[i].y_advance -= d; - pos[i].y_offset -= d; - - pos[j].y_advance = roundf (entry_y); - break; - case HB_DIRECTION_INVALID: - default: - break; - } - - /* Cross-direction adjustment */ - - /* We attach child to parent (think graph theory and rooted trees whereas - * the root stays on baseline and each node aligns itself against its - * parent. - * - * Optimize things for the case of RightToLeft, as that's most common in - * Arabic. */ - unsigned int child = i; - unsigned int parent = j; - hb_position_t x_offset = entry_x - exit_x; - hb_position_t y_offset = entry_y - exit_y; - if (!(c->lookup_props & LookupFlag::RightToLeft)) - { - unsigned int k = child; - child = parent; - parent = k; - x_offset = -x_offset; - y_offset = -y_offset; - } - - /* If child was already connected to someone else, walk through its old - * chain and reverse the link direction, such that the whole tree of its - * previous connection now attaches to new parent. Watch out for case - * where new parent is on the path from old chain... - */ - reverse_cursive_minor_offset (pos, child, c->direction, parent); - - pos[child].attach_type() = ATTACH_TYPE_CURSIVE; - pos[child].attach_chain() = (int) parent - (int) child; - buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT; - if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction))) - pos[child].y_offset = y_offset; - else - pos[child].x_offset = x_offset; - - /* If parent was attached to child, separate them. - * https://github.com/harfbuzz/harfbuzz/issues/2469 - */ - if (unlikely (pos[parent].attach_chain() == -pos[child].attach_chain())) - pos[parent].attach_chain() = 0; - - buffer->idx++; - return_trace (true); - } - - template <typename Iterator, - hb_requires (hb_is_iterator (Iterator))> - void serialize (hb_subset_context_t *c, - Iterator it, - const void *src_base) - { - if (unlikely (!c->serializer->extend_min ((*this)))) return; - this->format = 1; - this->entryExitRecord.len = it.len (); - - for (const EntryExitRecord& entry_record : + it - | hb_map (hb_second)) - entry_record.subset (c, src_base); - - auto glyphs = - + it - | hb_map_retains_sorting (hb_first) - ; - - coverage.serialize_serialize (c->serializer, glyphs); - } - - bool subset (hb_subset_context_t *c) const - { - TRACE_SUBSET (this); - const hb_set_t &glyphset = *c->plan->glyphset_gsub (); - const hb_map_t &glyph_map = *c->plan->glyph_map; - - auto *out = c->serializer->start_embed (*this); - if (unlikely (!out)) return_trace (false); - - auto it = - + hb_zip (this+coverage, entryExitRecord) - | hb_filter (glyphset, hb_first) - | hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, const EntryExitRecord&> p) -> hb_pair_t<hb_codepoint_t, const EntryExitRecord&> - { return hb_pair (glyph_map[p.first], p.second);}) - ; - - bool ret = bool (it); - out->serialize (c, it, this); - return_trace (ret); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this)); - } - - protected: - HBUINT16 format; /* Format identifier--format = 1 */ - Offset16To<Coverage> - coverage; /* Offset to Coverage table--from - * beginning of subtable */ - Array16Of<EntryExitRecord> - entryExitRecord; /* Array of EntryExit records--in - * Coverage Index order */ - public: - DEFINE_SIZE_ARRAY (6, entryExitRecord); -}; - -struct CursivePos -{ - template <typename context_t, typename ...Ts> - typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const - { - TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); - switch (u.format) { - case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...)); - default:return_trace (c->default_return_value ()); - } - } - - protected: - union { - HBUINT16 format; /* Format identifier */ - CursivePosFormat1 format1; - } u; -}; - - -typedef AnchorMatrix BaseArray; /* base-major-- - * in order of BaseCoverage Index--, - * mark-minor-- - * ordered by class--zero-based. */ - -static void Markclass_closure_and_remap_indexes (const Coverage &mark_coverage, - const MarkArray &mark_array, - const hb_set_t &glyphset, - hb_map_t* klass_mapping /* INOUT */) -{ - hb_set_t orig_classes; - - + hb_zip (mark_coverage, mark_array) - | hb_filter (glyphset, hb_first) - | hb_map (hb_second) - | hb_map (&MarkRecord::get_class) - | hb_sink (orig_classes) - ; - - unsigned idx = 0; - for (auto klass : orig_classes.iter ()) - { - if (klass_mapping->has (klass)) continue; - klass_mapping->set (klass, idx); - idx++; - } -} - -struct MarkBasePosFormat1 -{ - bool intersects (const hb_set_t *glyphs) const - { - return (this+markCoverage).intersects (glyphs) && - (this+baseCoverage).intersects (glyphs); - } - - void closure_lookups (hb_closure_lookups_context_t *c) const {} - - void collect_variation_indices (hb_collect_variation_indices_context_t *c) const - { - + hb_zip (this+markCoverage, this+markArray) - | hb_filter (c->glyph_set, hb_first) - | hb_map (hb_second) - | hb_apply ([&] (const MarkRecord& record) { record.collect_variation_indices (c, &(this+markArray)); }) - ; - - hb_map_t klass_mapping; - Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, *c->glyph_set, &klass_mapping); - - unsigned basecount = (this+baseArray).rows; - auto base_iter = - + hb_zip (this+baseCoverage, hb_range (basecount)) - | hb_filter (c->glyph_set, hb_first) - | hb_map (hb_second) - ; - - hb_sorted_vector_t<unsigned> base_indexes; - for (const unsigned row : base_iter) - { - + hb_range ((unsigned) classCount) - | hb_filter (klass_mapping) - | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; }) - | hb_sink (base_indexes) - ; - } - (this+baseArray).collect_variation_indices (c, base_indexes.iter ()); - } - - void collect_glyphs (hb_collect_glyphs_context_t *c) const - { - if (unlikely (!(this+markCoverage).collect_coverage (c->input))) return; - if (unlikely (!(this+baseCoverage).collect_coverage (c->input))) return; - } - - const Coverage &get_coverage () const { return this+markCoverage; } - - bool apply (hb_ot_apply_context_t *c) const - { - TRACE_APPLY (this); - hb_buffer_t *buffer = c->buffer; - unsigned int mark_index = (this+markCoverage).get_coverage (buffer->cur().codepoint); - if (likely (mark_index == NOT_COVERED)) return_trace (false); - - /* Now we search backwards for a non-mark glyph */ - hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; - skippy_iter.reset (buffer->idx, 1); - skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks); - do { - unsigned unsafe_from; - if (!skippy_iter.prev (&unsafe_from)) - { - buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1); - return_trace (false); - } - - /* We only want to attach to the first of a MultipleSubst sequence. - * https://github.com/harfbuzz/harfbuzz/issues/740 - * Reject others... - * ...but stop if we find a mark in the MultipleSubst sequence: - * https://github.com/harfbuzz/harfbuzz/issues/1020 */ - if (!_hb_glyph_info_multiplied (&buffer->info[skippy_iter.idx]) || - 0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) || - (skippy_iter.idx == 0 || - _hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx - 1]) || - _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]) != - _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx - 1]) || - _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) != - _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx - 1]) + 1 - )) - break; - skippy_iter.reject (); - } while (true); - - /* Checking that matched glyph is actually a base glyph by GDEF is too strong; disabled */ - //if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { return_trace (false); } - - unsigned int base_index = (this+baseCoverage).get_coverage (buffer->info[skippy_iter.idx].codepoint); - if (base_index == NOT_COVERED) - { - buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); - return_trace (false); - } - - return_trace ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx)); - } - - bool subset (hb_subset_context_t *c) const - { - TRACE_SUBSET (this); - const hb_set_t &glyphset = *c->plan->glyphset_gsub (); - const hb_map_t &glyph_map = *c->plan->glyph_map; - - auto *out = c->serializer->start_embed (*this); - if (unlikely (!c->serializer->extend_min (out))) return_trace (false); - out->format = format; - - hb_map_t klass_mapping; - Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, glyphset, &klass_mapping); - - if (!klass_mapping.get_population ()) return_trace (false); - out->classCount = klass_mapping.get_population (); - - auto mark_iter = - + hb_zip (this+markCoverage, this+markArray) - | hb_filter (glyphset, hb_first) - ; - - hb_sorted_vector_t<hb_codepoint_t> new_coverage; - + mark_iter - | hb_map (hb_first) - | hb_map (glyph_map) - | hb_sink (new_coverage) - ; - - if (!out->markCoverage.serialize_serialize (c->serializer, new_coverage.iter ())) - return_trace (false); - - out->markArray.serialize_subset (c, markArray, this, - (this+markCoverage).iter (), - &klass_mapping); - - unsigned basecount = (this+baseArray).rows; - auto base_iter = - + hb_zip (this+baseCoverage, hb_range (basecount)) - | hb_filter (glyphset, hb_first) - ; - - new_coverage.reset (); - + base_iter - | hb_map (hb_first) - | hb_map (glyph_map) - | hb_sink (new_coverage) - ; - - if (!out->baseCoverage.serialize_serialize (c->serializer, new_coverage.iter ())) - return_trace (false); - - hb_sorted_vector_t<unsigned> base_indexes; - for (const unsigned row : + base_iter - | hb_map (hb_second)) - { - + hb_range ((unsigned) classCount) - | hb_filter (klass_mapping) - | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; }) - | hb_sink (base_indexes) - ; - } - - out->baseArray.serialize_subset (c, baseArray, this, - base_iter.len (), - base_indexes.iter ()); - - return_trace (true); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && - markCoverage.sanitize (c, this) && - baseCoverage.sanitize (c, this) && - markArray.sanitize (c, this) && - baseArray.sanitize (c, this, (unsigned int) classCount)); - } - - protected: - HBUINT16 format; /* Format identifier--format = 1 */ - Offset16To<Coverage> - markCoverage; /* Offset to MarkCoverage table--from - * beginning of MarkBasePos subtable */ - Offset16To<Coverage> - baseCoverage; /* Offset to BaseCoverage table--from - * beginning of MarkBasePos subtable */ - HBUINT16 classCount; /* Number of classes defined for marks */ - Offset16To<MarkArray> - markArray; /* Offset to MarkArray table--from - * beginning of MarkBasePos subtable */ - Offset16To<BaseArray> - baseArray; /* Offset to BaseArray table--from - * beginning of MarkBasePos subtable */ - public: - DEFINE_SIZE_STATIC (12); -}; - -struct MarkBasePos -{ - template <typename context_t, typename ...Ts> - typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const - { - TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); - switch (u.format) { - case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...)); - default:return_trace (c->default_return_value ()); - } - } - - protected: - union { - HBUINT16 format; /* Format identifier */ - MarkBasePosFormat1 format1; - } u; -}; - - -typedef AnchorMatrix LigatureAttach; /* component-major-- - * in order of writing direction--, - * mark-minor-- - * ordered by class--zero-based. */ - -/* Array of LigatureAttach tables ordered by LigatureCoverage Index */ -struct LigatureArray : List16OfOffset16To<LigatureAttach> -{ - template <typename Iterator, - hb_requires (hb_is_iterator (Iterator))> - bool subset (hb_subset_context_t *c, - Iterator coverage, - unsigned class_count, - const hb_map_t *klass_mapping) const - { - TRACE_SUBSET (this); - const hb_set_t &glyphset = *c->plan->glyphset_gsub (); - - auto *out = c->serializer->start_embed (this); - if (unlikely (!c->serializer->extend_min (out))) return_trace (false); - - for (const auto _ : + hb_zip (coverage, *this) - | hb_filter (glyphset, hb_first)) - { - auto *matrix = out->serialize_append (c->serializer); - if (unlikely (!matrix)) return_trace (false); - - const LigatureAttach& src = (this + _.second); - auto indexes = - + hb_range (src.rows * class_count) - | hb_filter ([=] (unsigned index) { return klass_mapping->has (index % class_count); }) - ; - matrix->serialize_subset (c, - _.second, - this, - src.rows, - indexes); - } - return_trace (this->len); - } -}; - -struct MarkLigPosFormat1 -{ - bool intersects (const hb_set_t *glyphs) const - { - return (this+markCoverage).intersects (glyphs) && - (this+ligatureCoverage).intersects (glyphs); - } - - void closure_lookups (hb_closure_lookups_context_t *c) const {} - - void collect_variation_indices (hb_collect_variation_indices_context_t *c) const - { - + hb_zip (this+markCoverage, this+markArray) - | hb_filter (c->glyph_set, hb_first) - | hb_map (hb_second) - | hb_apply ([&] (const MarkRecord& record) { record.collect_variation_indices (c, &(this+markArray)); }) - ; - - hb_map_t klass_mapping; - Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, *c->glyph_set, &klass_mapping); - - unsigned ligcount = (this+ligatureArray).len; - auto lig_iter = - + hb_zip (this+ligatureCoverage, hb_range (ligcount)) - | hb_filter (c->glyph_set, hb_first) - | hb_map (hb_second) - ; - - const LigatureArray& lig_array = this+ligatureArray; - for (const unsigned i : lig_iter) - { - hb_sorted_vector_t<unsigned> lig_indexes; - unsigned row_count = lig_array[i].rows; - for (unsigned row : + hb_range (row_count)) - { - + hb_range ((unsigned) classCount) - | hb_filter (klass_mapping) - | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; }) - | hb_sink (lig_indexes) - ; - } - - lig_array[i].collect_variation_indices (c, lig_indexes.iter ()); - } - } - - void collect_glyphs (hb_collect_glyphs_context_t *c) const - { - if (unlikely (!(this+markCoverage).collect_coverage (c->input))) return; - if (unlikely (!(this+ligatureCoverage).collect_coverage (c->input))) return; - } - - const Coverage &get_coverage () const { return this+markCoverage; } - - bool apply (hb_ot_apply_context_t *c) const - { - TRACE_APPLY (this); - hb_buffer_t *buffer = c->buffer; - unsigned int mark_index = (this+markCoverage).get_coverage (buffer->cur().codepoint); - if (likely (mark_index == NOT_COVERED)) return_trace (false); - - /* Now we search backwards for a non-mark glyph */ - hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; - skippy_iter.reset (buffer->idx, 1); - skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks); - unsigned unsafe_from; - if (!skippy_iter.prev (&unsafe_from)) - { - buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1); - return_trace (false); - } - - /* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */ - //if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { return_trace (false); } - - unsigned int j = skippy_iter.idx; - unsigned int lig_index = (this+ligatureCoverage).get_coverage (buffer->info[j].codepoint); - if (lig_index == NOT_COVERED) - { - buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); - return_trace (false); - } - - const LigatureArray& lig_array = this+ligatureArray; - const LigatureAttach& lig_attach = lig_array[lig_index]; - - /* Find component to attach to */ - unsigned int comp_count = lig_attach.rows; - if (unlikely (!comp_count)) - { - buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); - return_trace (false); - } - - /* We must now check whether the ligature ID of the current mark glyph - * is identical to the ligature ID of the found ligature. If yes, we - * can directly use the component index. If not, we attach the mark - * glyph to the last component of the ligature. */ - unsigned int comp_index; - unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[j]); - unsigned int mark_id = _hb_glyph_info_get_lig_id (&buffer->cur()); - unsigned int mark_comp = _hb_glyph_info_get_lig_comp (&buffer->cur()); - if (lig_id && lig_id == mark_id && mark_comp > 0) - comp_index = hb_min (comp_count, _hb_glyph_info_get_lig_comp (&buffer->cur())) - 1; - else - comp_index = comp_count - 1; - - return_trace ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j)); - } - - bool subset (hb_subset_context_t *c) const - { - TRACE_SUBSET (this); - const hb_set_t &glyphset = *c->plan->glyphset_gsub (); - const hb_map_t &glyph_map = *c->plan->glyph_map; - - auto *out = c->serializer->start_embed (*this); - if (unlikely (!c->serializer->extend_min (out))) return_trace (false); - out->format = format; - - hb_map_t klass_mapping; - Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, glyphset, &klass_mapping); - - if (!klass_mapping.get_population ()) return_trace (false); - out->classCount = klass_mapping.get_population (); - - auto mark_iter = - + hb_zip (this+markCoverage, this+markArray) - | hb_filter (glyphset, hb_first) - ; - - auto new_mark_coverage = - + mark_iter - | hb_map_retains_sorting (hb_first) - | hb_map_retains_sorting (glyph_map) - ; - - if (!out->markCoverage.serialize_serialize (c->serializer, new_mark_coverage)) - return_trace (false); - - out->markArray.serialize_subset (c, markArray, this, - (this+markCoverage).iter (), - &klass_mapping); - - auto new_ligature_coverage = - + hb_iter (this + ligatureCoverage) - | hb_filter (glyphset) - | hb_map_retains_sorting (glyph_map) - ; - - if (!out->ligatureCoverage.serialize_serialize (c->serializer, new_ligature_coverage)) - return_trace (false); - - out->ligatureArray.serialize_subset (c, ligatureArray, this, - hb_iter (this+ligatureCoverage), classCount, &klass_mapping); - - return_trace (true); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && - markCoverage.sanitize (c, this) && - ligatureCoverage.sanitize (c, this) && - markArray.sanitize (c, this) && - ligatureArray.sanitize (c, this, (unsigned int) classCount)); - } - - protected: - HBUINT16 format; /* Format identifier--format = 1 */ - Offset16To<Coverage> - markCoverage; /* Offset to Mark Coverage table--from - * beginning of MarkLigPos subtable */ - Offset16To<Coverage> - ligatureCoverage; /* Offset to Ligature Coverage - * table--from beginning of MarkLigPos - * subtable */ - HBUINT16 classCount; /* Number of defined mark classes */ - Offset16To<MarkArray> - markArray; /* Offset to MarkArray table--from - * beginning of MarkLigPos subtable */ - Offset16To<LigatureArray> - ligatureArray; /* Offset to LigatureArray table--from - * beginning of MarkLigPos subtable */ - public: - DEFINE_SIZE_STATIC (12); -}; - - -struct MarkLigPos -{ - template <typename context_t, typename ...Ts> - typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const - { - TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); - switch (u.format) { - case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...)); - default:return_trace (c->default_return_value ()); - } - } - - protected: - union { - HBUINT16 format; /* Format identifier */ - MarkLigPosFormat1 format1; - } u; -}; - - -typedef AnchorMatrix Mark2Array; /* mark2-major-- - * in order of Mark2Coverage Index--, - * mark1-minor-- - * ordered by class--zero-based. */ - -struct MarkMarkPosFormat1 -{ - bool intersects (const hb_set_t *glyphs) const - { - return (this+mark1Coverage).intersects (glyphs) && - (this+mark2Coverage).intersects (glyphs); - } - - void closure_lookups (hb_closure_lookups_context_t *c) const {} - - void collect_variation_indices (hb_collect_variation_indices_context_t *c) const - { - + hb_zip (this+mark1Coverage, this+mark1Array) - | hb_filter (c->glyph_set, hb_first) - | hb_map (hb_second) - | hb_apply ([&] (const MarkRecord& record) { record.collect_variation_indices (c, &(this+mark1Array)); }) - ; - - hb_map_t klass_mapping; - Markclass_closure_and_remap_indexes (this+mark1Coverage, this+mark1Array, *c->glyph_set, &klass_mapping); - - unsigned mark2_count = (this+mark2Array).rows; - auto mark2_iter = - + hb_zip (this+mark2Coverage, hb_range (mark2_count)) - | hb_filter (c->glyph_set, hb_first) - | hb_map (hb_second) - ; - - hb_sorted_vector_t<unsigned> mark2_indexes; - for (const unsigned row : mark2_iter) - { - + hb_range ((unsigned) classCount) - | hb_filter (klass_mapping) - | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; }) - | hb_sink (mark2_indexes) - ; - } - (this+mark2Array).collect_variation_indices (c, mark2_indexes.iter ()); - } - - void collect_glyphs (hb_collect_glyphs_context_t *c) const - { - if (unlikely (!(this+mark1Coverage).collect_coverage (c->input))) return; - if (unlikely (!(this+mark2Coverage).collect_coverage (c->input))) return; - } - - const Coverage &get_coverage () const { return this+mark1Coverage; } - - bool apply (hb_ot_apply_context_t *c) const - { - TRACE_APPLY (this); - hb_buffer_t *buffer = c->buffer; - unsigned int mark1_index = (this+mark1Coverage).get_coverage (buffer->cur().codepoint); - if (likely (mark1_index == NOT_COVERED)) return_trace (false); - - /* now we search backwards for a suitable mark glyph until a non-mark glyph */ - hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; - skippy_iter.reset (buffer->idx, 1); - skippy_iter.set_lookup_props (c->lookup_props & ~LookupFlag::IgnoreFlags); - unsigned unsafe_from; - if (!skippy_iter.prev (&unsafe_from)) - { - buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1); - return_trace (false); - } - - if (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx])) - { - buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); - return_trace (false); - } - - unsigned int j = skippy_iter.idx; - - unsigned int id1 = _hb_glyph_info_get_lig_id (&buffer->cur()); - unsigned int id2 = _hb_glyph_info_get_lig_id (&buffer->info[j]); - unsigned int comp1 = _hb_glyph_info_get_lig_comp (&buffer->cur()); - unsigned int comp2 = _hb_glyph_info_get_lig_comp (&buffer->info[j]); - - if (likely (id1 == id2)) - { - if (id1 == 0) /* Marks belonging to the same base. */ - goto good; - else if (comp1 == comp2) /* Marks belonging to the same ligature component. */ - goto good; - } - else - { - /* If ligature ids don't match, it may be the case that one of the marks - * itself is a ligature. In which case match. */ - if ((id1 > 0 && !comp1) || (id2 > 0 && !comp2)) - goto good; - } - - /* Didn't match. */ - buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); - return_trace (false); - - good: - unsigned int mark2_index = (this+mark2Coverage).get_coverage (buffer->info[j].codepoint); - if (mark2_index == NOT_COVERED) - { - buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); - return_trace (false); - } - - return_trace ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j)); - } - - bool subset (hb_subset_context_t *c) const - { - TRACE_SUBSET (this); - const hb_set_t &glyphset = *c->plan->glyphset_gsub (); - const hb_map_t &glyph_map = *c->plan->glyph_map; - - auto *out = c->serializer->start_embed (*this); - if (unlikely (!c->serializer->extend_min (out))) return_trace (false); - out->format = format; - - hb_map_t klass_mapping; - Markclass_closure_and_remap_indexes (this+mark1Coverage, this+mark1Array, glyphset, &klass_mapping); - - if (!klass_mapping.get_population ()) return_trace (false); - out->classCount = klass_mapping.get_population (); - - auto mark1_iter = - + hb_zip (this+mark1Coverage, this+mark1Array) - | hb_filter (glyphset, hb_first) - ; - - hb_sorted_vector_t<hb_codepoint_t> new_coverage; - + mark1_iter - | hb_map (hb_first) - | hb_map (glyph_map) - | hb_sink (new_coverage) - ; - - if (!out->mark1Coverage.serialize_serialize (c->serializer, new_coverage.iter ())) - return_trace (false); - - out->mark1Array.serialize_subset (c, mark1Array, this, - (this+mark1Coverage).iter (), - &klass_mapping); - - unsigned mark2count = (this+mark2Array).rows; - auto mark2_iter = - + hb_zip (this+mark2Coverage, hb_range (mark2count)) - | hb_filter (glyphset, hb_first) - ; - - new_coverage.reset (); - + mark2_iter - | hb_map (hb_first) - | hb_map (glyph_map) - | hb_sink (new_coverage) - ; - - if (!out->mark2Coverage.serialize_serialize (c->serializer, new_coverage.iter ())) - return_trace (false); - - hb_sorted_vector_t<unsigned> mark2_indexes; - for (const unsigned row : + mark2_iter - | hb_map (hb_second)) - { - + hb_range ((unsigned) classCount) - | hb_filter (klass_mapping) - | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; }) - | hb_sink (mark2_indexes) - ; - } - - out->mark2Array.serialize_subset (c, mark2Array, this, mark2_iter.len (), mark2_indexes.iter ()); - - return_trace (true); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && - mark1Coverage.sanitize (c, this) && - mark2Coverage.sanitize (c, this) && - mark1Array.sanitize (c, this) && - mark2Array.sanitize (c, this, (unsigned int) classCount)); - } - - protected: - HBUINT16 format; /* Format identifier--format = 1 */ - Offset16To<Coverage> - mark1Coverage; /* Offset to Combining Mark1 Coverage - * table--from beginning of MarkMarkPos - * subtable */ - Offset16To<Coverage> - mark2Coverage; /* Offset to Combining Mark2 Coverage - * table--from beginning of MarkMarkPos - * subtable */ - HBUINT16 classCount; /* Number of defined mark classes */ - Offset16To<MarkArray> - mark1Array; /* Offset to Mark1Array table--from - * beginning of MarkMarkPos subtable */ - Offset16To<Mark2Array> - mark2Array; /* Offset to Mark2Array table--from - * beginning of MarkMarkPos subtable */ - public: - DEFINE_SIZE_STATIC (12); -}; - -struct MarkMarkPos -{ - template <typename context_t, typename ...Ts> - typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const - { - TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); - switch (u.format) { - case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...)); - default:return_trace (c->default_return_value ()); - } - } - - protected: - union { - HBUINT16 format; /* Format identifier */ - MarkMarkPosFormat1 format1; - } u; -}; - - -struct ContextPos : Context {}; - -struct ChainContextPos : ChainContext {}; - -struct ExtensionPos : Extension<ExtensionPos> -{ - typedef struct PosLookupSubTable SubTable; -}; - - - -/* - * PosLookup - */ - - -struct PosLookupSubTable -{ - friend struct Lookup; - friend struct PosLookup; - - enum Type { - Single = 1, - Pair = 2, - Cursive = 3, - MarkBase = 4, - MarkLig = 5, - MarkMark = 6, - Context = 7, - ChainContext = 8, - Extension = 9 - }; - - template <typename context_t, typename ...Ts> - typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type, Ts&&... ds) const - { - TRACE_DISPATCH (this, lookup_type); - switch (lookup_type) { - case Single: return_trace (u.single.dispatch (c, std::forward<Ts> (ds)...)); - case Pair: return_trace (u.pair.dispatch (c, std::forward<Ts> (ds)...)); - case Cursive: return_trace (u.cursive.dispatch (c, std::forward<Ts> (ds)...)); - case MarkBase: return_trace (u.markBase.dispatch (c, std::forward<Ts> (ds)...)); - case MarkLig: return_trace (u.markLig.dispatch (c, std::forward<Ts> (ds)...)); - case MarkMark: return_trace (u.markMark.dispatch (c, std::forward<Ts> (ds)...)); - case Context: return_trace (u.context.dispatch (c, std::forward<Ts> (ds)...)); - case ChainContext: return_trace (u.chainContext.dispatch (c, std::forward<Ts> (ds)...)); - case Extension: return_trace (u.extension.dispatch (c, std::forward<Ts> (ds)...)); - default: return_trace (c->default_return_value ()); - } - } - - bool intersects (const hb_set_t *glyphs, unsigned int lookup_type) const - { - hb_intersects_context_t c (glyphs); - return dispatch (&c, lookup_type); - } - - protected: - union { - SinglePos single; - PairPos pair; - CursivePos cursive; - MarkBasePos markBase; - MarkLigPos markLig; - MarkMarkPos markMark; - ContextPos context; - ChainContextPos chainContext; - ExtensionPos extension; - } u; - public: - DEFINE_SIZE_MIN (0); -}; - - -struct PosLookup : Lookup -{ - typedef struct PosLookupSubTable SubTable; - - const SubTable& get_subtable (unsigned int i) const - { return Lookup::get_subtable<SubTable> (i); } - - bool is_reverse () const - { - return false; - } - - bool apply (hb_ot_apply_context_t *c) const - { - TRACE_APPLY (this); - return_trace (dispatch (c)); - } - - bool intersects (const hb_set_t *glyphs) const - { - hb_intersects_context_t c (glyphs); - return dispatch (&c); - } - - hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const - { return dispatch (c); } - - hb_closure_lookups_context_t::return_t closure_lookups (hb_closure_lookups_context_t *c, unsigned this_index) const - { - if (c->is_lookup_visited (this_index)) - return hb_closure_lookups_context_t::default_return_value (); - - c->set_lookup_visited (this_index); - if (!intersects (c->glyphs)) - { - c->set_lookup_inactive (this_index); - return hb_closure_lookups_context_t::default_return_value (); - } - c->set_recurse_func (dispatch_closure_lookups_recurse_func); - - hb_closure_lookups_context_t::return_t ret = dispatch (c); - return ret; - } - - template <typename set_t> - void collect_coverage (set_t *glyphs) const - { - hb_collect_coverage_context_t<set_t> c (glyphs); - dispatch (&c); - } - - static inline bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index); - - template <typename context_t> - static typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index); - - HB_INTERNAL static hb_closure_lookups_context_t::return_t dispatch_closure_lookups_recurse_func (hb_closure_lookups_context_t *c, unsigned this_index); - - template <typename context_t, typename ...Ts> - typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const - { return Lookup::dispatch<SubTable> (c, std::forward<Ts> (ds)...); } - - bool subset (hb_subset_context_t *c) const - { return Lookup::subset<SubTable> (c); } - - bool sanitize (hb_sanitize_context_t *c) const - { return Lookup::sanitize<SubTable> (c); } -}; - -/* - * GPOS -- Glyph Positioning - * https://docs.microsoft.com/en-us/typography/opentype/spec/gpos - */ - -struct GPOS : GSUBGPOS -{ - static constexpr hb_tag_t tableTag = HB_OT_TAG_GPOS; - - const PosLookup& get_lookup (unsigned int i) const - { return static_cast<const PosLookup &> (GSUBGPOS::get_lookup (i)); } - - static inline void position_start (hb_font_t *font, hb_buffer_t *buffer); - static inline void position_finish_advances (hb_font_t *font, hb_buffer_t *buffer); - static inline void position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer); - - bool subset (hb_subset_context_t *c) const - { - hb_subset_layout_context_t l (c, tableTag, c->plan->gpos_lookups, c->plan->gpos_langsys, c->plan->gpos_features); - return GSUBGPOS::subset<PosLookup> (&l); - } - - bool sanitize (hb_sanitize_context_t *c) const - { return GSUBGPOS::sanitize<PosLookup> (c); } - - HB_INTERNAL bool is_blocklisted (hb_blob_t *blob, - hb_face_t *face) const; - - void collect_variation_indices (hb_collect_variation_indices_context_t *c) const - { - for (unsigned i = 0; i < GSUBGPOS::get_lookup_count (); i++) - { - if (!c->gpos_lookups->has (i)) continue; - const PosLookup &l = get_lookup (i); - l.dispatch (c); - } - } - - void closure_lookups (hb_face_t *face, - const hb_set_t *glyphs, - hb_set_t *lookup_indexes /* IN/OUT */) const - { GSUBGPOS::closure_lookups<PosLookup> (face, glyphs, lookup_indexes); } - - typedef GSUBGPOS::accelerator_t<GPOS> accelerator_t; -}; - - -static void -reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent) -{ - int chain = pos[i].attach_chain(), type = pos[i].attach_type(); - if (likely (!chain || 0 == (type & ATTACH_TYPE_CURSIVE))) - return; - - pos[i].attach_chain() = 0; - - unsigned int j = (int) i + chain; - - /* Stop if we see new parent in the chain. */ - if (j == new_parent) - return; - - reverse_cursive_minor_offset (pos, j, direction, new_parent); - - if (HB_DIRECTION_IS_HORIZONTAL (direction)) - pos[j].y_offset = -pos[i].y_offset; - else - pos[j].x_offset = -pos[i].x_offset; - - pos[j].attach_chain() = -chain; - pos[j].attach_type() = type; -} -static void -propagate_attachment_offsets (hb_glyph_position_t *pos, - unsigned int len, - unsigned int i, - hb_direction_t direction) -{ - /* Adjusts offsets of attached glyphs (both cursive and mark) to accumulate - * offset of glyph they are attached to. */ - int chain = pos[i].attach_chain(), type = pos[i].attach_type(); - if (likely (!chain)) - return; - - pos[i].attach_chain() = 0; - - unsigned int j = (int) i + chain; - - if (unlikely (j >= len)) - return; - - propagate_attachment_offsets (pos, len, j, direction); - - assert (!!(type & ATTACH_TYPE_MARK) ^ !!(type & ATTACH_TYPE_CURSIVE)); - - if (type & ATTACH_TYPE_CURSIVE) - { - if (HB_DIRECTION_IS_HORIZONTAL (direction)) - pos[i].y_offset += pos[j].y_offset; - else - pos[i].x_offset += pos[j].x_offset; - } - else /*if (type & ATTACH_TYPE_MARK)*/ - { - pos[i].x_offset += pos[j].x_offset; - pos[i].y_offset += pos[j].y_offset; - - assert (j < i); - if (HB_DIRECTION_IS_FORWARD (direction)) - for (unsigned int k = j; k < i; k++) { - pos[i].x_offset -= pos[k].x_advance; - pos[i].y_offset -= pos[k].y_advance; - } - else - for (unsigned int k = j + 1; k < i + 1; k++) { - pos[i].x_offset += pos[k].x_advance; - pos[i].y_offset += pos[k].y_advance; - } - } -} - -void -GPOS::position_start (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer) -{ - unsigned int count = buffer->len; - for (unsigned int i = 0; i < count; i++) - buffer->pos[i].attach_chain() = buffer->pos[i].attach_type() = 0; -} - -void -GPOS::position_finish_advances (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer HB_UNUSED) -{ - //_hb_buffer_assert_gsubgpos_vars (buffer); -} - -void -GPOS::position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer) -{ - _hb_buffer_assert_gsubgpos_vars (buffer); - - unsigned int len; - hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len); - hb_direction_t direction = buffer->props.direction; - - /* Handle attachments */ - if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT) - for (unsigned i = 0; i < len; i++) - propagate_attachment_offsets (pos, len, i, direction); - - if (unlikely (font->slant)) - { - for (unsigned i = 0; i < len; i++) - if (unlikely (pos[i].y_offset)) - pos[i].x_offset += _hb_roundf (font->slant_xy * pos[i].y_offset); - } -} - - -struct GPOS_accelerator_t : GPOS::accelerator_t { - GPOS_accelerator_t (hb_face_t *face) : GPOS::accelerator_t (face) {} -}; - +using Layout::GPOS_impl::PosLookup; +// TODO(garretrieger): Move into new layout directory. /* Out-of-class implementation for methods recursing */ - #ifndef HB_NO_OT_LAYOUT template <typename context_t> /*static*/ typename context_t::return_t PosLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index) @@ -3121,13 +45,16 @@ template <typename context_t> return l.dispatch (c); } -/*static*/ inline hb_closure_lookups_context_t::return_t PosLookup::dispatch_closure_lookups_recurse_func (hb_closure_lookups_context_t *c, unsigned this_index) +template <> +inline hb_closure_lookups_context_t::return_t +PosLookup::dispatch_recurse_func<hb_closure_lookups_context_t> (hb_closure_lookups_context_t *c, unsigned this_index) { const PosLookup &l = c->face->table.GPOS.get_relaxed ()->table->get_lookup (this_index); return l.closure_lookups (c, this_index); } -/*static*/ bool PosLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index) +template <> +inline bool PosLookup::dispatch_recurse_func<hb_ot_apply_context_t> (hb_ot_apply_context_t *c, unsigned int lookup_index) { const PosLookup &l = c->face->table.GPOS.get_relaxed ()->table->get_lookup (lookup_index); unsigned int saved_lookup_props = c->lookup_props; @@ -3141,7 +68,6 @@ template <typename context_t> } #endif - } /* namespace OT */ diff --git a/thirdparty/harfbuzz/src/hb-ot-layout-gsub-table.hh b/thirdparty/harfbuzz/src/hb-ot-layout-gsub-table.hh index bef381430b..462542025b 100644 --- a/thirdparty/harfbuzz/src/hb-ot-layout-gsub-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-layout-gsub-table.hh @@ -59,13 +59,16 @@ template <typename context_t> return l.dispatch (c); } -/*static*/ inline hb_closure_lookups_context_t::return_t SubstLookup::dispatch_closure_lookups_recurse_func (hb_closure_lookups_context_t *c, unsigned this_index) +template <> +inline hb_closure_lookups_context_t::return_t +SubstLookup::dispatch_recurse_func<hb_closure_lookups_context_t> (hb_closure_lookups_context_t *c, unsigned this_index) { const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (this_index); return l.closure_lookups (c, this_index); } -/*static*/ bool SubstLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index) +template <> +inline bool SubstLookup::dispatch_recurse_func<hb_ot_apply_context_t> (hb_ot_apply_context_t *c, unsigned int lookup_index) { const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index); unsigned int saved_lookup_props = c->lookup_props; diff --git a/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh b/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh index 3faa1e53d5..31da498652 100644 --- a/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh +++ b/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh @@ -109,14 +109,10 @@ struct hb_closure_context_t : { done_lookups_glyph_count->set (lookup_index, glyphs->get_population ()); - if (!done_lookups_glyph_set->get (lookup_index)) + if (!done_lookups_glyph_set->has (lookup_index)) { - hb_set_t* empty_set = hb_set_create (); - if (unlikely (!done_lookups_glyph_set->set (lookup_index, empty_set))) - { - hb_set_destroy (empty_set); + if (unlikely (!done_lookups_glyph_set->set (lookup_index, hb::unique_ptr<hb_set_t> {hb_set_create ()}))) return true; - } } hb_set_clear (done_lookups_glyph_set->get (lookup_index)); @@ -165,21 +161,19 @@ struct hb_closure_context_t : hb_set_t *glyphs; hb_set_t output[1]; hb_vector_t<hb_set_t> active_glyphs_stack; - recurse_func_t recurse_func; + recurse_func_t recurse_func = nullptr; unsigned int nesting_level_left; hb_closure_context_t (hb_face_t *face_, hb_set_t *glyphs_, hb_map_t *done_lookups_glyph_count_, - hb_hashmap_t<unsigned, hb_set_t *> *done_lookups_glyph_set_, + hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *done_lookups_glyph_set_, unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) : face (face_), glyphs (glyphs_), - recurse_func (nullptr), nesting_level_left (nesting_level_left_), done_lookups_glyph_count (done_lookups_glyph_count_), - done_lookups_glyph_set (done_lookups_glyph_set_), - lookup_count (0) + done_lookups_glyph_set (done_lookups_glyph_set_) {} ~hb_closure_context_t () { flush (); } @@ -197,8 +191,8 @@ struct hb_closure_context_t : private: hb_map_t *done_lookups_glyph_count; - hb_hashmap_t<unsigned, hb_set_t *> *done_lookups_glyph_set; - unsigned int lookup_count; + hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *done_lookups_glyph_set; + unsigned int lookup_count = 0; }; @@ -400,7 +394,6 @@ struct hb_collect_coverage_context_t : set_t *set; }; - struct hb_ot_apply_context_t : hb_dispatch_context_t<hb_ot_apply_context_t, bool, HB_DEBUG_APPLY> { @@ -416,7 +409,7 @@ struct hb_ot_apply_context_t : match_func (nullptr), match_data (nullptr) {} - typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data); + typedef bool (*match_func_t) (hb_glyph_info_t &info, const HBUINT16 &value, const void *data); void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; } void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; } @@ -434,7 +427,7 @@ struct hb_ot_apply_context_t : MATCH_MAYBE }; - may_match_t may_match (const hb_glyph_info_t &info, + may_match_t may_match (hb_glyph_info_t &info, const HBUINT16 *glyph_data) const { if (!(info.mask & mask) || @@ -442,7 +435,7 @@ struct hb_ot_apply_context_t : return MATCH_NO; if (match_func) - return match_func (info.codepoint, *glyph_data, match_data) ? MATCH_YES : MATCH_NO; + return match_func (info, *glyph_data, match_data) ? MATCH_YES : MATCH_NO; return MATCH_MAYBE; } @@ -530,7 +523,7 @@ struct hb_ot_apply_context_t : while (idx + num_items < end) { idx++; - const hb_glyph_info_t &info = c->buffer->info[idx]; + hb_glyph_info_t &info = c->buffer->info[idx]; matcher_t::may_skip_t skip = matcher.may_skip (c, info); if (unlikely (skip == matcher_t::SKIP_YES)) @@ -563,7 +556,7 @@ struct hb_ot_apply_context_t : while (idx > num_items - 1) { idx--; - const hb_glyph_info_t &info = c->buffer->out_info[idx]; + hb_glyph_info_t &info = c->buffer->out_info[idx]; matcher_t::may_skip_t skip = matcher.may_skip (c, info); if (unlikely (skip == matcher_t::SKIP_YES)) @@ -611,7 +604,10 @@ struct hb_ot_apply_context_t : return_t recurse (unsigned int sub_lookup_index) { if (unlikely (nesting_level_left == 0 || !recurse_func || buffer->max_ops-- <= 0)) + { + buffer->shaping_failed = true; return default_return_value (); + } nesting_level_left--; bool ret = recurse_func (this, sub_lookup_index); @@ -621,35 +617,34 @@ struct hb_ot_apply_context_t : skipping_iterator_t iter_input, iter_context; + unsigned int table_index; /* GSUB/GPOS */ hb_font_t *font; hb_face_t *face; hb_buffer_t *buffer; - recurse_func_t recurse_func; + recurse_func_t recurse_func = nullptr; const GDEF &gdef; const VariationStore &var_store; + VariationStore::cache_t *var_store_cache; hb_direction_t direction; - hb_mask_t lookup_mask; - unsigned int table_index; /* GSUB/GPOS */ - unsigned int lookup_index; - unsigned int lookup_props; - unsigned int nesting_level_left; + hb_mask_t lookup_mask = 1; + unsigned int lookup_index = (unsigned) -1; + unsigned int lookup_props = 0; + unsigned int nesting_level_left = HB_MAX_NESTING_LEVEL; bool has_glyph_classes; - bool auto_zwnj; - bool auto_zwj; - bool per_syllable; - bool random; - - uint32_t random_state; - + bool auto_zwnj = true; + bool auto_zwj = true; + bool per_syllable = false; + bool random = false; + uint32_t random_state = 1; + unsigned new_syllables = (unsigned) -1; hb_ot_apply_context_t (unsigned int table_index_, hb_font_t *font_, hb_buffer_t *buffer_) : - iter_input (), iter_context (), + table_index (table_index_), font (font_), face (font->face), buffer (buffer_), - recurse_func (nullptr), gdef ( #ifndef HB_NO_OT_LAYOUT *face->table.GDEF->table @@ -658,18 +653,23 @@ struct hb_ot_apply_context_t : #endif ), var_store (gdef.get_var_store ()), + var_store_cache ( +#ifndef HB_NO_VAR + table_index == 1 && font->num_coords ? var_store.create_cache () : nullptr +#else + nullptr +#endif + ), direction (buffer_->props.direction), - lookup_mask (1), - table_index (table_index_), - lookup_index ((unsigned int) -1), - lookup_props (0), - nesting_level_left (HB_MAX_NESTING_LEVEL), - has_glyph_classes (gdef.has_glyph_classes ()), - auto_zwnj (true), - auto_zwj (true), - per_syllable (false), - random (false), - random_state (1) { init_iters (); } + has_glyph_classes (gdef.has_glyph_classes ()) + { init_iters (); } + + ~hb_ot_apply_context_t () + { +#ifndef HB_NO_VAR + VariationStore::destroy_cache (var_store_cache); +#endif + } void init_iters () { @@ -736,6 +736,9 @@ struct hb_ot_apply_context_t : bool ligature = false, bool component = false) const { + if (new_syllables != (unsigned) -1) + buffer->cur().syllable() = new_syllables; + unsigned int props = _hb_glyph_info_get_glyph_props (&buffer->cur()); props |= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED; if (ligature) @@ -790,8 +793,8 @@ struct hb_ot_apply_context_t : }; -struct hb_get_subtables_context_t : - hb_dispatch_context_t<hb_get_subtables_context_t> +struct hb_accelerate_subtables_context_t : + hb_dispatch_context_t<hb_accelerate_subtables_context_t> { template <typename Type> static inline bool apply_to (const void *obj, OT::hb_ot_apply_context_t *c) @@ -800,15 +803,53 @@ struct hb_get_subtables_context_t : return typed_obj->apply (c); } +#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE + template <typename T> + static inline auto apply_cached_ (const T *obj, OT::hb_ot_apply_context_t *c, hb_priority<1>) HB_RETURN (bool, obj->apply (c, true) ) + template <typename T> + static inline auto apply_cached_ (const T *obj, OT::hb_ot_apply_context_t *c, hb_priority<0>) HB_RETURN (bool, obj->apply (c) ) + template <typename Type> + static inline bool apply_cached_to (const void *obj, OT::hb_ot_apply_context_t *c) + { + const Type *typed_obj = (const Type *) obj; + return apply_cached_ (typed_obj, c, hb_prioritize); + } + + template <typename T> + static inline auto cache_func_ (const T *obj, OT::hb_ot_apply_context_t *c, bool enter, hb_priority<1>) HB_RETURN (bool, obj->cache_func (c, enter) ) + template <typename T> + static inline bool cache_func_ (const T *obj, OT::hb_ot_apply_context_t *c, bool enter, hb_priority<0>) { return false; } + template <typename Type> + static inline bool cache_func_to (const void *obj, OT::hb_ot_apply_context_t *c, bool enter) + { + const Type *typed_obj = (const Type *) obj; + return cache_func_ (typed_obj, c, enter, hb_prioritize); + } +#endif + typedef bool (*hb_apply_func_t) (const void *obj, OT::hb_ot_apply_context_t *c); + typedef bool (*hb_cache_func_t) (const void *obj, OT::hb_ot_apply_context_t *c, bool enter); struct hb_applicable_t { + friend struct hb_accelerate_subtables_context_t; + friend struct hb_ot_layout_lookup_accelerator_t; + template <typename T> - void init (const T &obj_, hb_apply_func_t apply_func_) + void init (const T &obj_, + hb_apply_func_t apply_func_ +#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE + , hb_apply_func_t apply_cached_func_ + , hb_cache_func_t cache_func_ +#endif + ) { obj = &obj_; apply_func = apply_func_; +#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE + apply_cached_func = apply_cached_func_; + cache_func = cache_func_; +#endif digest.init (); obj_.get_coverage ().collect_coverage (&digest); } @@ -817,38 +858,93 @@ struct hb_get_subtables_context_t : { return digest.may_have (c->buffer->cur().codepoint) && apply_func (obj, c); } +#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE + bool apply_cached (OT::hb_ot_apply_context_t *c) const + { + return digest.may_have (c->buffer->cur().codepoint) && apply_cached_func (obj, c); + } + bool cache_enter (OT::hb_ot_apply_context_t *c) const + { + return cache_func (obj, c, true); + } + void cache_leave (OT::hb_ot_apply_context_t *c) const + { + cache_func (obj, c, false); + } +#endif private: const void *obj; hb_apply_func_t apply_func; +#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE + hb_apply_func_t apply_cached_func; + hb_cache_func_t cache_func; +#endif hb_set_digest_t digest; }; typedef hb_vector_t<hb_applicable_t> array_t; +#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE + template <typename T> + auto cache_cost (const T &obj, hb_priority<1>) HB_AUTO_RETURN ( obj.cache_cost () ) + template <typename T> + auto cache_cost (const T &obj, hb_priority<0>) HB_AUTO_RETURN ( 0u ) +#endif + /* Dispatch interface. */ template <typename T> return_t dispatch (const T &obj) { - hb_applicable_t *entry = array.push(); - entry->init (obj, apply_to<T>); + hb_applicable_t entry; + + entry.init (obj, + apply_to<T> +#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE + , apply_cached_to<T> + , cache_func_to<T> +#endif + ); + + array.push (entry); + +#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE + /* Cache handling + * + * We allow one subtable from each lookup to use a cache. The assumption + * being that multiple subtables of the same lookup cannot use a cache + * because the resources they would use will collide. As such, we ask + * each subtable to tell us how much it costs (which a cache would avoid), + * and we allocate the cache opportunity to the costliest subtable. + */ + unsigned cost = cache_cost (obj, hb_prioritize); + if (cost > cache_user_cost && !array.in_error ()) + { + cache_user_idx = array.length - 1; + cache_user_cost = cost; + } +#endif + return hb_empty_t (); } static return_t default_return_value () { return hb_empty_t (); } - hb_get_subtables_context_t (array_t &array_) : - array (array_) {} + hb_accelerate_subtables_context_t (array_t &array_) : + array (array_) {} array_t &array; -}; - +#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE + unsigned cache_user_idx = (unsigned) -1; + unsigned cache_user_cost = 0; +#endif +}; typedef bool (*intersects_func_t) (const hb_set_t *glyphs, const HBUINT16 &value, const void *data); typedef void (*intersected_glyphs_func_t) (const hb_set_t *glyphs, const void *data, unsigned value, hb_set_t *intersected_glyphs); typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const HBUINT16 &value, const void *data); -typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data); +typedef bool (*match_func_t) (hb_glyph_info_t &info, const HBUINT16 &value, const void *data); struct ContextClosureFuncs { @@ -863,6 +959,10 @@ struct ContextApplyFuncs { match_func_t match; }; +struct ChainContextApplyFuncs +{ + match_func_t match[3]; +}; static inline bool intersects_glyph (const hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED) @@ -939,19 +1039,30 @@ static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED, } -static inline bool match_glyph (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data HB_UNUSED) +static inline bool match_glyph (hb_glyph_info_t &info, const HBUINT16 &value, const void *data HB_UNUSED) { - return glyph_id == value; + return info.codepoint == value; } -static inline bool match_class (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data) +static inline bool match_class (hb_glyph_info_t &info, const HBUINT16 &value, const void *data) { const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data); - return class_def.get_class (glyph_id) == value; + return class_def.get_class (info.codepoint) == value; } -static inline bool match_coverage (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data) +static inline bool match_class_cached (hb_glyph_info_t &info, const HBUINT16 &value, const void *data) +{ + unsigned klass = info.syllable(); + if (klass < 255) + return klass == value; + const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data); + klass = class_def.get_class (info.codepoint); + if (likely (klass < 255)) + info.syllable() = klass; + return klass == value; +} +static inline bool match_coverage (hb_glyph_info_t &info, const HBUINT16 &value, const void *data) { const Offset16To<Coverage> &coverage = (const Offset16To<Coverage>&)value; - return (data+coverage).get_coverage (glyph_id) != NOT_COVERED; + return (data+coverage).get_coverage (info.codepoint) != NOT_COVERED; } static inline bool would_match_input (hb_would_apply_context_t *c, @@ -964,8 +1075,12 @@ static inline bool would_match_input (hb_would_apply_context_t *c, return false; for (unsigned int i = 1; i < count; i++) - if (likely (!match_func (c->glyphs[i], input[i - 1], match_data))) + { + hb_glyph_info_t info; + info.codepoint = c->glyphs[i]; + if (likely (!match_func (info, input[i - 1], match_data))) return false; + } return true; } @@ -1328,7 +1443,7 @@ static void context_closure_recurse_lookups (hb_closure_context_t *c, bool has_pos_glyphs = false; hb_set_t pos_glyphs; - if (hb_set_is_empty (covered_seq_indicies) || !hb_set_has (covered_seq_indicies, seqIndex)) + if (!hb_set_has (covered_seq_indicies, seqIndex)) { has_pos_glyphs = true; if (seqIndex == 0) @@ -1361,7 +1476,7 @@ static void context_closure_recurse_lookups (hb_closure_context_t *c, covered_seq_indicies->add (seqIndex); if (has_pos_glyphs) { - c->push_cur_active_glyphs () = pos_glyphs; + c->push_cur_active_glyphs () = std::move (pos_glyphs); } else { c->push_cur_active_glyphs ().set (*c->glyphs); } @@ -1415,11 +1530,6 @@ static inline void apply_lookup (hb_ot_apply_context_t *c, if (idx >= count) continue; - /* Don't recurse to ourself at same position. - * Note that this test is too naive, it doesn't catch longer loops. */ - if (unlikely (idx == 0 && lookupRecord[i].lookupListIndex == c->lookup_index)) - continue; - unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len (); /* This can happen if earlier recursed lookups deleted many entries. */ @@ -1457,11 +1567,10 @@ static inline void apply_lookup (hb_ot_apply_context_t *c, * NOT the one after it. * * - If buffer length was decreased by n, it does not necessarily - * mean that n match positions where removed, as there might - * have been marks and default-ignorables in the sequence. We - * should instead drop match positions between current-position - * and current-position + n instead. Though, am not sure which - * one is better. Both cases have valid uses. Sigh. + * mean that n match positions where removed, as there recursed-to + * lookup might had a different LookupFlag. Here's a constructed + * case of that: + * https://github.com/harfbuzz/harfbuzz/discussions/3538 * * It should be possible to construct tests for both of these cases. */ @@ -2131,19 +2240,54 @@ struct ContextFormat2 const Coverage &get_coverage () const { return this+coverage; } - bool apply (hb_ot_apply_context_t *c) const + unsigned cache_cost () const + { + unsigned c = (this+classDef).cost () * ruleSet.len; + return c >= 4 ? c : 0; + } + bool cache_func (hb_ot_apply_context_t *c, bool enter) const + { + if (enter) + { + if (!HB_BUFFER_TRY_ALLOCATE_VAR (c->buffer, syllable)) + return false; + auto &info = c->buffer->info; + unsigned count = c->buffer->len; + for (unsigned i = 0; i < count; i++) + info[i].syllable() = 255; + c->new_syllables = 255; + return true; + } + else + { + c->new_syllables = (unsigned) -1; + HB_BUFFER_DEALLOCATE_VAR (c->buffer, syllable); + return true; + } + } + + bool apply (hb_ot_apply_context_t *c, bool cached = false) const { TRACE_APPLY (this); unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); if (likely (index == NOT_COVERED)) return_trace (false); const ClassDef &class_def = this+classDef; - index = class_def.get_class (c->buffer->cur().codepoint); - const RuleSet &rule_set = this+ruleSet[index]; + struct ContextApplyLookupContext lookup_context = { - {match_class}, + {cached ? match_class_cached : match_class}, &class_def }; + + if (cached && c->buffer->cur().syllable() < 255) + index = c->buffer->cur().syllable (); + else + { + index = class_def.get_class (c->buffer->cur().codepoint); + if (cached && index < 255) + c->buffer->cur().syllable() = index; + } + const RuleSet &rule_set = this+ruleSet[index]; return_trace (rule_set.apply (c, lookup_context)); } @@ -2417,7 +2561,7 @@ struct ChainContextCollectGlyphsLookupContext struct ChainContextApplyLookupContext { - ContextApplyFuncs funcs; + ChainContextApplyFuncs funcs; const void *match_data[3]; }; @@ -2505,7 +2649,7 @@ static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c return (c->zero_context ? !backtrackCount && !lookaheadCount : true) && would_match_input (c, inputCount, input, - lookup_context.funcs.match, lookup_context.match_data[1]); + lookup_context.funcs.match[1], lookup_context.match_data[1]); } static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c, @@ -2524,11 +2668,11 @@ static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c, unsigned match_positions[HB_MAX_CONTEXT_LENGTH]; if (!(match_input (c, inputCount, input, - lookup_context.funcs.match, lookup_context.match_data[1], + lookup_context.funcs.match[1], lookup_context.match_data[1], &match_end, match_positions) && (end_index = match_end) && match_lookahead (c, lookaheadCount, lookahead, - lookup_context.funcs.match, lookup_context.match_data[2], + lookup_context.funcs.match[2], lookup_context.match_data[2], match_end, &end_index))) { c->buffer->unsafe_to_concat (c->buffer->idx, end_index); @@ -2538,7 +2682,7 @@ static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c, unsigned start_index = c->buffer->out_len; if (!match_backtrack (c, backtrackCount, backtrack, - lookup_context.funcs.match, lookup_context.match_data[0], + lookup_context.funcs.match[0], lookup_context.match_data[0], &start_index)) { c->buffer->unsafe_to_concat_from_outbuffer (start_index, end_index); @@ -2940,7 +3084,7 @@ struct ChainContextFormat1 { const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])]; struct ChainContextApplyLookupContext lookup_context = { - {match_glyph}, + {{match_glyph, match_glyph, match_glyph}}, {nullptr, nullptr, nullptr} }; return rule_set.would_apply (c, lookup_context); @@ -2956,7 +3100,7 @@ struct ChainContextFormat1 const ChainRuleSet &rule_set = this+ruleSet[index]; struct ChainContextApplyLookupContext lookup_context = { - {match_glyph}, + {{match_glyph, match_glyph, match_glyph}}, {nullptr, nullptr, nullptr} }; return_trace (rule_set.apply (c, lookup_context)); @@ -3140,7 +3284,7 @@ struct ChainContextFormat2 unsigned int index = input_class_def.get_class (c->glyphs[0]); const ChainRuleSet &rule_set = this+ruleSet[index]; struct ChainContextApplyLookupContext lookup_context = { - {match_class}, + {{match_class, match_class, match_class}}, {&backtrack_class_def, &input_class_def, &lookahead_class_def} @@ -3150,7 +3294,33 @@ struct ChainContextFormat2 const Coverage &get_coverage () const { return this+coverage; } - bool apply (hb_ot_apply_context_t *c) const + unsigned cache_cost () const + { + unsigned c = (this+lookaheadClassDef).cost () * ruleSet.len; + return c >= 4 ? c : 0; + } + bool cache_func (hb_ot_apply_context_t *c, bool enter) const + { + if (enter) + { + if (!HB_BUFFER_TRY_ALLOCATE_VAR (c->buffer, syllable)) + return false; + auto &info = c->buffer->info; + unsigned count = c->buffer->len; + for (unsigned i = 0; i < count; i++) + info[i].syllable() = 255; + c->new_syllables = 255; + return true; + } + else + { + c->new_syllables = (unsigned) -1; + HB_BUFFER_DEALLOCATE_VAR (c->buffer, syllable); + return true; + } + } + + bool apply (hb_ot_apply_context_t *c, bool cached = false) const { TRACE_APPLY (this); unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); @@ -3160,14 +3330,27 @@ struct ChainContextFormat2 const ClassDef &input_class_def = this+inputClassDef; const ClassDef &lookahead_class_def = this+lookaheadClassDef; - index = input_class_def.get_class (c->buffer->cur().codepoint); - const ChainRuleSet &rule_set = this+ruleSet[index]; + /* For ChainContextFormat2 we cache the LookaheadClassDef instead of InputClassDef. + * The reason is that most heavy fonts want to identify a glyph in context and apply + * a lookup to it. In this scenario, the length of the input sequence is one, whereas + * the lookahead / backtrack are typically longer. The one glyph in input sequence is + * looked-up below and no input glyph is looked up in individual rules, whereas the + * lookahead and backtrack glyphs are tried. Since we match lookahead before backtrack, + * we should cache lookahead. This decisions showed a 20% improvement in shaping of + * the Gulzar font. + */ + struct ChainContextApplyLookupContext lookup_context = { - {match_class}, + {{cached && &backtrack_class_def == &input_class_def ? match_class_cached : match_class, + cached && &input_class_def == &lookahead_class_def ? match_class_cached : match_class, + cached ? match_class_cached : match_class}}, {&backtrack_class_def, &input_class_def, &lookahead_class_def} }; + + index = input_class_def.get_class (c->buffer->cur().codepoint); + const ChainRuleSet &rule_set = this+ruleSet[index]; return_trace (rule_set.apply (c, lookup_context)); } @@ -3365,7 +3548,7 @@ struct ChainContextFormat3 const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input); const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead); struct ChainContextApplyLookupContext lookup_context = { - {match_coverage}, + {{match_coverage, match_coverage, match_coverage}}, {this, this, this} }; return chain_context_would_apply_lookup (c, @@ -3392,7 +3575,7 @@ struct ChainContextFormat3 const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input); const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead); struct ChainContextApplyLookupContext lookup_context = { - {match_coverage}, + {{match_coverage, match_coverage, match_coverage}}, {this, this, this} }; return_trace (chain_context_apply_lookup (c, @@ -3629,25 +3812,63 @@ struct hb_ot_layout_lookup_accelerator_t lookup.collect_coverage (&digest); subtables.init (); - OT::hb_get_subtables_context_t c_get_subtables (subtables); - lookup.dispatch (&c_get_subtables); + OT::hb_accelerate_subtables_context_t c_accelerate_subtables (subtables); + lookup.dispatch (&c_accelerate_subtables); + +#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE + cache_user_idx = c_accelerate_subtables.cache_user_idx; + for (unsigned i = 0; i < subtables.length; i++) + if (i != cache_user_idx) + subtables[i].apply_cached_func = subtables[i].apply_func; +#endif } void fini () { subtables.fini (); } bool may_have (hb_codepoint_t g) const { return digest.may_have (g); } - bool apply (hb_ot_apply_context_t *c) const + bool apply (hb_ot_apply_context_t *c, bool use_cache) const { - for (unsigned int i = 0; i < subtables.length; i++) - if (subtables[i].apply (c)) - return true; +#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE + if (use_cache) + { + for (unsigned int i = 0; i < subtables.length; i++) + if (subtables[i].apply_cached (c)) + return true; + } + else +#endif + { + for (unsigned int i = 0; i < subtables.length; i++) + if (subtables[i].apply (c)) + return true; + } return false; } + bool cache_enter (OT::hb_ot_apply_context_t *c) const + { +#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE + return cache_user_idx != (unsigned) -1 && + subtables[cache_user_idx].cache_enter (c); +#else + return false; +#endif + } + void cache_leave (OT::hb_ot_apply_context_t *c) const + { +#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE + subtables[cache_user_idx].cache_leave (c); +#endif + } + + private: hb_set_digest_t digest; - hb_get_subtables_context_t::array_t subtables; + hb_accelerate_subtables_context_t::array_t subtables; +#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE + unsigned cache_user_idx = (unsigned) -1; +#endif }; struct GSUBGPOS @@ -3727,6 +3948,8 @@ struct GSUBGPOS hb_set_t visited_lookups, inactive_lookups; OT::hb_closure_lookups_context_t c (face, glyphs, &visited_lookups, &inactive_lookups); + c.set_recurse_func (TLookup::template dispatch_recurse_func<hb_closure_lookups_context_t>); + for (unsigned lookup_index : + hb_iter (lookup_indexes)) reinterpret_cast<const TLookup &> (get_lookup (lookup_index)).closure_lookups (&c, lookup_index); @@ -3735,7 +3958,7 @@ struct GSUBGPOS } void prune_langsys (const hb_map_t *duplicate_feature_map, - hb_hashmap_t<unsigned, hb_set_t *> *script_langsys_map, + hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *script_langsys_map, hb_set_t *new_feature_indexes /* OUT */) const { hb_prune_langsys_context_t c (this, script_langsys_map, duplicate_feature_map, new_feature_indexes); @@ -3793,7 +4016,7 @@ struct GSUBGPOS hb_map_t *duplicate_feature_map /* OUT */) const { if (feature_indices->is_empty ()) return; - hb_hashmap_t<hb_tag_t, hb_set_t *> unique_features; + hb_hashmap_t<hb_tag_t, hb::unique_ptr<hb_set_t>> unique_features; //find out duplicate features after subset for (unsigned i : feature_indices->iter ()) { @@ -3801,16 +4024,9 @@ struct GSUBGPOS if (t == HB_MAP_VALUE_INVALID) continue; if (!unique_features.has (t)) { - hb_set_t* indices = hb_set_create (); - if (unlikely (indices == hb_set_get_empty () || - !unique_features.set (t, indices))) - { - hb_set_destroy (indices); - for (auto _ : unique_features.iter ()) - hb_set_destroy (_.second); + if (unlikely (!unique_features.set (t, hb::unique_ptr<hb_set_t> {hb_set_create ()}))) return; - } - if (unique_features.get (t)) + if (unique_features.has (t)) unique_features.get (t)->add (i); duplicate_feature_map->set (i, i); continue; @@ -3855,9 +4071,6 @@ struct GSUBGPOS duplicate_feature_map->set (i, i); } } - - for (auto _ : unique_features.iter ()) - hb_set_destroy (_.second); } void prune_features (const hb_map_t *lookup_indices, /* IN */ diff --git a/thirdparty/harfbuzz/src/hb-ot-layout.cc b/thirdparty/harfbuzz/src/hb-ot-layout.cc index f4ea21a4f9..142c843dad 100644 --- a/thirdparty/harfbuzz/src/hb-ot-layout.cc +++ b/thirdparty/harfbuzz/src/hb-ot-layout.cc @@ -46,7 +46,7 @@ #include "hb-ot-layout-gdef-table.hh" #include "hb-ot-layout-gsub-table.hh" #include "hb-ot-layout-gpos-table.hh" -#include "hb-ot-layout-base-table.hh" // Just so we compile it; unused otherwise. +#include "hb-ot-layout-base-table.hh" #include "hb-ot-layout-jstf-table.hh" // Just so we compile it; unused otherwise. #include "hb-ot-name-table.hh" #include "hb-ot-os2-table.hh" @@ -55,6 +55,7 @@ #include "hb-aat-layout-opbd-table.hh" // Just so we compile it; unused otherwise. using OT::Layout::GSUB::GSUB; +using OT::Layout::GPOS; /** * SECTION:hb-ot-layout @@ -260,7 +261,6 @@ _hb_ot_layout_set_glyph_props (hb_font_t *font, { _hb_glyph_info_set_glyph_props (&buffer->info[i], gdef.get_glyph_props (buffer->info[i].codepoint)); _hb_glyph_info_clear_lig_props (&buffer->info[i]); - buffer->info[i].syllable() = 0; } } @@ -401,7 +401,7 @@ GSUB::is_blocklisted (hb_blob_t *blob HB_UNUSED, } bool -OT::GPOS::is_blocklisted (hb_blob_t *blob HB_UNUSED, +GPOS::is_blocklisted (hb_blob_t *blob HB_UNUSED, hb_face_t *face HB_UNUSED) const { #ifdef HB_NO_OT_LAYOUT_BLOCKLIST @@ -1501,15 +1501,12 @@ hb_ot_layout_lookup_substitute_closure (hb_face_t *face, hb_set_t *glyphs /* OUT */) { hb_map_t done_lookups_glyph_count; - hb_hashmap_t<unsigned, hb_set_t *> done_lookups_glyph_set; + hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> done_lookups_glyph_set; OT::hb_closure_context_t c (face, glyphs, &done_lookups_glyph_count, &done_lookups_glyph_set); const OT::SubstLookup& l = face->table.GSUB->table->get_lookup (lookup_index); l.closure (&c, lookup_index); - - for (auto _ : done_lookups_glyph_set.iter ()) - hb_set_destroy (_.second); } /** @@ -1529,7 +1526,7 @@ hb_ot_layout_lookups_substitute_closure (hb_face_t *face, hb_set_t *glyphs /* OUT */) { hb_map_t done_lookups_glyph_count; - hb_hashmap_t<unsigned, hb_set_t *> done_lookups_glyph_set; + hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> done_lookups_glyph_set; OT::hb_closure_context_t c (face, glyphs, &done_lookups_glyph_count, &done_lookups_glyph_set); const GSUB& gsub = *face->table.GSUB->table; @@ -1551,13 +1548,10 @@ hb_ot_layout_lookups_substitute_closure (hb_face_t *face, } } while (iteration_count++ <= HB_CLOSURE_MAX_STAGES && glyphs_length != glyphs->get_population ()); - - for (auto _ : done_lookups_glyph_set.iter ()) - hb_set_destroy (_.second); } /* - * OT::GPOS + * GPOS */ @@ -1588,7 +1582,7 @@ hb_ot_layout_has_positioning (hb_face_t *face) void hb_ot_layout_position_start (hb_font_t *font, hb_buffer_t *buffer) { - OT::GPOS::position_start (font, buffer); + GPOS::position_start (font, buffer); } @@ -1603,7 +1597,7 @@ hb_ot_layout_position_start (hb_font_t *font, hb_buffer_t *buffer) void hb_ot_layout_position_finish_advances (hb_font_t *font, hb_buffer_t *buffer) { - OT::GPOS::position_finish_advances (font, buffer); + GPOS::position_finish_advances (font, buffer); } /** @@ -1617,7 +1611,7 @@ hb_ot_layout_position_finish_advances (hb_font_t *font, hb_buffer_t *buffer) void hb_ot_layout_position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer) { - OT::GPOS::position_finish_offsets (font, buffer); + GPOS::position_finish_offsets (font, buffer); } @@ -1652,7 +1646,7 @@ hb_ot_layout_get_size_params (hb_face_t *face, unsigned int *range_start, /* OUT. May be NULL */ unsigned int *range_end /* OUT. May be NULL */) { - const OT::GPOS &gpos = *face->table.GPOS->table; + const GPOS &gpos = *face->table.GPOS->table; const hb_tag_t tag = HB_TAG ('s','i','z','e'); unsigned int num_features = gpos.get_feature_count (); @@ -1803,7 +1797,7 @@ hb_ot_layout_feature_get_characters (hb_face_t *face, struct GSUBProxy { static constexpr unsigned table_index = 0u; - static constexpr bool inplace = false; + static constexpr bool always_inplace = false; typedef OT::SubstLookup Lookup; GSUBProxy (hb_face_t *face) : @@ -1817,14 +1811,14 @@ struct GSUBProxy struct GPOSProxy { static constexpr unsigned table_index = 1u; - static constexpr bool inplace = true; + static constexpr bool always_inplace = true; typedef OT::PosLookup Lookup; GPOSProxy (hb_face_t *face) : table (*face->table.GPOS->table), accels (face->table.GPOS->accels) {} - const OT::GPOS &table; + const GPOS &table; const OT::hb_ot_layout_lookup_accelerator_t *accels; }; @@ -1833,6 +1827,8 @@ static inline bool apply_forward (OT::hb_ot_apply_context_t *c, const OT::hb_ot_layout_lookup_accelerator_t &accel) { + bool use_cache = accel.cache_enter (c); + bool ret = false; hb_buffer_t *buffer = c->buffer; while (buffer->idx < buffer->len && buffer->successful) @@ -1842,7 +1838,7 @@ apply_forward (OT::hb_ot_apply_context_t *c, (buffer->cur().mask & c->lookup_mask) && c->check_glyph_property (&buffer->cur(), c->lookup_props)) { - applied = accel.apply (c); + applied = accel.apply (c, use_cache); } if (applied) @@ -1850,6 +1846,10 @@ apply_forward (OT::hb_ot_apply_context_t *c, else (void) buffer->next_glyph (); } + + if (use_cache) + accel.cache_leave (c); + return ret; } @@ -1864,7 +1864,7 @@ apply_backward (OT::hb_ot_apply_context_t *c, if (accel.may_have (buffer->cur().codepoint) && (buffer->cur().mask & c->lookup_mask) && c->check_glyph_property (&buffer->cur(), c->lookup_props)) - ret |= accel.apply (c); + ret |= accel.apply (c, false); /* The reverse lookup doesn't "advance" cursor (for good reason). */ buffer->idx--; @@ -1890,13 +1890,13 @@ apply_string (OT::hb_ot_apply_context_t *c, if (likely (!lookup.is_reverse ())) { /* in/out forward substitution/positioning */ - if (!Proxy::inplace) + if (!Proxy::always_inplace) buffer->clear_output (); buffer->idx = 0; apply_forward (c, accel); - if (!Proxy::inplace) + if (!Proxy::always_inplace) buffer->sync (); } else @@ -1917,7 +1917,7 @@ inline void hb_ot_map_t::apply (const Proxy &proxy, const unsigned int table_index = proxy.table_index; unsigned int i = 0; OT::hb_ot_apply_context_t c (table_index, font, buffer); - c.set_recurse_func (Proxy::Lookup::apply_recurse_func); + c.set_recurse_func (Proxy::Lookup::template dispatch_recurse_func<OT::hb_ot_apply_context_t>); for (unsigned int stage_index = 0; stage_index < stages[table_index].length; stage_index++) { diff --git a/thirdparty/harfbuzz/src/hb-ot-layout.hh b/thirdparty/harfbuzz/src/hb-ot-layout.hh index 75bba0bc50..6395f06670 100644 --- a/thirdparty/harfbuzz/src/hb-ot-layout.hh +++ b/thirdparty/harfbuzz/src/hb-ot-layout.hh @@ -589,13 +589,11 @@ _hb_buffer_allocate_gsubgpos_vars (hb_buffer_t *buffer) { HB_BUFFER_ALLOCATE_VAR (buffer, glyph_props); HB_BUFFER_ALLOCATE_VAR (buffer, lig_props); - HB_BUFFER_ALLOCATE_VAR (buffer, syllable); } static inline void _hb_buffer_deallocate_gsubgpos_vars (hb_buffer_t *buffer) { - HB_BUFFER_DEALLOCATE_VAR (buffer, syllable); HB_BUFFER_DEALLOCATE_VAR (buffer, lig_props); HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_props); } @@ -605,7 +603,6 @@ _hb_buffer_assert_gsubgpos_vars (hb_buffer_t *buffer) { HB_BUFFER_ASSERT_VAR (buffer, glyph_props); HB_BUFFER_ASSERT_VAR (buffer, lig_props); - HB_BUFFER_ASSERT_VAR (buffer, syllable); } /* Make sure no one directly touches our props... */ diff --git a/thirdparty/harfbuzz/src/hb-ot-name-language-static.hh b/thirdparty/harfbuzz/src/hb-ot-name-language-static.hh index c496dc2981..0e0f2d632a 100644 --- a/thirdparty/harfbuzz/src/hb-ot-name-language-static.hh +++ b/thirdparty/harfbuzz/src/hb-ot-name-language-static.hh @@ -45,7 +45,7 @@ struct hb_ot_language_map_t }; static const hb_ot_language_map_t -hb_ms_language_map[] = +_hb_ms_language_map[] = { {0x0001, "ar"}, /* ??? */ {0x0004, "zh"}, /* ??? */ @@ -298,7 +298,7 @@ hb_ms_language_map[] = }; static const hb_ot_language_map_t -hb_mac_language_map[] = +_hb_mac_language_map[] = { { 0, "en"}, /* English */ { 1, "fr"}, /* French */ @@ -441,16 +441,16 @@ hb_language_t _hb_ot_name_language_for_ms_code (unsigned int code) { return _hb_ot_name_language_for (code, - hb_ms_language_map, - ARRAY_LENGTH (hb_ms_language_map)); + _hb_ms_language_map, + ARRAY_LENGTH (_hb_ms_language_map)); } hb_language_t _hb_ot_name_language_for_mac_code (unsigned int code) { return _hb_ot_name_language_for (code, - hb_mac_language_map, - ARRAY_LENGTH (hb_mac_language_map)); + _hb_mac_language_map, + ARRAY_LENGTH (_hb_mac_language_map)); } #endif /* HB_OT_NAME_LANGUAGE_STATIC_HH */ diff --git a/thirdparty/harfbuzz/src/hb-ot-name-table.hh b/thirdparty/harfbuzz/src/hb-ot-name-table.hh index d52367e9b1..01107aad67 100644 --- a/thirdparty/harfbuzz/src/hb-ot-name-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-name-table.hh @@ -156,7 +156,7 @@ struct NameRecord }; static int -_hb_ot_name_entry_cmp_key (const void *pa, const void *pb) +_hb_ot_name_entry_cmp_key (const void *pa, const void *pb, bool exact) { const hb_ot_name_entry_t *a = (const hb_ot_name_entry_t *) pa; const hb_ot_name_entry_t *b = (const hb_ot_name_entry_t *) pb; @@ -169,8 +169,23 @@ _hb_ot_name_entry_cmp_key (const void *pa, const void *pb) if (a->language == b->language) return 0; if (!a->language) return -1; if (!b->language) return +1; - return strcmp (hb_language_to_string (a->language), - hb_language_to_string (b->language)); + + const char *astr = hb_language_to_string (a->language); + const char *bstr = hb_language_to_string (b->language); + + signed c = strcmp (astr, bstr); + + if (!exact && c) + { + unsigned la = strlen (astr); + unsigned lb = strlen (bstr); + // 'a' is the user request, and 'b' is string in the font. + // If eg. user asks for "en-us" and font has "en", approve. + if (la > lb && astr[lb] == '-' && !strncmp (astr, bstr, lb)) + return 0; + } + + return c; } static int @@ -178,7 +193,7 @@ _hb_ot_name_entry_cmp (const void *pa, const void *pb) { /* Compare by name_id, then language, then score, then index. */ - int v = _hb_ot_name_entry_cmp_key (pa, pb); + int v = _hb_ot_name_entry_cmp_key (pa, pb, true); if (v) return v; @@ -330,7 +345,18 @@ struct name const hb_ot_name_entry_t *entry = hb_bsearch (key, (const hb_ot_name_entry_t *) this->names, this->names.length, sizeof (hb_ot_name_entry_t), - _hb_ot_name_entry_cmp_key); + _hb_ot_name_entry_cmp_key, + true); + + if (!entry) + { + entry = hb_bsearch (key, (const hb_ot_name_entry_t *) this->names, + this->names.length, + sizeof (hb_ot_name_entry_t), + _hb_ot_name_entry_cmp_key, + false); + } + if (!entry) return -1; diff --git a/thirdparty/harfbuzz/src/hb-ot-os2-table.hh b/thirdparty/harfbuzz/src/hb-ot-os2-table.hh index f0035e2f04..3473afef54 100644 --- a/thirdparty/harfbuzz/src/hb-ot-os2-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-os2-table.hh @@ -224,9 +224,11 @@ struct OS2 *max_cp = hb_min (0xFFFFu, codepoints->get_max ()); } - /* https://github.com/Microsoft/Font-Validator/blob/520aaae/OTFontFileVal/val_OS2.cs#L644-L681 */ + /* https://github.com/Microsoft/Font-Validator/blob/520aaae/OTFontFileVal/val_OS2.cs#L644-L681 + * https://docs.microsoft.com/en-us/typography/legacy/legacy_arabic_fonts */ enum font_page_t { + FONT_PAGE_NONE = 0, FONT_PAGE_HEBREW = 0xB100, /* Hebrew Windows 3.1 font page */ FONT_PAGE_SIMP_ARABIC = 0xB200, /* Simplified Arabic Windows 3.1 font page */ FONT_PAGE_TRAD_ARABIC = 0xB300, /* Traditional Arabic Windows 3.1 font page */ diff --git a/thirdparty/harfbuzz/src/hb-ot-post-table-v2subset.hh b/thirdparty/harfbuzz/src/hb-ot-post-table-v2subset.hh index 0f3cd8e24f..4d427e5431 100644 --- a/thirdparty/harfbuzz/src/hb-ot-post-table-v2subset.hh +++ b/thirdparty/harfbuzz/src/hb-ot-post-table-v2subset.hh @@ -52,16 +52,16 @@ HB_INTERNAL bool postV2Tail::serialize (hb_serialize_context_t *c, { unsigned glyph_id = _.first; unsigned new_index = _.second; - + if (new_index < 258) continue; if (copied_indices.has (new_index)) continue; copied_indices.add (new_index); - + hb_bytes_t s = reinterpret_cast<const post::accelerator_t*> (_post)->find_glyph_name (glyph_id); HBUINT8 *o = c->allocate_size<HBUINT8> (HBUINT8::static_size * (s.length + 1)); if (unlikely (!o)) return_trace (false); if (!c->check_assign (o[0], s.length, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false); - memcpy (o+1, s.arrayZ, HBUINT8::static_size * s.length); + hb_memcpy (o+1, s.arrayZ, HBUINT8::static_size * s.length); } return_trace (true); @@ -78,17 +78,19 @@ HB_INTERNAL bool postV2Tail::subset (hb_subset_context_t *c) const post::accelerator_t _post (c->plan->source); - hb_hashmap_t<hb_bytes_t, unsigned, std::nullptr_t, unsigned, nullptr, (unsigned)-1> glyph_name_to_new_index; + hb_hashmap_t<hb_bytes_t, unsigned, true> glyph_name_to_new_index; for (hb_codepoint_t new_gid = 0; new_gid < num_glyphs; new_gid++) { hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid); unsigned old_index = glyphNameIndex[old_gid]; unsigned new_index; + const unsigned *new_index2; if (old_index <= 257) new_index = old_index; - else if (old_new_index_map.has (old_index)) new_index = old_new_index_map.get (old_index); - else + else if (old_new_index_map.has (old_index, &new_index2)) { + new_index = *new_index2; + } else { hb_bytes_t s = _post.find_glyph_name (old_gid); new_index = glyph_name_to_new_index.get (s); if (new_index == (unsigned)-1) diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic-machine.hh b/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic-machine.hh deleted file mode 100644 index 74bf3ca0fa..0000000000 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic-machine.hh +++ /dev/null @@ -1,603 +0,0 @@ - -#line 1 "hb-ot-shape-complex-indic-machine.rl" -/* - * Copyright © 2011,2012 Google, Inc. - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Google Author(s): Behdad Esfahbod - */ - -#ifndef HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH -#define HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH - -#include "hb.hh" - -enum indic_syllable_type_t { - indic_consonant_syllable, - indic_vowel_syllable, - indic_standalone_cluster, - indic_symbol_cluster, - indic_broken_cluster, - indic_non_indic_cluster, -}; - - -#line 45 "hb-ot-shape-complex-indic-machine.hh" -#define indic_syllable_machine_ex_A 10u -#define indic_syllable_machine_ex_C 1u -#define indic_syllable_machine_ex_CM 17u -#define indic_syllable_machine_ex_CS 19u -#define indic_syllable_machine_ex_DOTTEDCIRCLE 12u -#define indic_syllable_machine_ex_H 4u -#define indic_syllable_machine_ex_M 7u -#define indic_syllable_machine_ex_N 3u -#define indic_syllable_machine_ex_PLACEHOLDER 11u -#define indic_syllable_machine_ex_RS 13u -#define indic_syllable_machine_ex_Ra 16u -#define indic_syllable_machine_ex_Repha 15u -#define indic_syllable_machine_ex_SM 8u -#define indic_syllable_machine_ex_Symbol 18u -#define indic_syllable_machine_ex_V 2u -#define indic_syllable_machine_ex_ZWJ 6u -#define indic_syllable_machine_ex_ZWNJ 5u - - -#line 65 "hb-ot-shape-complex-indic-machine.hh" -static const unsigned char _indic_syllable_machine_trans_keys[] = { - 8u, 8u, 4u, 8u, 5u, 7u, 5u, 8u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, - 4u, 13u, 4u, 8u, 8u, 8u, 5u, 7u, 5u, 8u, 4u, 8u, 6u, 6u, 16u, 16u, - 4u, 8u, 4u, 13u, 4u, 13u, 4u, 13u, 8u, 8u, 5u, 7u, 5u, 8u, 4u, 8u, - 6u, 6u, 16u, 16u, 4u, 8u, 4u, 8u, 4u, 13u, 8u, 8u, 5u, 7u, 5u, 8u, - 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 4u, 8u, 5u, 8u, 8u, 8u, 1u, 19u, - 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 5u, 10u, 5u, 10u, 10u, 10u, 5u, 10u, - 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 4u, 10u, 5u, 10u, 4u, 10u, 5u, 10u, - 3u, 10u, 5u, 10u, 3u, 17u, 3u, 17u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, - 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 5u, 10u, 10u, 10u, 5u, 10u, 1u, 16u, - 1u, 16u, 3u, 10u, 4u, 10u, 5u, 10u, 4u, 10u, 5u, 10u, 5u, 10u, 3u, 10u, - 5u, 10u, 3u, 17u, 3u, 17u, 4u, 8u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, - 3u, 17u, 1u, 16u, 5u, 10u, 10u, 10u, 5u, 10u, 1u, 16u, 1u, 16u, 3u, 10u, - 4u, 10u, 5u, 10u, 3u, 17u, 4u, 10u, 5u, 10u, 5u, 10u, 3u, 10u, 5u, 10u, - 3u, 17u, 4u, 13u, 4u, 8u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u, - 1u, 16u, 5u, 10u, 10u, 10u, 5u, 10u, 1u, 16u, 1u, 16u, 3u, 10u, 4u, 10u, - 5u, 10u, 3u, 17u, 4u, 10u, 5u, 10u, 5u, 10u, 3u, 10u, 5u, 10u, 1u, 17u, - 3u, 17u, 1u, 17u, 4u, 13u, 5u, 10u, 10u, 10u, 5u, 10u, 1u, 16u, 3u, 10u, - 5u, 10u, 5u, 10u, 10u, 10u, 5u, 10u, 1u, 16u, 0 -}; - -static const char _indic_syllable_machine_key_spans[] = { - 1, 5, 3, 4, 5, 1, 1, 5, - 10, 5, 1, 3, 4, 5, 1, 1, - 5, 10, 10, 10, 1, 3, 4, 5, - 1, 1, 5, 5, 10, 1, 3, 4, - 5, 1, 1, 5, 5, 4, 1, 19, - 15, 15, 14, 16, 6, 6, 1, 6, - 16, 16, 16, 8, 7, 6, 7, 6, - 8, 6, 15, 15, 15, 15, 14, 16, - 15, 15, 14, 16, 6, 1, 6, 16, - 16, 8, 7, 6, 7, 6, 6, 8, - 6, 15, 15, 5, 15, 15, 14, 16, - 15, 16, 6, 1, 6, 16, 16, 8, - 7, 6, 15, 7, 6, 6, 8, 6, - 15, 10, 5, 15, 15, 14, 16, 15, - 16, 6, 1, 6, 16, 16, 8, 7, - 6, 15, 7, 6, 6, 8, 6, 17, - 15, 17, 10, 6, 1, 6, 16, 8, - 6, 6, 1, 6, 16 -}; - -static const short _indic_syllable_machine_index_offsets[] = { - 0, 2, 8, 12, 17, 23, 25, 27, - 33, 44, 50, 52, 56, 61, 67, 69, - 71, 77, 88, 99, 110, 112, 116, 121, - 127, 129, 131, 137, 143, 154, 156, 160, - 165, 171, 173, 175, 181, 187, 192, 194, - 214, 230, 246, 261, 278, 285, 292, 294, - 301, 318, 335, 352, 361, 369, 376, 384, - 391, 400, 407, 423, 439, 455, 471, 486, - 503, 519, 535, 550, 567, 574, 576, 583, - 600, 617, 626, 634, 641, 649, 656, 663, - 672, 679, 695, 711, 717, 733, 749, 764, - 781, 797, 814, 821, 823, 830, 847, 864, - 873, 881, 888, 904, 912, 919, 926, 935, - 942, 958, 969, 975, 991, 1007, 1022, 1039, - 1055, 1072, 1079, 1081, 1088, 1105, 1122, 1131, - 1139, 1146, 1162, 1170, 1177, 1184, 1193, 1200, - 1218, 1234, 1252, 1263, 1270, 1272, 1279, 1296, - 1305, 1312, 1319, 1321, 1328 -}; - -static const unsigned char _indic_syllable_machine_indicies[] = { - 1, 0, 2, 3, 3, 4, 1, 0, - 3, 3, 4, 0, 3, 3, 4, 1, - 0, 5, 3, 3, 4, 1, 0, 6, - 0, 7, 0, 8, 3, 3, 4, 1, - 0, 2, 3, 3, 4, 1, 0, 0, - 0, 0, 9, 0, 11, 12, 12, 13, - 14, 10, 14, 10, 12, 12, 13, 10, - 12, 12, 13, 14, 10, 15, 12, 12, - 13, 14, 10, 16, 10, 17, 10, 18, - 12, 12, 13, 14, 10, 11, 12, 12, - 13, 14, 10, 10, 10, 10, 19, 10, - 11, 12, 12, 13, 14, 10, 10, 10, - 10, 20, 10, 22, 23, 23, 24, 25, - 21, 21, 21, 21, 26, 21, 25, 21, - 23, 23, 24, 27, 23, 23, 24, 25, - 21, 28, 23, 23, 24, 25, 21, 29, - 21, 30, 21, 22, 23, 23, 24, 25, - 21, 31, 23, 23, 24, 25, 21, 33, - 34, 34, 35, 36, 32, 32, 32, 32, - 37, 32, 36, 32, 34, 34, 35, 32, - 34, 34, 35, 36, 32, 38, 34, 34, - 35, 36, 32, 39, 32, 40, 32, 33, - 34, 34, 35, 36, 32, 41, 34, 34, - 35, 36, 32, 23, 23, 24, 1, 0, - 43, 42, 45, 46, 47, 48, 49, 50, - 24, 25, 44, 51, 52, 52, 26, 44, - 53, 54, 55, 56, 57, 44, 59, 60, - 61, 62, 4, 1, 58, 63, 58, 58, - 9, 58, 58, 58, 64, 58, 65, 60, - 66, 66, 4, 1, 58, 63, 58, 58, - 58, 58, 58, 58, 64, 58, 60, 66, - 66, 4, 1, 58, 63, 58, 58, 58, - 58, 58, 58, 64, 58, 45, 58, 58, - 58, 67, 68, 58, 1, 58, 63, 58, - 58, 58, 58, 58, 45, 58, 69, 69, - 58, 1, 58, 63, 58, 63, 58, 58, - 70, 58, 63, 58, 63, 58, 63, 58, - 58, 58, 58, 63, 58, 45, 58, 71, - 58, 69, 69, 58, 1, 58, 63, 58, - 58, 58, 58, 58, 45, 58, 45, 58, - 58, 58, 69, 69, 58, 1, 58, 63, - 58, 58, 58, 58, 58, 45, 58, 45, - 58, 58, 58, 69, 68, 58, 1, 58, - 63, 58, 58, 58, 58, 58, 45, 58, - 72, 7, 73, 74, 4, 1, 58, 63, - 58, 7, 73, 74, 4, 1, 58, 63, - 58, 73, 73, 4, 1, 58, 63, 58, - 75, 76, 76, 4, 1, 58, 63, 58, - 67, 77, 58, 1, 58, 63, 58, 67, - 58, 69, 69, 58, 1, 58, 63, 58, - 69, 77, 58, 1, 58, 63, 58, 59, - 60, 66, 66, 4, 1, 58, 63, 58, - 58, 58, 58, 58, 58, 64, 58, 59, - 60, 61, 66, 4, 1, 58, 63, 58, - 58, 9, 58, 58, 58, 64, 58, 79, - 80, 81, 82, 13, 14, 78, 83, 78, - 78, 20, 78, 78, 78, 84, 78, 85, - 80, 86, 82, 13, 14, 78, 83, 78, - 78, 78, 78, 78, 78, 84, 78, 80, - 86, 82, 13, 14, 78, 83, 78, 78, - 78, 78, 78, 78, 84, 78, 87, 78, - 78, 78, 88, 89, 78, 14, 78, 83, - 78, 78, 78, 78, 78, 87, 78, 90, - 80, 91, 92, 13, 14, 78, 83, 78, - 78, 19, 78, 78, 78, 84, 78, 93, - 80, 86, 86, 13, 14, 78, 83, 78, - 78, 78, 78, 78, 78, 84, 78, 80, - 86, 86, 13, 14, 78, 83, 78, 78, - 78, 78, 78, 78, 84, 78, 87, 78, - 78, 78, 94, 89, 78, 14, 78, 83, - 78, 78, 78, 78, 78, 87, 78, 83, - 78, 78, 95, 78, 83, 78, 83, 78, - 83, 78, 78, 78, 78, 83, 78, 87, - 78, 96, 78, 94, 94, 78, 14, 78, - 83, 78, 78, 78, 78, 78, 87, 78, - 87, 78, 78, 78, 94, 94, 78, 14, - 78, 83, 78, 78, 78, 78, 78, 87, - 78, 97, 17, 98, 99, 13, 14, 78, - 83, 78, 17, 98, 99, 13, 14, 78, - 83, 78, 98, 98, 13, 14, 78, 83, - 78, 100, 101, 101, 13, 14, 78, 83, - 78, 88, 102, 78, 14, 78, 83, 78, - 94, 94, 78, 14, 78, 83, 78, 88, - 78, 94, 94, 78, 14, 78, 83, 78, - 94, 102, 78, 14, 78, 83, 78, 90, - 80, 86, 86, 13, 14, 78, 83, 78, - 78, 78, 78, 78, 78, 84, 78, 90, - 80, 91, 86, 13, 14, 78, 83, 78, - 78, 19, 78, 78, 78, 84, 78, 11, - 12, 12, 13, 14, 78, 79, 80, 86, - 82, 13, 14, 78, 83, 78, 78, 78, - 78, 78, 78, 84, 78, 104, 48, 105, - 105, 24, 25, 103, 51, 103, 103, 103, - 103, 103, 103, 55, 103, 48, 105, 105, - 24, 25, 103, 51, 103, 103, 103, 103, - 103, 103, 55, 103, 106, 103, 103, 103, - 107, 108, 103, 25, 103, 51, 103, 103, - 103, 103, 103, 106, 103, 47, 48, 109, - 110, 24, 25, 103, 51, 103, 103, 26, - 103, 103, 103, 55, 103, 106, 103, 103, - 103, 111, 108, 103, 25, 103, 51, 103, - 103, 103, 103, 103, 106, 103, 51, 103, - 103, 112, 103, 51, 103, 51, 103, 51, - 103, 103, 103, 103, 51, 103, 106, 103, - 113, 103, 111, 111, 103, 25, 103, 51, - 103, 103, 103, 103, 103, 106, 103, 106, - 103, 103, 103, 111, 111, 103, 25, 103, - 51, 103, 103, 103, 103, 103, 106, 103, - 114, 30, 115, 116, 24, 25, 103, 51, - 103, 30, 115, 116, 24, 25, 103, 51, - 103, 115, 115, 24, 25, 103, 51, 103, - 47, 48, 105, 105, 24, 25, 103, 51, - 103, 103, 103, 103, 103, 103, 55, 103, - 117, 118, 118, 24, 25, 103, 51, 103, - 107, 119, 103, 25, 103, 51, 103, 111, - 111, 103, 25, 103, 51, 103, 107, 103, - 111, 111, 103, 25, 103, 51, 103, 111, - 119, 103, 25, 103, 51, 103, 47, 48, - 109, 105, 24, 25, 103, 51, 103, 103, - 26, 103, 103, 103, 55, 103, 22, 23, - 23, 24, 25, 120, 120, 120, 120, 26, - 120, 22, 23, 23, 24, 25, 120, 122, - 123, 124, 125, 35, 36, 121, 126, 121, - 121, 37, 121, 121, 121, 127, 121, 128, - 123, 125, 125, 35, 36, 121, 126, 121, - 121, 121, 121, 121, 121, 127, 121, 123, - 125, 125, 35, 36, 121, 126, 121, 121, - 121, 121, 121, 121, 127, 121, 129, 121, - 121, 121, 130, 131, 121, 36, 121, 126, - 121, 121, 121, 121, 121, 129, 121, 122, - 123, 124, 52, 35, 36, 121, 126, 121, - 121, 37, 121, 121, 121, 127, 121, 129, - 121, 121, 121, 132, 131, 121, 36, 121, - 126, 121, 121, 121, 121, 121, 129, 121, - 126, 121, 121, 133, 121, 126, 121, 126, - 121, 126, 121, 121, 121, 121, 126, 121, - 129, 121, 134, 121, 132, 132, 121, 36, - 121, 126, 121, 121, 121, 121, 121, 129, - 121, 129, 121, 121, 121, 132, 132, 121, - 36, 121, 126, 121, 121, 121, 121, 121, - 129, 121, 135, 40, 136, 137, 35, 36, - 121, 126, 121, 40, 136, 137, 35, 36, - 121, 126, 121, 136, 136, 35, 36, 121, - 126, 121, 122, 123, 125, 125, 35, 36, - 121, 126, 121, 121, 121, 121, 121, 121, - 127, 121, 138, 139, 139, 35, 36, 121, - 126, 121, 130, 140, 121, 36, 121, 126, - 121, 132, 132, 121, 36, 121, 126, 121, - 130, 121, 132, 132, 121, 36, 121, 126, - 121, 132, 140, 121, 36, 121, 126, 121, - 45, 46, 47, 48, 109, 105, 24, 25, - 103, 51, 52, 52, 26, 103, 103, 45, - 55, 103, 59, 141, 61, 62, 4, 1, - 58, 63, 58, 58, 9, 58, 58, 58, - 64, 58, 45, 46, 47, 48, 142, 143, - 24, 144, 58, 145, 58, 52, 26, 58, - 58, 45, 55, 58, 22, 146, 146, 24, - 144, 58, 63, 58, 58, 26, 58, 145, - 58, 58, 147, 58, 145, 58, 145, 58, - 145, 58, 58, 58, 58, 145, 58, 45, - 58, 71, 22, 146, 146, 24, 144, 58, - 63, 58, 58, 58, 58, 58, 45, 58, - 149, 148, 150, 150, 148, 43, 148, 151, - 148, 150, 150, 148, 43, 148, 151, 148, - 151, 148, 148, 152, 148, 151, 148, 151, - 148, 151, 148, 148, 148, 148, 151, 148, - 45, 120, 120, 120, 120, 120, 120, 120, - 120, 120, 52, 120, 120, 120, 120, 45, - 120, 0 -}; - -static const unsigned char _indic_syllable_machine_trans_targs[] = { - 39, 45, 50, 2, 51, 5, 6, 53, - 57, 58, 39, 67, 11, 73, 68, 14, - 15, 75, 80, 81, 84, 39, 89, 21, - 95, 90, 98, 39, 24, 25, 97, 103, - 39, 112, 30, 118, 113, 121, 33, 34, - 120, 126, 39, 137, 39, 40, 60, 85, - 87, 105, 106, 91, 107, 127, 128, 99, - 135, 140, 39, 41, 43, 8, 59, 46, - 54, 42, 1, 44, 48, 0, 47, 49, - 52, 3, 4, 55, 7, 56, 39, 61, - 63, 18, 83, 69, 76, 62, 9, 64, - 78, 71, 65, 17, 82, 66, 10, 70, - 72, 74, 12, 13, 77, 16, 79, 39, - 86, 26, 88, 101, 93, 19, 104, 20, - 92, 94, 96, 22, 23, 100, 27, 102, - 39, 39, 108, 110, 28, 35, 114, 122, - 109, 111, 124, 116, 29, 115, 117, 119, - 31, 32, 123, 36, 125, 129, 130, 134, - 131, 132, 37, 133, 39, 136, 38, 138, - 139 -}; - -static const char _indic_syllable_machine_trans_actions[] = { - 1, 0, 2, 0, 2, 0, 0, 2, - 2, 2, 3, 2, 0, 2, 0, 0, - 0, 2, 2, 2, 2, 4, 2, 0, - 5, 0, 5, 6, 0, 0, 5, 2, - 7, 2, 0, 2, 0, 2, 0, 0, - 2, 2, 8, 0, 11, 2, 2, 5, - 0, 12, 12, 0, 2, 5, 2, 5, - 2, 0, 13, 2, 0, 0, 2, 0, - 2, 2, 0, 2, 2, 0, 0, 2, - 2, 0, 0, 0, 0, 2, 14, 2, - 0, 0, 2, 0, 2, 2, 0, 2, - 2, 2, 2, 0, 2, 2, 0, 0, - 2, 2, 0, 0, 0, 0, 2, 15, - 5, 0, 5, 2, 2, 0, 5, 0, - 0, 2, 5, 0, 0, 0, 0, 2, - 16, 17, 2, 0, 0, 0, 0, 2, - 2, 2, 2, 2, 0, 0, 2, 2, - 0, 0, 0, 0, 2, 0, 18, 18, - 0, 0, 0, 0, 19, 2, 0, 0, - 0 -}; - -static const char _indic_syllable_machine_to_state_actions[] = { - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 9, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0 -}; - -static const char _indic_syllable_machine_from_state_actions[] = { - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 10, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0 -}; - -static const short _indic_syllable_machine_eof_trans[] = { - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 22, 22, 28, 22, 22, - 22, 22, 22, 22, 33, 33, 33, 33, - 33, 33, 33, 33, 33, 1, 43, 0, - 59, 59, 59, 59, 59, 59, 59, 59, - 59, 59, 59, 59, 59, 59, 59, 59, - 59, 59, 59, 59, 79, 79, 79, 79, - 79, 79, 79, 79, 79, 79, 79, 79, - 79, 79, 79, 79, 79, 79, 79, 79, - 79, 79, 79, 79, 79, 104, 104, 104, - 104, 104, 104, 104, 104, 104, 104, 104, - 104, 104, 104, 104, 104, 104, 104, 104, - 104, 121, 121, 122, 122, 122, 122, 122, - 122, 122, 122, 122, 122, 122, 122, 122, - 122, 122, 122, 122, 122, 122, 122, 104, - 59, 59, 59, 59, 59, 59, 59, 149, - 149, 149, 149, 149, 121 -}; - -static const int indic_syllable_machine_start = 39; -static const int indic_syllable_machine_first_final = 39; -static const int indic_syllable_machine_error = -1; - -static const int indic_syllable_machine_en_main = 39; - - -#line 46 "hb-ot-shape-complex-indic-machine.rl" - - - -#line 102 "hb-ot-shape-complex-indic-machine.rl" - - -#define found_syllable(syllable_type) \ - HB_STMT_START { \ - if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \ - for (unsigned int i = ts; i < te; i++) \ - info[i].syllable() = (syllable_serial << 4) | syllable_type; \ - syllable_serial++; \ - if (unlikely (syllable_serial == 16)) syllable_serial = 1; \ - } HB_STMT_END - -static void -find_syllables_indic (hb_buffer_t *buffer) -{ - unsigned int p, pe, eof, ts, te, act; - int cs; - hb_glyph_info_t *info = buffer->info; - -#line 440 "hb-ot-shape-complex-indic-machine.hh" - { - cs = indic_syllable_machine_start; - ts = 0; - te = 0; - act = 0; - } - -#line 122 "hb-ot-shape-complex-indic-machine.rl" - - - p = 0; - pe = eof = buffer->len; - - unsigned int syllable_serial = 1; - -#line 456 "hb-ot-shape-complex-indic-machine.hh" - { - int _slen; - int _trans; - const unsigned char *_keys; - const unsigned char *_inds; - if ( p == pe ) - goto _test_eof; -_resume: - switch ( _indic_syllable_machine_from_state_actions[cs] ) { - case 10: -#line 1 "NONE" - {ts = p;} - break; -#line 470 "hb-ot-shape-complex-indic-machine.hh" - } - - _keys = _indic_syllable_machine_trans_keys + (cs<<1); - _inds = _indic_syllable_machine_indicies + _indic_syllable_machine_index_offsets[cs]; - - _slen = _indic_syllable_machine_key_spans[cs]; - _trans = _inds[ _slen > 0 && _keys[0] <=( info[p].indic_category()) && - ( info[p].indic_category()) <= _keys[1] ? - ( info[p].indic_category()) - _keys[0] : _slen ]; - -_eof_trans: - cs = _indic_syllable_machine_trans_targs[_trans]; - - if ( _indic_syllable_machine_trans_actions[_trans] == 0 ) - goto _again; - - switch ( _indic_syllable_machine_trans_actions[_trans] ) { - case 2: -#line 1 "NONE" - {te = p+1;} - break; - case 11: -#line 98 "hb-ot-shape-complex-indic-machine.rl" - {te = p+1;{ found_syllable (indic_non_indic_cluster); }} - break; - case 13: -#line 93 "hb-ot-shape-complex-indic-machine.rl" - {te = p;p--;{ found_syllable (indic_consonant_syllable); }} - break; - case 14: -#line 94 "hb-ot-shape-complex-indic-machine.rl" - {te = p;p--;{ found_syllable (indic_vowel_syllable); }} - break; - case 17: -#line 95 "hb-ot-shape-complex-indic-machine.rl" - {te = p;p--;{ found_syllable (indic_standalone_cluster); }} - break; - case 19: -#line 96 "hb-ot-shape-complex-indic-machine.rl" - {te = p;p--;{ found_syllable (indic_symbol_cluster); }} - break; - case 15: -#line 97 "hb-ot-shape-complex-indic-machine.rl" - {te = p;p--;{ found_syllable (indic_broken_cluster); }} - break; - case 16: -#line 98 "hb-ot-shape-complex-indic-machine.rl" - {te = p;p--;{ found_syllable (indic_non_indic_cluster); }} - break; - case 1: -#line 93 "hb-ot-shape-complex-indic-machine.rl" - {{p = ((te))-1;}{ found_syllable (indic_consonant_syllable); }} - break; - case 3: -#line 94 "hb-ot-shape-complex-indic-machine.rl" - {{p = ((te))-1;}{ found_syllable (indic_vowel_syllable); }} - break; - case 7: -#line 95 "hb-ot-shape-complex-indic-machine.rl" - {{p = ((te))-1;}{ found_syllable (indic_standalone_cluster); }} - break; - case 8: -#line 96 "hb-ot-shape-complex-indic-machine.rl" - {{p = ((te))-1;}{ found_syllable (indic_symbol_cluster); }} - break; - case 4: -#line 97 "hb-ot-shape-complex-indic-machine.rl" - {{p = ((te))-1;}{ found_syllable (indic_broken_cluster); }} - break; - case 6: -#line 1 "NONE" - { switch( act ) { - case 1: - {{p = ((te))-1;} found_syllable (indic_consonant_syllable); } - break; - case 5: - {{p = ((te))-1;} found_syllable (indic_broken_cluster); } - break; - case 6: - {{p = ((te))-1;} found_syllable (indic_non_indic_cluster); } - break; - } - } - break; - case 18: -#line 1 "NONE" - {te = p+1;} -#line 93 "hb-ot-shape-complex-indic-machine.rl" - {act = 1;} - break; - case 5: -#line 1 "NONE" - {te = p+1;} -#line 97 "hb-ot-shape-complex-indic-machine.rl" - {act = 5;} - break; - case 12: -#line 1 "NONE" - {te = p+1;} -#line 98 "hb-ot-shape-complex-indic-machine.rl" - {act = 6;} - break; -#line 573 "hb-ot-shape-complex-indic-machine.hh" - } - -_again: - switch ( _indic_syllable_machine_to_state_actions[cs] ) { - case 9: -#line 1 "NONE" - {ts = 0;} - break; -#line 582 "hb-ot-shape-complex-indic-machine.hh" - } - - if ( ++p != pe ) - goto _resume; - _test_eof: {} - if ( p == eof ) - { - if ( _indic_syllable_machine_eof_trans[cs] > 0 ) { - _trans = _indic_syllable_machine_eof_trans[cs] - 1; - goto _eof_trans; - } - } - - } - -#line 130 "hb-ot-shape-complex-indic-machine.rl" - -} - -#undef found_syllable - -#endif /* HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH */ diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic-table.cc b/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic-table.cc deleted file mode 100644 index 326aa9f96e..0000000000 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic-table.cc +++ /dev/null @@ -1,501 +0,0 @@ -/* == Start of generated table == */ -/* - * The following table is generated by running: - * - * ./gen-indic-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt Blocks.txt - * - * on files with these headers: - * - * # IndicSyllabicCategory-14.0.0.txt - * # Date: 2021-05-22, 01:01:00 GMT [KW, RP] - * # IndicPositionalCategory-14.0.0.txt - * # Date: 2021-05-22, 01:01:00 GMT [KW, RP] - * # Blocks-14.0.0.txt - * # Date: 2021-01-22, 23:29:00 GMT [KW] - */ - -#include "hb.hh" - -#ifndef HB_NO_OT_SHAPE - -#include "hb-ot-shape-complex-indic.hh" - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-macros" - -#define ISC_A INDIC_SYLLABIC_CATEGORY_AVAGRAHA /* 17 chars; Avagraha */ -#define ISC_Bi INDIC_SYLLABIC_CATEGORY_BINDU /* 91 chars; Bindu */ -#define ISC_BJN INDIC_SYLLABIC_CATEGORY_BRAHMI_JOINING_NUMBER /* 20 chars; Brahmi_Joining_Number */ -#define ISC_Ca INDIC_SYLLABIC_CATEGORY_CANTILLATION_MARK /* 59 chars; Cantillation_Mark */ -#define ISC_C INDIC_SYLLABIC_CATEGORY_CONSONANT /* 2206 chars; Consonant */ -#define ISC_CD INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD /* 14 chars; Consonant_Dead */ -#define ISC_CF INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL /* 70 chars; Consonant_Final */ -#define ISC_CHL INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER /* 5 chars; Consonant_Head_Letter */ -#define ISC_CIP INDIC_SYLLABIC_CATEGORY_CONSONANT_INITIAL_POSTFIXED /* 1 chars; Consonant_Initial_Postfixed */ -#define ISC_CK INDIC_SYLLABIC_CATEGORY_CONSONANT_KILLER /* 2 chars; Consonant_Killer */ -#define ISC_CM INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL /* 31 chars; Consonant_Medial */ -#define ISC_CP INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER /* 22 chars; Consonant_Placeholder */ -#define ISC_CPR INDIC_SYLLABIC_CATEGORY_CONSONANT_PRECEDING_REPHA /* 3 chars; Consonant_Preceding_Repha */ -#define ISC_CPrf INDIC_SYLLABIC_CATEGORY_CONSONANT_PREFIXED /* 10 chars; Consonant_Prefixed */ -#define ISC_CS INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED /* 94 chars; Consonant_Subjoined */ -#define ISC_CSR INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA /* 1 chars; Consonant_Succeeding_Repha */ -#define ISC_CWS INDIC_SYLLABIC_CATEGORY_CONSONANT_WITH_STACKER /* 8 chars; Consonant_With_Stacker */ -#define ISC_GM INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK /* 3 chars; Gemination_Mark */ -#define ISC_IS INDIC_SYLLABIC_CATEGORY_INVISIBLE_STACKER /* 12 chars; Invisible_Stacker */ -#define ISC_ZWJ INDIC_SYLLABIC_CATEGORY_JOINER /* 1 chars; Joiner */ -#define ISC_ML INDIC_SYLLABIC_CATEGORY_MODIFYING_LETTER /* 1 chars; Modifying_Letter */ -#define ISC_ZWNJ INDIC_SYLLABIC_CATEGORY_NON_JOINER /* 1 chars; Non_Joiner */ -#define ISC_N INDIC_SYLLABIC_CATEGORY_NUKTA /* 32 chars; Nukta */ -#define ISC_Nd INDIC_SYLLABIC_CATEGORY_NUMBER /* 491 chars; Number */ -#define ISC_NJ INDIC_SYLLABIC_CATEGORY_NUMBER_JOINER /* 1 chars; Number_Joiner */ -#define ISC_x INDIC_SYLLABIC_CATEGORY_OTHER /* 1 chars; Other */ -#define ISC_PK INDIC_SYLLABIC_CATEGORY_PURE_KILLER /* 25 chars; Pure_Killer */ -#define ISC_RS INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER /* 2 chars; Register_Shifter */ -#define ISC_SM INDIC_SYLLABIC_CATEGORY_SYLLABLE_MODIFIER /* 25 chars; Syllable_Modifier */ -#define ISC_TL INDIC_SYLLABIC_CATEGORY_TONE_LETTER /* 7 chars; Tone_Letter */ -#define ISC_TM INDIC_SYLLABIC_CATEGORY_TONE_MARK /* 42 chars; Tone_Mark */ -#define ISC_V INDIC_SYLLABIC_CATEGORY_VIRAMA /* 27 chars; Virama */ -#define ISC_Vs INDIC_SYLLABIC_CATEGORY_VISARGA /* 35 chars; Visarga */ -#define ISC_Vo INDIC_SYLLABIC_CATEGORY_VOWEL /* 30 chars; Vowel */ -#define ISC_M INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT /* 686 chars; Vowel_Dependent */ -#define ISC_VI INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT /* 486 chars; Vowel_Independent */ - -#define IMC_B INDIC_MATRA_CATEGORY_BOTTOM /* 352 chars; Bottom */ -#define IMC_BL INDIC_MATRA_CATEGORY_BOTTOM_AND_LEFT /* 1 chars; Bottom_And_Left */ -#define IMC_BR INDIC_MATRA_CATEGORY_BOTTOM_AND_RIGHT /* 4 chars; Bottom_And_Right */ -#define IMC_L INDIC_MATRA_CATEGORY_LEFT /* 64 chars; Left */ -#define IMC_LR INDIC_MATRA_CATEGORY_LEFT_AND_RIGHT /* 22 chars; Left_And_Right */ -#define IMC_x INDIC_MATRA_CATEGORY_NOT_APPLICABLE /* 1 chars; Not_Applicable */ -#define IMC_O INDIC_MATRA_CATEGORY_OVERSTRUCK /* 10 chars; Overstruck */ -#define IMC_R INDIC_MATRA_CATEGORY_RIGHT /* 290 chars; Right */ -#define IMC_T INDIC_MATRA_CATEGORY_TOP /* 418 chars; Top */ -#define IMC_TB INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM /* 10 chars; Top_And_Bottom */ -#define IMC_TBL INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_LEFT /* 2 chars; Top_And_Bottom_And_Left */ -#define IMC_TBR INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_RIGHT /* 1 chars; Top_And_Bottom_And_Right */ -#define IMC_TL INDIC_MATRA_CATEGORY_TOP_AND_LEFT /* 6 chars; Top_And_Left */ -#define IMC_TLR INDIC_MATRA_CATEGORY_TOP_AND_LEFT_AND_RIGHT /* 4 chars; Top_And_Left_And_Right */ -#define IMC_TR INDIC_MATRA_CATEGORY_TOP_AND_RIGHT /* 13 chars; Top_And_Right */ -#define IMC_VOL INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT /* 19 chars; Visual_Order_Left */ - -#pragma GCC diagnostic pop - -#define _(S,M) INDIC_COMBINE_CATEGORIES (ISC_##S, IMC_##M) - - -static const uint16_t indic_table[] = { - - -#define indic_offset_0x0028u 0 - - - /* Basic Latin */ - - /* 0028 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(CP,x), _(x,x), _(x,x), - /* 0030 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), - /* 0038 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), - -#define indic_offset_0x00b0u 24 - - - /* Latin-1 Supplement */ - - /* 00B0 */ _(x,x), _(x,x), _(SM,x), _(SM,x), _(x,x), _(x,x), _(x,x), _(x,x), - /* 00B8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), - /* 00C0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), - /* 00C8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), - /* 00D0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(CP,x), - -#define indic_offset_0x0900u 64 - - - /* Devanagari */ - - /* 0900 */ _(Bi,T), _(Bi,T), _(Bi,T), _(Vs,R), _(VI,x), _(VI,x), _(VI,x), _(VI,x), - /* 0908 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), - /* 0910 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), - /* 0918 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), - /* 0920 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), - /* 0928 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), - /* 0930 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), - /* 0938 */ _(C,x), _(C,x), _(M,T), _(M,R), _(N,B), _(A,x), _(M,R), _(M,L), - /* 0940 */ _(M,R), _(M,B), _(M,B), _(M,B), _(M,B), _(M,T), _(M,T), _(M,T), - /* 0948 */ _(M,T), _(M,R), _(M,R), _(M,R), _(M,R), _(V,B), _(M,L), _(M,R), - /* 0950 */ _(x,x), _(Ca,T), _(Ca,B), _(x,T), _(x,T), _(M,T), _(M,B), _(M,B), - /* 0958 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), - /* 0960 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(Nd,x), _(Nd,x), - /* 0968 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), - /* 0970 */ _(x,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), - /* 0978 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), - - /* Bengali */ - - /* 0980 */ _(CP,x), _(Bi,T), _(Bi,R), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x), - /* 0988 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(VI,x), - /* 0990 */ _(VI,x), _(x,x), _(x,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), - /* 0998 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), - /* 09A0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), - /* 09A8 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), - /* 09B0 */ _(C,x), _(x,x), _(C,x), _(x,x), _(x,x), _(x,x), _(C,x), _(C,x), - /* 09B8 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,B), _(A,x), _(M,R), _(M,L), - /* 09C0 */ _(M,R), _(M,B), _(M,B), _(M,B), _(M,B), _(x,x), _(x,x), _(M,L), - /* 09C8 */ _(M,L), _(x,x), _(x,x), _(M,LR), _(M,LR), _(V,B), _(CD,x), _(x,x), - /* 09D0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R), - /* 09D8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(C,x), _(C,x), _(x,x), _(C,x), - /* 09E0 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(Nd,x), _(Nd,x), - /* 09E8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), - /* 09F0 */ _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), - /* 09F8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(Bi,x), _(x,x), _(SM,T), _(x,x), - - /* Gurmukhi */ - - /* 0A00 */ _(x,x), _(Bi,T), _(Bi,T), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x), - /* 0A08 */ _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(x,x), _(x,x), _(VI,x), - /* 0A10 */ _(VI,x), _(x,x), _(x,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), - /* 0A18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), - /* 0A20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), - /* 0A28 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), - /* 0A30 */ _(C,x), _(x,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(x,x), - /* 0A38 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,B), _(x,x), _(M,R), _(M,L), - /* 0A40 */ _(M,R), _(M,B), _(M,B), _(x,x), _(x,x), _(x,x), _(x,x), _(M,T), - /* 0A48 */ _(M,T), _(x,x), _(x,x), _(M,T), _(M,T), _(V,B), _(x,x), _(x,x), - /* 0A50 */ _(x,x), _(Ca,B), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), - /* 0A58 */ _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(C,x), _(x,x), - /* 0A60 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(Nd,x), _(Nd,x), - /* 0A68 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), - /* 0A70 */ _(Bi,T), _(GM,T), _(CP,x), _(CP,x), _(x,x), _(CM,B), _(x,x), _(x,x), - /* 0A78 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), - - /* Gujarati */ - - /* 0A80 */ _(x,x), _(Bi,T), _(Bi,T), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x), - /* 0A88 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(VI,x), - /* 0A90 */ _(VI,x), _(VI,x), _(x,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), - /* 0A98 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), - /* 0AA0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), - /* 0AA8 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), - /* 0AB0 */ _(C,x), _(x,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), - /* 0AB8 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,B), _(A,x), _(M,R), _(M,L), - /* 0AC0 */ _(M,R), _(M,B), _(M,B), _(M,B), _(M,B), _(M,T), _(x,x), _(M,T), - /* 0AC8 */ _(M,T), _(M,TR), _(x,x), _(M,R), _(M,R), _(V,B), _(x,x), _(x,x), - /* 0AD0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), - /* 0AD8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), - /* 0AE0 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(Nd,x), _(Nd,x), - /* 0AE8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), - /* 0AF0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), - /* 0AF8 */ _(x,x), _(C,x), _(Ca,T), _(Ca,T), _(Ca,T), _(N,T), _(N,T), _(N,T), - - /* Oriya */ - - /* 0B00 */ _(x,x), _(Bi,T), _(Bi,R), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x), - /* 0B08 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(VI,x), - /* 0B10 */ _(VI,x), _(x,x), _(x,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), - /* 0B18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), - /* 0B20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), - /* 0B28 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), - /* 0B30 */ _(C,x), _(x,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), - /* 0B38 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,B), _(A,x), _(M,R), _(M,T), - /* 0B40 */ _(M,R), _(M,B), _(M,B), _(M,B), _(M,B), _(x,x), _(x,x), _(M,L), - /* 0B48 */ _(M,TL), _(x,x), _(x,x), _(M,LR),_(M,TLR), _(V,B), _(x,x), _(x,x), - /* 0B50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,T), _(M,T), _(M,TR), - /* 0B58 */ _(x,x), _(x,x), _(x,x), _(x,x), _(C,x), _(C,x), _(x,x), _(C,x), - /* 0B60 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(Nd,x), _(Nd,x), - /* 0B68 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), - /* 0B70 */ _(x,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), - /* 0B78 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), - - /* Tamil */ - - /* 0B80 */ _(x,x), _(x,x), _(Bi,T), _(ML,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), - /* 0B88 */ _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(x,x), _(VI,x), _(VI,x), - /* 0B90 */ _(VI,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(x,x), _(x,x), - /* 0B98 */ _(x,x), _(C,x), _(C,x), _(x,x), _(C,x), _(x,x), _(C,x), _(C,x), - /* 0BA0 */ _(x,x), _(x,x), _(x,x), _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), - /* 0BA8 */ _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(C,x), _(C,x), - /* 0BB0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), - /* 0BB8 */ _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R), _(M,R), - /* 0BC0 */ _(M,T), _(M,R), _(M,R), _(x,x), _(x,x), _(x,x), _(M,L), _(M,L), - /* 0BC8 */ _(M,L), _(x,x), _(M,LR), _(M,LR), _(M,LR), _(V,T), _(x,x), _(x,x), - /* 0BD0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R), - /* 0BD8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), - /* 0BE0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(Nd,x), _(Nd,x), - /* 0BE8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), - /* 0BF0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), - /* 0BF8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), - - /* Telugu */ - - /* 0C00 */ _(Bi,T), _(Bi,R), _(Bi,R), _(Vs,R), _(Bi,T), _(VI,x), _(VI,x), _(VI,x), - /* 0C08 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(VI,x), _(VI,x), - /* 0C10 */ _(VI,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), - /* 0C18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), - /* 0C20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), - /* 0C28 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), - /* 0C30 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), - /* 0C38 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,B), _(A,x), _(M,T), _(M,T), - /* 0C40 */ _(M,T), _(M,R), _(M,R), _(M,R), _(M,R), _(x,x), _(M,T), _(M,T), - /* 0C48 */ _(M,TB), _(x,x), _(M,T), _(M,T), _(M,T), _(V,T), _(x,x), _(x,x), - /* 0C50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,T), _(M,B), _(x,x), - /* 0C58 */ _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(CD,x), _(x,x), _(x,x), - /* 0C60 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(Nd,x), _(Nd,x), - /* 0C68 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), - /* 0C70 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), - /* 0C78 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), - - /* Kannada */ - - /* 0C80 */ _(Bi,x), _(Bi,T), _(Bi,R), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x), - /* 0C88 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(VI,x), _(VI,x), - /* 0C90 */ _(VI,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), - /* 0C98 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), - /* 0CA0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), - /* 0CA8 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), - /* 0CB0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), - /* 0CB8 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,B), _(A,x), _(M,R), _(M,T), - /* 0CC0 */ _(M,TR), _(M,R), _(M,R), _(M,R), _(M,R), _(x,x), _(M,T), _(M,TR), - /* 0CC8 */ _(M,TR), _(x,x), _(M,TR), _(M,TR), _(M,T), _(V,T), _(x,x), _(x,x), - /* 0CD0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R), _(M,R), _(x,x), - /* 0CD8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(CD,x), _(C,x), _(x,x), - /* 0CE0 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(Nd,x), _(Nd,x), - /* 0CE8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), - /* 0CF0 */ _(x,x),_(CWS,x),_(CWS,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), - /* 0CF8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), - - /* Malayalam */ - - /* 0D00 */ _(Bi,T), _(Bi,T), _(Bi,R), _(Vs,R), _(Bi,x), _(VI,x), _(VI,x), _(VI,x), - /* 0D08 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(VI,x), _(VI,x), - /* 0D10 */ _(VI,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), - /* 0D18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), - /* 0D20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), - /* 0D28 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), - /* 0D30 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), - /* 0D38 */ _(C,x), _(C,x), _(C,x), _(PK,T), _(PK,T), _(A,x), _(M,R), _(M,R), - /* 0D40 */ _(M,R), _(M,R), _(M,R), _(M,B), _(M,B), _(x,x), _(M,L), _(M,L), - /* 0D48 */ _(M,L), _(x,x), _(M,LR), _(M,LR), _(M,LR), _(V,T),_(CPR,T), _(x,x), - /* 0D50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(CD,x), _(CD,x), _(CD,x), _(M,R), - /* 0D58 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(VI,x), - /* 0D60 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(Nd,x), _(Nd,x), - /* 0D68 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), - /* 0D70 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), - /* 0D78 */ _(x,x), _(x,x), _(CD,x), _(CD,x), _(CD,x), _(CD,x), _(CD,x), _(CD,x), - - /* Sinhala */ - - /* 0D80 */ _(x,x), _(Bi,T), _(Bi,R), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x), - /* 0D88 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), - /* 0D90 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), - /* 0D98 */ _(x,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), - /* 0DA0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), - /* 0DA8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), - /* 0DB0 */ _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), - /* 0DB8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(C,x), _(x,x), _(x,x), - /* 0DC0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), - /* 0DC8 */ _(x,x), _(x,x), _(V,T), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R), - /* 0DD0 */ _(M,R), _(M,R), _(M,T), _(M,T), _(M,B), _(x,x), _(M,B), _(x,x), - /* 0DD8 */ _(M,R), _(M,L), _(M,TL), _(M,L), _(M,LR),_(M,TLR), _(M,LR), _(M,R), - /* 0DE0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(Nd,x), _(Nd,x), - /* 0DE8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), - /* 0DF0 */ _(x,x), _(x,x), _(M,R), _(M,R), _(x,x), _(x,x), _(x,x), _(x,x), - -#define indic_offset_0x1000u 1336 - - - /* Myanmar */ - - /* 1000 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), - /* 1008 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), - /* 1010 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), - /* 1018 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), - /* 1020 */ _(C,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), - /* 1028 */ _(VI,x), _(VI,x), _(VI,x), _(M,R), _(M,R), _(M,T), _(M,T), _(M,B), - /* 1030 */ _(M,B), _(M,L), _(M,T), _(M,T), _(M,T), _(M,T), _(Bi,T), _(TM,B), - /* 1038 */ _(Vs,R), _(IS,x), _(PK,T), _(CM,R),_(CM,TBL), _(CM,B), _(CM,B), _(C,x), - /* 1040 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), - /* 1048 */ _(Nd,x), _(Nd,x), _(x,x), _(CP,x), _(x,x), _(x,x), _(CP,x), _(x,x), - /* 1050 */ _(C,x), _(C,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(M,R), _(M,R), - /* 1058 */ _(M,B), _(M,B), _(C,x), _(C,x), _(C,x), _(C,x), _(CM,B), _(CM,B), - /* 1060 */ _(CM,B), _(C,x), _(M,R), _(TM,R), _(TM,R), _(C,x), _(C,x), _(M,R), - /* 1068 */ _(M,R), _(TM,R), _(TM,R), _(TM,R), _(TM,R), _(TM,R), _(C,x), _(C,x), - /* 1070 */ _(C,x), _(M,T), _(M,T), _(M,T), _(M,T), _(C,x), _(C,x), _(C,x), - /* 1078 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), - /* 1080 */ _(C,x), _(C,x), _(CM,B), _(M,R), _(M,L), _(M,T), _(M,T), _(TM,R), - /* 1088 */ _(TM,R), _(TM,R), _(TM,R), _(TM,R), _(TM,R), _(TM,B), _(C,x), _(TM,R), - /* 1090 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), - /* 1098 */ _(Nd,x), _(Nd,x), _(TM,R), _(TM,R), _(M,R), _(M,T), _(x,x), _(x,x), - -#define indic_offset_0x1780u 1496 - - - /* Khmer */ - - /* 1780 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), - /* 1788 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), - /* 1790 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), - /* 1798 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), - /* 17A0 */ _(C,x), _(C,x), _(C,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), - /* 17A8 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), - /* 17B0 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(M,R), _(M,T), - /* 17B8 */ _(M,T), _(M,T), _(M,T), _(M,B), _(M,B), _(M,B), _(M,TL),_(M,TLR), - /* 17C0 */ _(M,LR), _(M,L), _(M,L), _(M,L), _(M,LR), _(M,LR), _(Bi,T), _(Vs,R), - /* 17C8 */ _(M,R), _(RS,T), _(RS,T), _(SM,T),_(CSR,T), _(CK,T), _(SM,T), _(SM,T), - /* 17D0 */ _(SM,T), _(PK,T), _(IS,x), _(SM,T), _(x,x), _(x,x), _(x,x), _(x,x), - /* 17D8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(A,x), _(SM,T), _(x,x), _(x,x), - /* 17E0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), - /* 17E8 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), - -#define indic_offset_0x1cd0u 1608 - - - /* Vedic Extensions */ - - /* 1CD0 */ _(Ca,T), _(Ca,T), _(Ca,T), _(x,x), _(Ca,O), _(Ca,B), _(Ca,B), _(Ca,B), - /* 1CD8 */ _(Ca,B), _(Ca,B), _(Ca,T), _(Ca,T), _(Ca,B), _(Ca,B), _(Ca,B), _(Ca,B), - /* 1CE0 */ _(Ca,T), _(Ca,R), _(x,O), _(x,O), _(x,O), _(x,O), _(x,O), _(x,O), - /* 1CE8 */ _(x,O), _(x,x), _(x,x), _(x,x), _(x,x), _(x,B), _(x,x), _(x,x), - /* 1CF0 */ _(x,x), _(x,x), _(CD,x), _(CD,x), _(Ca,T),_(CWS,x),_(CWS,x), _(Ca,R), - /* 1CF8 */ _(Ca,x), _(Ca,x), _(CP,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), - -#define indic_offset_0x2008u 1656 - - - /* General Punctuation */ - - /* 2008 */ _(x,x), _(x,x), _(x,x), _(x,x),_(ZWNJ,x),_(ZWJ,x), _(x,x), _(x,x), - /* 2010 */ _(CP,x), _(CP,x), _(CP,x), _(CP,x), _(CP,x), _(x,x), _(x,x), _(x,x), - -#define indic_offset_0x2070u 1672 - - - /* Superscripts and Subscripts */ - - /* 2070 */ _(x,x), _(x,x), _(x,x), _(x,x), _(SM,x), _(x,x), _(x,x), _(x,x), - /* 2078 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), - /* 2080 */ _(x,x), _(x,x), _(SM,x), _(SM,x), _(SM,x), _(x,x), _(x,x), _(x,x), - -#define indic_offset_0xa8e0u 1696 - - - /* Devanagari Extended */ - - /* A8E0 */ _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), - /* A8E8 */ _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), - /* A8F0 */ _(Ca,T), _(Ca,T), _(Bi,x), _(Bi,x), _(x,x), _(x,x), _(x,x), _(x,x), - /* A8F8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(VI,x), _(M,T), - -#define indic_offset_0xa9e0u 1728 - - - /* Myanmar Extended-B */ - - /* A9E0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(M,T), _(x,x), _(C,x), - /* A9E8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), - /* A9F0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), - /* A9F8 */ _(Nd,x), _(Nd,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), - -#define indic_offset_0xaa60u 1760 - - - /* Myanmar Extended-A */ - - /* AA60 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), - /* AA68 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), - /* AA70 */ _(x,x), _(C,x), _(C,x), _(C,x), _(CP,x), _(CP,x), _(CP,x), _(x,x), - /* AA78 */ _(x,x), _(x,x), _(C,x), _(TM,R), _(TM,T), _(TM,R), _(C,x), _(C,x), - -}; /* Table items: 1792; occupancy: 71% */ - -uint16_t -hb_indic_get_categories (hb_codepoint_t u) -{ - switch (u >> 12) - { - case 0x0u: - if (unlikely (u == 0x00A0u)) return _(CP,x); - if (hb_in_range<hb_codepoint_t> (u, 0x0028u, 0x003Fu)) return indic_table[u - 0x0028u + indic_offset_0x0028u]; - if (hb_in_range<hb_codepoint_t> (u, 0x00B0u, 0x00D7u)) return indic_table[u - 0x00B0u + indic_offset_0x00b0u]; - if (hb_in_range<hb_codepoint_t> (u, 0x0900u, 0x0DF7u)) return indic_table[u - 0x0900u + indic_offset_0x0900u]; - break; - - case 0x1u: - if (hb_in_range<hb_codepoint_t> (u, 0x1000u, 0x109Fu)) return indic_table[u - 0x1000u + indic_offset_0x1000u]; - if (hb_in_range<hb_codepoint_t> (u, 0x1780u, 0x17EFu)) return indic_table[u - 0x1780u + indic_offset_0x1780u]; - if (hb_in_range<hb_codepoint_t> (u, 0x1CD0u, 0x1CFFu)) return indic_table[u - 0x1CD0u + indic_offset_0x1cd0u]; - break; - - case 0x2u: - if (unlikely (u == 0x25CCu)) return _(CP,x); - if (hb_in_range<hb_codepoint_t> (u, 0x2008u, 0x2017u)) return indic_table[u - 0x2008u + indic_offset_0x2008u]; - if (hb_in_range<hb_codepoint_t> (u, 0x2070u, 0x2087u)) return indic_table[u - 0x2070u + indic_offset_0x2070u]; - break; - - case 0xAu: - if (hb_in_range<hb_codepoint_t> (u, 0xA8E0u, 0xA8FFu)) return indic_table[u - 0xA8E0u + indic_offset_0xa8e0u]; - if (hb_in_range<hb_codepoint_t> (u, 0xA9E0u, 0xA9FFu)) return indic_table[u - 0xA9E0u + indic_offset_0xa9e0u]; - if (hb_in_range<hb_codepoint_t> (u, 0xAA60u, 0xAA7Fu)) return indic_table[u - 0xAA60u + indic_offset_0xaa60u]; - break; - - default: - break; - } - return _(x,x); -} - -#undef _ - -#undef ISC_A -#undef ISC_Bi -#undef ISC_BJN -#undef ISC_Ca -#undef ISC_C -#undef ISC_CD -#undef ISC_CF -#undef ISC_CHL -#undef ISC_CIP -#undef ISC_CK -#undef ISC_CM -#undef ISC_CP -#undef ISC_CPR -#undef ISC_CPrf -#undef ISC_CS -#undef ISC_CSR -#undef ISC_CWS -#undef ISC_GM -#undef ISC_IS -#undef ISC_ZWJ -#undef ISC_ML -#undef ISC_ZWNJ -#undef ISC_N -#undef ISC_Nd -#undef ISC_NJ -#undef ISC_x -#undef ISC_PK -#undef ISC_RS -#undef ISC_SM -#undef ISC_TL -#undef ISC_TM -#undef ISC_V -#undef ISC_Vs -#undef ISC_Vo -#undef ISC_M -#undef ISC_VI - -#undef IMC_B -#undef IMC_BL -#undef IMC_BR -#undef IMC_L -#undef IMC_LR -#undef IMC_x -#undef IMC_O -#undef IMC_R -#undef IMC_T -#undef IMC_TB -#undef IMC_TBL -#undef IMC_TBR -#undef IMC_TL -#undef IMC_TLR -#undef IMC_TR -#undef IMC_VOL - -#endif - -/* == End of generated table == */ diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic.hh b/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic.hh deleted file mode 100644 index da77a2887c..0000000000 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic.hh +++ /dev/null @@ -1,431 +0,0 @@ -/* - * Copyright © 2012 Google, Inc. - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Google Author(s): Behdad Esfahbod - */ - -#ifndef HB_OT_SHAPE_COMPLEX_INDIC_HH -#define HB_OT_SHAPE_COMPLEX_INDIC_HH - -#include "hb.hh" - -#include "hb-ot-shape-complex-syllabic.hh" - - -/* buffer var allocations */ -#define indic_category() complex_var_u8_category() /* indic_category_t */ -#define indic_position() complex_var_u8_auxiliary() /* indic_position_t */ - - -/* Cateories used in the OpenType spec: - * https://docs.microsoft.com/en-us/typography/script-development/devanagari - */ -/* Note: This enum is duplicated in the -machine.rl source file. - * Not sure how to avoid duplication. */ -enum indic_category_t { - OT_X = 0, - OT_C = 1, - OT_V = 2, - OT_N = 3, - OT_H = 4, - OT_ZWNJ = 5, - OT_ZWJ = 6, - OT_M = 7, - OT_SM = 8, - /* OT_VD = 9, UNUSED; we use OT_A instead. */ - OT_A = 10, - OT_PLACEHOLDER = 11, - OT_DOTTEDCIRCLE = 12, - OT_RS = 13, /* Register Shifter, used in Khmer OT spec. */ - OT_Coeng = 14, /* Khmer-style Virama. */ - OT_Repha = 15, /* Atomically-encoded logical or visual repha. */ - OT_Ra = 16, - OT_CM = 17, /* Consonant-Medial. */ - OT_Symbol = 18, /* Avagraha, etc that take marks (SM,A,VD). */ - OT_CS = 19, - - /* The following are used by Khmer & Myanmar shapers. Defined - * here for them to share. */ - OT_VAbv = 26, - OT_VBlw = 27, - OT_VPre = 28, - OT_VPst = 29, -}; - -#define MEDIAL_FLAGS (FLAG (OT_CM)) - -/* Note: - * - * We treat Vowels and placeholders as if they were consonants. This is safe because Vowels - * cannot happen in a consonant syllable. The plus side however is, we can call the - * consonant syllable logic from the vowel syllable function and get it all right! */ -#define CONSONANT_FLAGS (FLAG (OT_C) | FLAG (OT_CS) | FLAG (OT_Ra) | MEDIAL_FLAGS | FLAG (OT_V) | FLAG (OT_PLACEHOLDER) | FLAG (OT_DOTTEDCIRCLE)) -#define JOINER_FLAGS (FLAG (OT_ZWJ) | FLAG (OT_ZWNJ)) - - -/* Visual positions in a syllable from left to right. */ -enum indic_position_t { - POS_START = 0, - - POS_RA_TO_BECOME_REPH = 1, - POS_PRE_M = 2, - POS_PRE_C = 3, - - POS_BASE_C = 4, - POS_AFTER_MAIN = 5, - - POS_ABOVE_C = 6, - - POS_BEFORE_SUB = 7, - POS_BELOW_C = 8, - POS_AFTER_SUB = 9, - - POS_BEFORE_POST = 10, - POS_POST_C = 11, - POS_AFTER_POST = 12, - - POS_FINAL_C = 13, - POS_SMVD = 14, - - POS_END = 15 -}; - -/* Categories used in IndicSyllabicCategory.txt from UCD. */ -enum indic_syllabic_category_t { - INDIC_SYLLABIC_CATEGORY_OTHER = OT_X, - - INDIC_SYLLABIC_CATEGORY_AVAGRAHA = OT_Symbol, - INDIC_SYLLABIC_CATEGORY_BINDU = OT_SM, - INDIC_SYLLABIC_CATEGORY_BRAHMI_JOINING_NUMBER = OT_PLACEHOLDER, /* Don't care. */ - INDIC_SYLLABIC_CATEGORY_CANTILLATION_MARK = OT_A, - INDIC_SYLLABIC_CATEGORY_CONSONANT = OT_C, - INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD = OT_C, - INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL = OT_CM, - INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER = OT_C, - INDIC_SYLLABIC_CATEGORY_CONSONANT_KILLER = OT_M, /* U+17CD only. */ - INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL = OT_CM, - INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER = OT_PLACEHOLDER, - INDIC_SYLLABIC_CATEGORY_CONSONANT_PRECEDING_REPHA = OT_Repha, - INDIC_SYLLABIC_CATEGORY_CONSONANT_PREFIXED = OT_X, /* Don't care. */ - INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED = OT_CM, - INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA = OT_CM, - INDIC_SYLLABIC_CATEGORY_CONSONANT_WITH_STACKER = OT_CS, - INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK = OT_SM, /* https://github.com/harfbuzz/harfbuzz/issues/552 */ - INDIC_SYLLABIC_CATEGORY_INVISIBLE_STACKER = OT_Coeng, - INDIC_SYLLABIC_CATEGORY_JOINER = OT_ZWJ, - INDIC_SYLLABIC_CATEGORY_MODIFYING_LETTER = OT_X, - INDIC_SYLLABIC_CATEGORY_NON_JOINER = OT_ZWNJ, - INDIC_SYLLABIC_CATEGORY_NUKTA = OT_N, - INDIC_SYLLABIC_CATEGORY_NUMBER = OT_PLACEHOLDER, - INDIC_SYLLABIC_CATEGORY_NUMBER_JOINER = OT_PLACEHOLDER, /* Don't care. */ - INDIC_SYLLABIC_CATEGORY_PURE_KILLER = OT_M, /* Is like a vowel matra. */ - INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER = OT_RS, - INDIC_SYLLABIC_CATEGORY_SYLLABLE_MODIFIER = OT_SM, - INDIC_SYLLABIC_CATEGORY_TONE_LETTER = OT_X, - INDIC_SYLLABIC_CATEGORY_TONE_MARK = OT_N, - INDIC_SYLLABIC_CATEGORY_VIRAMA = OT_H, - INDIC_SYLLABIC_CATEGORY_VISARGA = OT_SM, - INDIC_SYLLABIC_CATEGORY_VOWEL = OT_V, - INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT = OT_M, - INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT = OT_V -}; - -/* Categories used in IndicSMatraCategory.txt from UCD */ -enum indic_matra_category_t { - INDIC_MATRA_CATEGORY_NOT_APPLICABLE = POS_END, - - INDIC_MATRA_CATEGORY_LEFT = POS_PRE_C, - INDIC_MATRA_CATEGORY_TOP = POS_ABOVE_C, - INDIC_MATRA_CATEGORY_BOTTOM = POS_BELOW_C, - INDIC_MATRA_CATEGORY_RIGHT = POS_POST_C, - - /* These should resolve to the position of the last part of the split sequence. */ - INDIC_MATRA_CATEGORY_BOTTOM_AND_RIGHT = INDIC_MATRA_CATEGORY_RIGHT, - INDIC_MATRA_CATEGORY_LEFT_AND_RIGHT = INDIC_MATRA_CATEGORY_RIGHT, - INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM = INDIC_MATRA_CATEGORY_BOTTOM, - INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_LEFT = INDIC_MATRA_CATEGORY_BOTTOM, - INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_RIGHT = INDIC_MATRA_CATEGORY_RIGHT, - INDIC_MATRA_CATEGORY_TOP_AND_LEFT = INDIC_MATRA_CATEGORY_TOP, - INDIC_MATRA_CATEGORY_TOP_AND_LEFT_AND_RIGHT = INDIC_MATRA_CATEGORY_RIGHT, - INDIC_MATRA_CATEGORY_TOP_AND_RIGHT = INDIC_MATRA_CATEGORY_RIGHT, - - INDIC_MATRA_CATEGORY_OVERSTRUCK = POS_AFTER_MAIN, - INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT = POS_PRE_M -}; - -#define INDIC_COMBINE_CATEGORIES(S,M) \ - ( \ - static_assert_expr (S < 255 && M < 255) + \ - ( S | \ - ( \ - ( \ - S == INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL || \ - S == INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK || \ - S == INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER || \ - S == INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA || \ - S == INDIC_SYLLABIC_CATEGORY_VIRAMA || \ - S == INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT || \ - false \ - ? M : INDIC_MATRA_CATEGORY_NOT_APPLICABLE \ - ) << 8 \ - ) \ - ) \ - ) - -HB_INTERNAL uint16_t -hb_indic_get_categories (hb_codepoint_t u); - - -static inline bool -is_one_of (const hb_glyph_info_t &info, unsigned int flags) -{ - /* If it ligated, all bets are off. */ - if (_hb_glyph_info_ligated (&info)) return false; - return !!(FLAG_UNSAFE (info.indic_category()) & flags); -} - -static inline bool -is_joiner (const hb_glyph_info_t &info) -{ - return is_one_of (info, JOINER_FLAGS); -} - -static inline bool -is_consonant (const hb_glyph_info_t &info) -{ - return is_one_of (info, CONSONANT_FLAGS); -} - -static inline bool -is_halant (const hb_glyph_info_t &info) -{ - return is_one_of (info, FLAG (OT_H)); -} - -#define IN_HALF_BLOCK(u, Base) (((u) & ~0x7Fu) == (Base)) - -#define IS_DEVA(u) (IN_HALF_BLOCK (u, 0x0900u)) -#define IS_BENG(u) (IN_HALF_BLOCK (u, 0x0980u)) -#define IS_GURU(u) (IN_HALF_BLOCK (u, 0x0A00u)) -#define IS_GUJR(u) (IN_HALF_BLOCK (u, 0x0A80u)) -#define IS_ORYA(u) (IN_HALF_BLOCK (u, 0x0B00u)) -#define IS_TAML(u) (IN_HALF_BLOCK (u, 0x0B80u)) -#define IS_TELU(u) (IN_HALF_BLOCK (u, 0x0C00u)) -#define IS_KNDA(u) (IN_HALF_BLOCK (u, 0x0C80u)) -#define IS_MLYM(u) (IN_HALF_BLOCK (u, 0x0D00u)) -#define IS_SINH(u) (IN_HALF_BLOCK (u, 0x0D80u)) - - -#define MATRA_POS_LEFT(u) POS_PRE_M -#define MATRA_POS_RIGHT(u) ( \ - IS_DEVA(u) ? POS_AFTER_SUB : \ - IS_BENG(u) ? POS_AFTER_POST : \ - IS_GURU(u) ? POS_AFTER_POST : \ - IS_GUJR(u) ? POS_AFTER_POST : \ - IS_ORYA(u) ? POS_AFTER_POST : \ - IS_TAML(u) ? POS_AFTER_POST : \ - IS_TELU(u) ? (u <= 0x0C42u ? POS_BEFORE_SUB : POS_AFTER_SUB) : \ - IS_KNDA(u) ? (u < 0x0CC3u || u > 0xCD6u ? POS_BEFORE_SUB : POS_AFTER_SUB) : \ - IS_MLYM(u) ? POS_AFTER_POST : \ - IS_SINH(u) ? POS_AFTER_SUB : \ - /*default*/ POS_AFTER_SUB \ - ) -#define MATRA_POS_TOP(u) ( /* BENG and MLYM don't have top matras. */ \ - IS_DEVA(u) ? POS_AFTER_SUB : \ - IS_GURU(u) ? POS_AFTER_POST : /* Deviate from spec */ \ - IS_GUJR(u) ? POS_AFTER_SUB : \ - IS_ORYA(u) ? POS_AFTER_MAIN : \ - IS_TAML(u) ? POS_AFTER_SUB : \ - IS_TELU(u) ? POS_BEFORE_SUB : \ - IS_KNDA(u) ? POS_BEFORE_SUB : \ - IS_SINH(u) ? POS_AFTER_SUB : \ - /*default*/ POS_AFTER_SUB \ - ) -#define MATRA_POS_BOTTOM(u) ( \ - IS_DEVA(u) ? POS_AFTER_SUB : \ - IS_BENG(u) ? POS_AFTER_SUB : \ - IS_GURU(u) ? POS_AFTER_POST : \ - IS_GUJR(u) ? POS_AFTER_POST : \ - IS_ORYA(u) ? POS_AFTER_SUB : \ - IS_TAML(u) ? POS_AFTER_POST : \ - IS_TELU(u) ? POS_BEFORE_SUB : \ - IS_KNDA(u) ? POS_BEFORE_SUB : \ - IS_MLYM(u) ? POS_AFTER_POST : \ - IS_SINH(u) ? POS_AFTER_SUB : \ - /*default*/ POS_AFTER_SUB \ - ) - -static inline indic_position_t -matra_position_indic (hb_codepoint_t u, indic_position_t side) -{ - switch ((int) side) - { - case POS_PRE_C: return MATRA_POS_LEFT (u); - case POS_POST_C: return MATRA_POS_RIGHT (u); - case POS_ABOVE_C: return MATRA_POS_TOP (u); - case POS_BELOW_C: return MATRA_POS_BOTTOM (u); - } - return side; -} - -/* XXX - * This is a hack for now. We should move this data into the main Indic table. - * Or completely remove it and just check in the tables. - */ -static const hb_codepoint_t ra_chars[] = { - 0x0930u, /* Devanagari */ - 0x09B0u, /* Bengali */ - 0x09F0u, /* Bengali */ - 0x0A30u, /* Gurmukhi */ /* No Reph */ - 0x0AB0u, /* Gujarati */ - 0x0B30u, /* Oriya */ - 0x0BB0u, /* Tamil */ /* No Reph */ - 0x0C30u, /* Telugu */ /* Reph formed only with ZWJ */ - 0x0CB0u, /* Kannada */ - 0x0D30u, /* Malayalam */ /* No Reph, Logical Repha */ - - 0x0DBBu, /* Sinhala */ /* Reph formed only with ZWJ */ -}; - -static inline bool -is_ra (hb_codepoint_t u) -{ - return hb_array (ra_chars).lfind (u); -} - -static inline void -set_indic_properties (hb_glyph_info_t &info) -{ - hb_codepoint_t u = info.codepoint; - unsigned int type = hb_indic_get_categories (u); - indic_category_t cat = (indic_category_t) (type & 0xFFu); - indic_position_t pos = (indic_position_t) (type >> 8); - - - /* - * Re-assign category - */ - - /* The following act more like the Bindus. */ - if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x0953u, 0x0954u))) - cat = OT_SM; - /* The following act like consonants. */ - else if (unlikely (hb_in_ranges<hb_codepoint_t> (u, 0x0A72u, 0x0A73u, - 0x1CF5u, 0x1CF6u))) - cat = OT_C; - /* TODO: The following should only be allowed after a Visarga. - * For now, just treat them like regular tone marks. */ - else if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x1CE2u, 0x1CE8u))) - cat = OT_A; - /* TODO: The following should only be allowed after some of - * the nasalization marks, maybe only for U+1CE9..U+1CF1. - * For now, just treat them like tone marks. */ - else if (unlikely (u == 0x1CEDu)) - cat = OT_A; - /* The following take marks in standalone clusters, similar to Avagraha. */ - else if (unlikely (hb_in_ranges<hb_codepoint_t> (u, 0xA8F2u, 0xA8F7u, - 0x1CE9u, 0x1CECu, - 0x1CEEu, 0x1CF1u))) - { - cat = OT_Symbol; - static_assert (((int) INDIC_SYLLABIC_CATEGORY_AVAGRAHA == OT_Symbol), ""); - } - else if (unlikely (u == 0x0A51u)) - { - /* https://github.com/harfbuzz/harfbuzz/issues/524 */ - cat = OT_M; - pos = POS_BELOW_C; - } - - /* According to ScriptExtensions.txt, these Grantha marks may also be used in Tamil, - * so the Indic shaper needs to know their categories. */ - else if (unlikely (u == 0x11301u || u == 0x11303u)) cat = OT_SM; - else if (unlikely (u == 0x1133Bu || u == 0x1133Cu)) cat = OT_N; - - else if (unlikely (u == 0x0AFBu)) cat = OT_N; /* https://github.com/harfbuzz/harfbuzz/issues/552 */ - else if (unlikely (u == 0x0B55u)) cat = OT_N; /* https://github.com/harfbuzz/harfbuzz/issues/2849 */ - - else if (unlikely (u == 0x0980u)) cat = OT_PLACEHOLDER; /* https://github.com/harfbuzz/harfbuzz/issues/538 */ - else if (unlikely (u == 0x09FCu)) cat = OT_PLACEHOLDER; /* https://github.com/harfbuzz/harfbuzz/pull/1613 */ - else if (unlikely (u == 0x0C80u)) cat = OT_PLACEHOLDER; /* https://github.com/harfbuzz/harfbuzz/pull/623 */ - else if (unlikely (u == 0x0D04u)) cat = OT_PLACEHOLDER; /* https://github.com/harfbuzz/harfbuzz/pull/3511 */ - else if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x2010u, 0x2011u))) - cat = OT_PLACEHOLDER; - else if (unlikely (u == 0x25CCu)) cat = OT_DOTTEDCIRCLE; - - - /* - * Re-assign position. - */ - - if ((FLAG_UNSAFE (cat) & CONSONANT_FLAGS)) - { - pos = POS_BASE_C; - if (is_ra (u)) - cat = OT_Ra; - } - else if (cat == OT_M) - { - pos = matra_position_indic (u, pos); - } - else if ((FLAG_UNSAFE (cat) & (FLAG (OT_SM) /* | FLAG (OT_VD) */ | FLAG (OT_A) | FLAG (OT_Symbol)))) - { - pos = POS_SMVD; - } - - if (unlikely (u == 0x0B01u)) pos = POS_BEFORE_SUB; /* Oriya Bindu is BeforeSub in the spec. */ - - - - info.indic_category() = cat; - info.indic_position() = pos; -} - -struct hb_indic_would_substitute_feature_t -{ - void init (const hb_ot_map_t *map, hb_tag_t feature_tag, bool zero_context_) - { - zero_context = zero_context_; - map->get_stage_lookups (0/*GSUB*/, - map->get_feature_stage (0/*GSUB*/, feature_tag), - &lookups, &count); - } - - bool would_substitute (const hb_codepoint_t *glyphs, - unsigned int glyphs_count, - hb_face_t *face) const - { - for (unsigned int i = 0; i < count; i++) - if (hb_ot_layout_lookup_would_substitute (face, lookups[i].index, glyphs, glyphs_count, zero_context)) - return true; - return false; - } - - private: - const hb_ot_map_t::lookup_map_t *lookups; - unsigned int count; - bool zero_context; -}; - - -#endif /* HB_OT_SHAPE_COMPLEX_INDIC_HH */ diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer-machine.hh b/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer-machine.hh deleted file mode 100644 index c52f72f394..0000000000 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer-machine.hh +++ /dev/null @@ -1,396 +0,0 @@ - -#line 1 "hb-ot-shape-complex-khmer-machine.rl" -/* - * Copyright © 2011,2012 Google, Inc. - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Google Author(s): Behdad Esfahbod - */ - -#ifndef HB_OT_SHAPE_COMPLEX_KHMER_MACHINE_HH -#define HB_OT_SHAPE_COMPLEX_KHMER_MACHINE_HH - -#include "hb.hh" - -enum khmer_syllable_type_t { - khmer_consonant_syllable, - khmer_broken_cluster, - khmer_non_khmer_cluster, -}; - - -#line 42 "hb-ot-shape-complex-khmer-machine.hh" -#define khmer_syllable_machine_ex_C 1u -#define khmer_syllable_machine_ex_Coeng 14u -#define khmer_syllable_machine_ex_DOTTEDCIRCLE 12u -#define khmer_syllable_machine_ex_PLACEHOLDER 11u -#define khmer_syllable_machine_ex_Ra 16u -#define khmer_syllable_machine_ex_Robatic 20u -#define khmer_syllable_machine_ex_V 2u -#define khmer_syllable_machine_ex_VAbv 26u -#define khmer_syllable_machine_ex_VBlw 27u -#define khmer_syllable_machine_ex_VPre 28u -#define khmer_syllable_machine_ex_VPst 29u -#define khmer_syllable_machine_ex_Xgroup 21u -#define khmer_syllable_machine_ex_Ygroup 22u -#define khmer_syllable_machine_ex_ZWJ 6u -#define khmer_syllable_machine_ex_ZWNJ 5u - - -#line 60 "hb-ot-shape-complex-khmer-machine.hh" -static const unsigned char _khmer_syllable_machine_trans_keys[] = { - 5u, 26u, 5u, 21u, 5u, 26u, 5u, 21u, 1u, 16u, 5u, 21u, 5u, 26u, 5u, 21u, - 5u, 26u, 5u, 21u, 5u, 21u, 5u, 26u, 5u, 21u, 1u, 16u, 5u, 21u, 5u, 26u, - 5u, 21u, 5u, 26u, 5u, 21u, 5u, 26u, 1u, 29u, 5u, 29u, 5u, 29u, 5u, 29u, - 22u, 22u, 5u, 22u, 5u, 29u, 5u, 29u, 5u, 29u, 1u, 16u, 5u, 26u, 5u, 29u, - 5u, 29u, 22u, 22u, 5u, 22u, 5u, 29u, 5u, 29u, 1u, 16u, 5u, 29u, 5u, 29u, - 0 -}; - -static const char _khmer_syllable_machine_key_spans[] = { - 22, 17, 22, 17, 16, 17, 22, 17, - 22, 17, 17, 22, 17, 16, 17, 22, - 17, 22, 17, 22, 29, 25, 25, 25, - 1, 18, 25, 25, 25, 16, 22, 25, - 25, 1, 18, 25, 25, 16, 25, 25 -}; - -static const short _khmer_syllable_machine_index_offsets[] = { - 0, 23, 41, 64, 82, 99, 117, 140, - 158, 181, 199, 217, 240, 258, 275, 293, - 316, 334, 357, 375, 398, 428, 454, 480, - 506, 508, 527, 553, 579, 605, 622, 645, - 671, 697, 699, 718, 744, 770, 787, 813 -}; - -static const char _khmer_syllable_machine_indicies[] = { - 1, 1, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 2, - 3, 0, 0, 0, 0, 4, 0, 1, - 1, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 3, - 0, 1, 1, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 3, 0, 0, 0, 0, 4, 0, - 5, 5, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 4, 0, 6, 6, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 6, 0, 7, 7, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 8, 0, 9, 9, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 10, 0, 0, - 0, 0, 4, 0, 9, 9, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 10, 0, 11, 11, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 12, 0, - 0, 0, 0, 4, 0, 11, 11, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 12, 0, 14, - 14, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 15, - 13, 14, 14, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 15, 16, 16, 16, 16, 17, 16, - 18, 18, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 17, 16, 19, 19, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 19, 16, 20, 20, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 21, 16, 22, 22, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 23, 16, 16, - 16, 16, 17, 16, 22, 22, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 23, 16, 24, 24, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 25, 16, - 16, 16, 16, 17, 16, 24, 24, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 25, 16, 14, - 14, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 26, 15, - 16, 16, 16, 16, 17, 16, 28, 28, - 27, 27, 29, 29, 27, 27, 27, 27, - 2, 2, 27, 30, 27, 28, 27, 27, - 27, 27, 15, 19, 27, 27, 27, 17, - 23, 25, 21, 27, 32, 32, 31, 31, - 31, 31, 31, 31, 31, 33, 31, 31, - 31, 31, 31, 2, 3, 6, 31, 31, - 31, 4, 10, 12, 8, 31, 34, 34, - 31, 31, 31, 31, 31, 31, 31, 35, - 31, 31, 31, 31, 31, 31, 3, 6, - 31, 31, 31, 4, 10, 12, 8, 31, - 5, 5, 31, 31, 31, 31, 31, 31, - 31, 35, 31, 31, 31, 31, 31, 31, - 4, 6, 31, 31, 31, 31, 31, 31, - 8, 31, 6, 31, 7, 7, 31, 31, - 31, 31, 31, 31, 31, 35, 31, 31, - 31, 31, 31, 31, 8, 6, 31, 36, - 36, 31, 31, 31, 31, 31, 31, 31, - 35, 31, 31, 31, 31, 31, 31, 10, - 6, 31, 31, 31, 4, 31, 31, 8, - 31, 37, 37, 31, 31, 31, 31, 31, - 31, 31, 35, 31, 31, 31, 31, 31, - 31, 12, 6, 31, 31, 31, 4, 10, - 31, 8, 31, 34, 34, 31, 31, 31, - 31, 31, 31, 31, 33, 31, 31, 31, - 31, 31, 31, 3, 6, 31, 31, 31, - 4, 10, 12, 8, 31, 28, 28, 31, - 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 28, 31, 14, 14, - 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 15, 38, - 38, 38, 38, 17, 38, 40, 40, 39, - 39, 39, 39, 39, 39, 39, 41, 39, - 39, 39, 39, 39, 39, 15, 19, 39, - 39, 39, 17, 23, 25, 21, 39, 18, - 18, 39, 39, 39, 39, 39, 39, 39, - 41, 39, 39, 39, 39, 39, 39, 17, - 19, 39, 39, 39, 39, 39, 39, 21, - 39, 19, 39, 20, 20, 39, 39, 39, - 39, 39, 39, 39, 41, 39, 39, 39, - 39, 39, 39, 21, 19, 39, 42, 42, - 39, 39, 39, 39, 39, 39, 39, 41, - 39, 39, 39, 39, 39, 39, 23, 19, - 39, 39, 39, 17, 39, 39, 21, 39, - 43, 43, 39, 39, 39, 39, 39, 39, - 39, 41, 39, 39, 39, 39, 39, 39, - 25, 19, 39, 39, 39, 17, 23, 39, - 21, 39, 44, 44, 39, 39, 39, 39, - 39, 39, 39, 39, 39, 39, 39, 39, - 39, 44, 39, 45, 45, 39, 39, 39, - 39, 39, 39, 39, 30, 39, 39, 39, - 39, 39, 26, 15, 19, 39, 39, 39, - 17, 23, 25, 21, 39, 40, 40, 39, - 39, 39, 39, 39, 39, 39, 30, 39, - 39, 39, 39, 39, 39, 15, 19, 39, - 39, 39, 17, 23, 25, 21, 39, 0 -}; - -static const char _khmer_syllable_machine_trans_targs[] = { - 20, 1, 28, 22, 23, 3, 24, 5, - 25, 7, 26, 9, 27, 20, 10, 31, - 20, 32, 12, 33, 14, 34, 16, 35, - 18, 36, 39, 20, 21, 30, 37, 20, - 0, 29, 2, 4, 6, 8, 20, 20, - 11, 13, 15, 17, 38, 19 -}; - -static const char _khmer_syllable_machine_trans_actions[] = { - 1, 0, 2, 2, 2, 0, 0, 0, - 2, 0, 2, 0, 2, 3, 0, 4, - 5, 2, 0, 0, 0, 2, 0, 2, - 0, 2, 4, 8, 2, 9, 0, 10, - 0, 0, 0, 0, 0, 0, 11, 12, - 0, 0, 0, 0, 4, 0 -}; - -static const char _khmer_syllable_machine_to_state_actions[] = { - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 6, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 -}; - -static const char _khmer_syllable_machine_from_state_actions[] = { - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 7, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 -}; - -static const unsigned char _khmer_syllable_machine_eof_trans[] = { - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 14, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 0, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 39, 40, - 40, 40, 40, 40, 40, 40, 40, 40 -}; - -static const int khmer_syllable_machine_start = 20; -static const int khmer_syllable_machine_first_final = 20; -static const int khmer_syllable_machine_error = -1; - -static const int khmer_syllable_machine_en_main = 20; - - -#line 43 "hb-ot-shape-complex-khmer-machine.rl" - - - -#line 86 "hb-ot-shape-complex-khmer-machine.rl" - - -#define found_syllable(syllable_type) \ - HB_STMT_START { \ - if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \ - for (unsigned int i = ts; i < te; i++) \ - info[i].syllable() = (syllable_serial << 4) | syllable_type; \ - syllable_serial++; \ - if (unlikely (syllable_serial == 16)) syllable_serial = 1; \ - } HB_STMT_END - -static void -find_syllables_khmer (hb_buffer_t *buffer) -{ - unsigned int p, pe, eof, ts, te, act HB_UNUSED; - int cs; - hb_glyph_info_t *info = buffer->info; - -#line 266 "hb-ot-shape-complex-khmer-machine.hh" - { - cs = khmer_syllable_machine_start; - ts = 0; - te = 0; - act = 0; - } - -#line 106 "hb-ot-shape-complex-khmer-machine.rl" - - - p = 0; - pe = eof = buffer->len; - - unsigned int syllable_serial = 1; - -#line 282 "hb-ot-shape-complex-khmer-machine.hh" - { - int _slen; - int _trans; - const unsigned char *_keys; - const char *_inds; - if ( p == pe ) - goto _test_eof; -_resume: - switch ( _khmer_syllable_machine_from_state_actions[cs] ) { - case 7: -#line 1 "NONE" - {ts = p;} - break; -#line 296 "hb-ot-shape-complex-khmer-machine.hh" - } - - _keys = _khmer_syllable_machine_trans_keys + (cs<<1); - _inds = _khmer_syllable_machine_indicies + _khmer_syllable_machine_index_offsets[cs]; - - _slen = _khmer_syllable_machine_key_spans[cs]; - _trans = _inds[ _slen > 0 && _keys[0] <=( info[p].khmer_category()) && - ( info[p].khmer_category()) <= _keys[1] ? - ( info[p].khmer_category()) - _keys[0] : _slen ]; - -_eof_trans: - cs = _khmer_syllable_machine_trans_targs[_trans]; - - if ( _khmer_syllable_machine_trans_actions[_trans] == 0 ) - goto _again; - - switch ( _khmer_syllable_machine_trans_actions[_trans] ) { - case 2: -#line 1 "NONE" - {te = p+1;} - break; - case 8: -#line 82 "hb-ot-shape-complex-khmer-machine.rl" - {te = p+1;{ found_syllable (khmer_non_khmer_cluster); }} - break; - case 10: -#line 80 "hb-ot-shape-complex-khmer-machine.rl" - {te = p;p--;{ found_syllable (khmer_consonant_syllable); }} - break; - case 12: -#line 81 "hb-ot-shape-complex-khmer-machine.rl" - {te = p;p--;{ found_syllable (khmer_broken_cluster); }} - break; - case 11: -#line 82 "hb-ot-shape-complex-khmer-machine.rl" - {te = p;p--;{ found_syllable (khmer_non_khmer_cluster); }} - break; - case 1: -#line 80 "hb-ot-shape-complex-khmer-machine.rl" - {{p = ((te))-1;}{ found_syllable (khmer_consonant_syllable); }} - break; - case 5: -#line 81 "hb-ot-shape-complex-khmer-machine.rl" - {{p = ((te))-1;}{ found_syllable (khmer_broken_cluster); }} - break; - case 3: -#line 1 "NONE" - { switch( act ) { - case 2: - {{p = ((te))-1;} found_syllable (khmer_broken_cluster); } - break; - case 3: - {{p = ((te))-1;} found_syllable (khmer_non_khmer_cluster); } - break; - } - } - break; - case 4: -#line 1 "NONE" - {te = p+1;} -#line 81 "hb-ot-shape-complex-khmer-machine.rl" - {act = 2;} - break; - case 9: -#line 1 "NONE" - {te = p+1;} -#line 82 "hb-ot-shape-complex-khmer-machine.rl" - {act = 3;} - break; -#line 366 "hb-ot-shape-complex-khmer-machine.hh" - } - -_again: - switch ( _khmer_syllable_machine_to_state_actions[cs] ) { - case 6: -#line 1 "NONE" - {ts = 0;} - break; -#line 375 "hb-ot-shape-complex-khmer-machine.hh" - } - - if ( ++p != pe ) - goto _resume; - _test_eof: {} - if ( p == eof ) - { - if ( _khmer_syllable_machine_eof_trans[cs] > 0 ) { - _trans = _khmer_syllable_machine_eof_trans[cs] - 1; - goto _eof_trans; - } - } - - } - -#line 114 "hb-ot-shape-complex-khmer-machine.rl" - -} - -#undef found_syllable - -#endif /* HB_OT_SHAPE_COMPLEX_KHMER_MACHINE_HH */ diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer.hh b/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer.hh deleted file mode 100644 index 35bfbb64d5..0000000000 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer.hh +++ /dev/null @@ -1,115 +0,0 @@ -/* - * 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_SHAPE_COMPLEX_KHMER_HH -#define HB_OT_SHAPE_COMPLEX_KHMER_HH - -#include "hb.hh" - -#include "hb-ot-shape-complex-indic.hh" - - -/* buffer var allocations */ -#define khmer_category() indic_category() /* khmer_category_t */ - - -/* Note: This enum is duplicated in the -machine.rl source file. - * Not sure how to avoid duplication. */ -enum khmer_category_t -{ - OT_Robatic = 20, - OT_Xgroup = 21, - OT_Ygroup = 22, - //OT_VAbv = 26, - //OT_VBlw = 27, - //OT_VPre = 28, - //OT_VPst = 29, -}; - -using khmer_position_t = indic_position_t; - -static inline void -set_khmer_properties (hb_glyph_info_t &info) -{ - hb_codepoint_t u = info.codepoint; - unsigned int type = hb_indic_get_categories (u); - khmer_category_t cat = (khmer_category_t) (type & 0xFFu); - khmer_position_t pos = (khmer_position_t) (type >> 8); - - - /* - * Re-assign category - * - * These categories are experimentally extracted from what Uniscribe allows. - */ - switch (u) - { - case 0x179Au: - cat = (khmer_category_t) OT_Ra; - break; - - case 0x17CCu: - case 0x17C9u: - case 0x17CAu: - cat = OT_Robatic; - break; - - case 0x17C6u: - case 0x17CBu: - case 0x17CDu: - case 0x17CEu: - case 0x17CFu: - case 0x17D0u: - case 0x17D1u: - cat = OT_Xgroup; - break; - - case 0x17C7u: - case 0x17C8u: - case 0x17DDu: - case 0x17D3u: /* Just guessing. Uniscribe doesn't categorize it. */ - cat = OT_Ygroup; - break; - } - - /* - * Re-assign position. - */ - if (cat == (khmer_category_t) OT_M) - switch ((int) pos) - { - case POS_PRE_C: cat = (khmer_category_t) OT_VPre; break; - case POS_BELOW_C: cat = (khmer_category_t) OT_VBlw; break; - case POS_ABOVE_C: cat = (khmer_category_t) OT_VAbv; break; - case POS_POST_C: cat = (khmer_category_t) OT_VPst; break; - default: assert (0); - } - - info.khmer_category() = cat; -} - - -#endif /* HB_OT_SHAPE_COMPLEX_KHMER_HH */ diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar-machine.hh b/thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar-machine.hh deleted file mode 100644 index f4ef33004d..0000000000 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar-machine.hh +++ /dev/null @@ -1,492 +0,0 @@ - -#line 1 "hb-ot-shape-complex-myanmar-machine.rl" -/* - * Copyright © 2011,2012 Google, Inc. - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Google Author(s): Behdad Esfahbod - */ - -#ifndef HB_OT_SHAPE_COMPLEX_MYANMAR_MACHINE_HH -#define HB_OT_SHAPE_COMPLEX_MYANMAR_MACHINE_HH - -#include "hb.hh" - -enum myanmar_syllable_type_t { - myanmar_consonant_syllable, - myanmar_punctuation_cluster, - myanmar_broken_cluster, - myanmar_non_myanmar_cluster, -}; - - -#line 43 "hb-ot-shape-complex-myanmar-machine.hh" -#define myanmar_syllable_machine_ex_A 10u -#define myanmar_syllable_machine_ex_As 18u -#define myanmar_syllable_machine_ex_C 1u -#define myanmar_syllable_machine_ex_CS 19u -#define myanmar_syllable_machine_ex_D 32u -#define myanmar_syllable_machine_ex_D0 20u -#define myanmar_syllable_machine_ex_DB 3u -#define myanmar_syllable_machine_ex_GB 11u -#define myanmar_syllable_machine_ex_H 4u -#define myanmar_syllable_machine_ex_IV 2u -#define myanmar_syllable_machine_ex_MH 21u -#define myanmar_syllable_machine_ex_ML 33u -#define myanmar_syllable_machine_ex_MR 22u -#define myanmar_syllable_machine_ex_MW 23u -#define myanmar_syllable_machine_ex_MY 24u -#define myanmar_syllable_machine_ex_P 31u -#define myanmar_syllable_machine_ex_PT 25u -#define myanmar_syllable_machine_ex_Ra 16u -#define myanmar_syllable_machine_ex_V 8u -#define myanmar_syllable_machine_ex_VAbv 26u -#define myanmar_syllable_machine_ex_VBlw 27u -#define myanmar_syllable_machine_ex_VPre 28u -#define myanmar_syllable_machine_ex_VPst 29u -#define myanmar_syllable_machine_ex_VS 30u -#define myanmar_syllable_machine_ex_ZWJ 6u -#define myanmar_syllable_machine_ex_ZWNJ 5u - - -#line 72 "hb-ot-shape-complex-myanmar-machine.hh" -static const unsigned char _myanmar_syllable_machine_trans_keys[] = { - 1u, 33u, 3u, 33u, 5u, 29u, 5u, 8u, 5u, 29u, 3u, 25u, 5u, 25u, 5u, 25u, - 3u, 33u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 33u, 1u, 16u, 3u, 33u, 3u, 33u, - 3u, 29u, 3u, 29u, 3u, 29u, 3u, 30u, 3u, 29u, 3u, 33u, 3u, 33u, 3u, 33u, - 3u, 33u, 3u, 33u, 5u, 29u, 5u, 8u, 5u, 29u, 3u, 25u, 5u, 25u, 5u, 25u, - 3u, 33u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 33u, 1u, 16u, 3u, 33u, 3u, 33u, - 3u, 33u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 30u, 3u, 29u, 3u, 33u, 3u, 33u, - 3u, 33u, 3u, 33u, 3u, 33u, 3u, 33u, 3u, 33u, 1u, 33u, 1u, 32u, 8u, 8u, - 0 -}; - -static const char _myanmar_syllable_machine_key_spans[] = { - 33, 31, 25, 4, 25, 23, 21, 21, - 31, 27, 27, 27, 31, 16, 31, 31, - 27, 27, 27, 28, 27, 31, 31, 31, - 31, 31, 25, 4, 25, 23, 21, 21, - 31, 27, 27, 27, 31, 16, 31, 31, - 31, 27, 27, 27, 28, 27, 31, 31, - 31, 31, 31, 31, 31, 33, 32, 1 -}; - -static const short _myanmar_syllable_machine_index_offsets[] = { - 0, 34, 66, 92, 97, 123, 147, 169, - 191, 223, 251, 279, 307, 339, 356, 388, - 420, 448, 476, 504, 533, 561, 593, 625, - 657, 689, 721, 747, 752, 778, 802, 824, - 846, 878, 906, 934, 962, 994, 1011, 1043, - 1075, 1107, 1135, 1163, 1191, 1220, 1248, 1280, - 1312, 1344, 1376, 1408, 1440, 1472, 1506, 1539 -}; - -static const char _myanmar_syllable_machine_indicies[] = { - 1, 1, 2, 3, 4, 4, 0, 5, - 0, 6, 1, 0, 0, 0, 0, 7, - 0, 8, 9, 0, 10, 11, 12, 13, - 14, 15, 16, 17, 18, 19, 20, 1, - 21, 0, 23, 24, 25, 25, 22, 26, - 22, 27, 22, 22, 22, 22, 22, 22, - 22, 28, 22, 22, 29, 30, 31, 32, - 33, 34, 35, 36, 37, 38, 22, 22, - 39, 22, 25, 25, 22, 26, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 40, - 22, 22, 22, 22, 22, 22, 33, 22, - 22, 22, 37, 22, 25, 25, 22, 26, - 22, 25, 25, 22, 26, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 33, 22, 22, - 22, 37, 22, 41, 22, 25, 25, 22, - 26, 22, 33, 22, 22, 22, 22, 22, - 22, 22, 42, 22, 22, 22, 22, 22, - 22, 33, 22, 25, 25, 22, 26, 22, - 22, 22, 22, 22, 22, 22, 22, 22, - 42, 22, 22, 22, 22, 22, 22, 33, - 22, 25, 25, 22, 26, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 33, 22, 23, - 22, 25, 25, 22, 26, 22, 27, 22, - 22, 22, 22, 22, 22, 22, 43, 22, - 22, 44, 22, 22, 22, 33, 45, 22, - 22, 37, 22, 22, 22, 43, 22, 23, - 22, 25, 25, 22, 26, 22, 27, 22, - 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 33, 22, 22, - 22, 37, 22, 23, 22, 25, 25, 22, - 26, 22, 27, 22, 22, 22, 22, 22, - 22, 22, 43, 22, 22, 22, 22, 22, - 22, 33, 45, 22, 22, 37, 22, 23, - 22, 25, 25, 22, 26, 22, 27, 22, - 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 33, 45, 22, - 22, 37, 22, 23, 22, 25, 25, 22, - 26, 22, 27, 22, 22, 22, 22, 22, - 22, 22, 43, 22, 22, 22, 22, 22, - 22, 33, 45, 22, 22, 37, 22, 22, - 22, 43, 22, 1, 1, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 1, 22, 23, 22, 25, 25, - 22, 26, 22, 27, 22, 22, 22, 22, - 22, 22, 22, 28, 22, 22, 29, 30, - 31, 32, 33, 34, 35, 36, 37, 22, - 22, 22, 39, 22, 23, 22, 25, 25, - 22, 26, 22, 27, 22, 22, 22, 22, - 22, 22, 22, 46, 22, 22, 22, 22, - 22, 22, 33, 34, 35, 36, 37, 22, - 22, 22, 39, 22, 23, 22, 25, 25, - 22, 26, 22, 27, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 33, 34, 35, 36, 37, 22, - 23, 22, 25, 25, 22, 26, 22, 27, - 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 33, 34, - 35, 22, 37, 22, 23, 22, 25, 25, - 22, 26, 22, 27, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 33, 22, 35, 22, 37, 22, - 23, 22, 25, 25, 22, 26, 22, 27, - 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 33, 34, - 35, 36, 37, 46, 22, 23, 22, 25, - 25, 22, 26, 22, 27, 22, 22, 22, - 22, 22, 22, 22, 46, 22, 22, 22, - 22, 22, 22, 33, 34, 35, 36, 37, - 22, 23, 22, 25, 25, 22, 26, 22, - 27, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 29, 22, 31, 22, 33, - 34, 35, 36, 37, 22, 22, 22, 39, - 22, 23, 22, 25, 25, 22, 26, 22, - 27, 22, 22, 22, 22, 22, 22, 22, - 46, 22, 22, 29, 22, 22, 22, 33, - 34, 35, 36, 37, 22, 22, 22, 39, - 22, 23, 22, 25, 25, 22, 26, 22, - 27, 22, 22, 22, 22, 22, 22, 22, - 47, 22, 22, 29, 30, 31, 22, 33, - 34, 35, 36, 37, 22, 22, 22, 39, - 22, 23, 22, 25, 25, 22, 26, 22, - 27, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 29, 30, 31, 22, 33, - 34, 35, 36, 37, 22, 22, 22, 39, - 22, 23, 24, 25, 25, 22, 26, 22, - 27, 22, 22, 22, 22, 22, 22, 22, - 28, 22, 22, 29, 30, 31, 32, 33, - 34, 35, 36, 37, 22, 22, 22, 39, - 22, 49, 49, 48, 5, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 50, 48, - 48, 48, 48, 48, 48, 14, 48, 48, - 48, 18, 48, 49, 49, 48, 5, 48, - 49, 49, 48, 5, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 14, 48, 48, 48, - 18, 48, 51, 48, 49, 49, 48, 5, - 48, 14, 48, 48, 48, 48, 48, 48, - 48, 52, 48, 48, 48, 48, 48, 48, - 14, 48, 49, 49, 48, 5, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 52, - 48, 48, 48, 48, 48, 48, 14, 48, - 49, 49, 48, 5, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 14, 48, 2, 48, - 49, 49, 48, 5, 48, 6, 48, 48, - 48, 48, 48, 48, 48, 53, 48, 48, - 54, 48, 48, 48, 14, 55, 48, 48, - 18, 48, 48, 48, 53, 48, 2, 48, - 49, 49, 48, 5, 48, 6, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 14, 48, 48, 48, - 18, 48, 2, 48, 49, 49, 48, 5, - 48, 6, 48, 48, 48, 48, 48, 48, - 48, 53, 48, 48, 48, 48, 48, 48, - 14, 55, 48, 48, 18, 48, 2, 48, - 49, 49, 48, 5, 48, 6, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 14, 55, 48, 48, - 18, 48, 2, 48, 49, 49, 48, 5, - 48, 6, 48, 48, 48, 48, 48, 48, - 48, 53, 48, 48, 48, 48, 48, 48, - 14, 55, 48, 48, 18, 48, 48, 48, - 53, 48, 56, 56, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 56, 48, 2, 3, 49, 49, 48, - 5, 48, 6, 48, 48, 48, 48, 48, - 48, 48, 8, 48, 48, 10, 11, 12, - 13, 14, 15, 16, 17, 18, 19, 48, - 48, 21, 48, 2, 48, 49, 49, 48, - 5, 48, 6, 48, 48, 48, 48, 48, - 48, 48, 8, 48, 48, 10, 11, 12, - 13, 14, 15, 16, 17, 18, 48, 48, - 48, 21, 48, 2, 48, 49, 49, 48, - 5, 48, 6, 48, 48, 48, 48, 48, - 48, 48, 57, 48, 48, 48, 48, 48, - 48, 14, 15, 16, 17, 18, 48, 48, - 48, 21, 48, 2, 48, 49, 49, 48, - 5, 48, 6, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 14, 15, 16, 17, 18, 48, 2, - 48, 49, 49, 48, 5, 48, 6, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 14, 15, 16, - 48, 18, 48, 2, 48, 49, 49, 48, - 5, 48, 6, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 14, 48, 16, 48, 18, 48, 2, - 48, 49, 49, 48, 5, 48, 6, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 14, 15, 16, - 17, 18, 57, 48, 2, 48, 49, 49, - 48, 5, 48, 6, 48, 48, 48, 48, - 48, 48, 48, 57, 48, 48, 48, 48, - 48, 48, 14, 15, 16, 17, 18, 48, - 2, 48, 49, 49, 48, 5, 48, 6, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 10, 48, 12, 48, 14, 15, - 16, 17, 18, 48, 48, 48, 21, 48, - 2, 48, 49, 49, 48, 5, 48, 6, - 48, 48, 48, 48, 48, 48, 48, 57, - 48, 48, 10, 48, 48, 48, 14, 15, - 16, 17, 18, 48, 48, 48, 21, 48, - 2, 48, 49, 49, 48, 5, 48, 6, - 48, 48, 48, 48, 48, 48, 48, 58, - 48, 48, 10, 11, 12, 48, 14, 15, - 16, 17, 18, 48, 48, 48, 21, 48, - 2, 48, 49, 49, 48, 5, 48, 6, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 10, 11, 12, 48, 14, 15, - 16, 17, 18, 48, 48, 48, 21, 48, - 2, 3, 49, 49, 48, 5, 48, 6, - 48, 48, 48, 48, 48, 48, 48, 8, - 48, 48, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 48, 48, 48, 21, 48, - 23, 24, 25, 25, 22, 26, 22, 27, - 22, 22, 22, 22, 22, 22, 22, 59, - 22, 22, 29, 30, 31, 32, 33, 34, - 35, 36, 37, 38, 22, 22, 39, 22, - 23, 60, 25, 25, 22, 26, 22, 27, - 22, 22, 22, 22, 22, 22, 22, 28, - 22, 22, 29, 30, 31, 32, 33, 34, - 35, 36, 37, 22, 22, 22, 39, 22, - 1, 1, 2, 3, 49, 49, 48, 5, - 48, 6, 1, 48, 48, 48, 48, 1, - 48, 8, 48, 48, 10, 11, 12, 13, - 14, 15, 16, 17, 18, 19, 48, 1, - 21, 48, 1, 1, 61, 61, 61, 61, - 61, 61, 61, 61, 1, 61, 61, 61, - 61, 1, 61, 61, 61, 61, 61, 61, - 61, 61, 61, 61, 61, 61, 61, 61, - 61, 1, 61, 62, 61, 0 -}; - -static const char _myanmar_syllable_machine_trans_targs[] = { - 0, 1, 26, 37, 0, 27, 33, 51, - 39, 54, 40, 46, 47, 48, 29, 42, - 43, 44, 32, 50, 55, 45, 0, 2, - 13, 0, 3, 9, 14, 15, 21, 22, - 23, 5, 17, 18, 19, 8, 25, 20, - 4, 6, 7, 10, 12, 11, 16, 24, - 0, 0, 28, 30, 31, 34, 36, 35, - 38, 41, 49, 52, 53, 0, 0 -}; - -static const char _myanmar_syllable_machine_trans_actions[] = { - 3, 0, 0, 0, 4, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 5, 0, - 0, 6, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 7, 8, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 9, 10 -}; - -static const char _myanmar_syllable_machine_to_state_actions[] = { - 1, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 -}; - -static const char _myanmar_syllable_machine_from_state_actions[] = { - 2, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 -}; - -static const short _myanmar_syllable_machine_eof_trans[] = { - 0, 23, 23, 23, 23, 23, 23, 23, - 23, 23, 23, 23, 23, 23, 23, 23, - 23, 23, 23, 23, 23, 23, 23, 23, - 23, 23, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 23, 23, 49, 62, 62 -}; - -static const int myanmar_syllable_machine_start = 0; -static const int myanmar_syllable_machine_first_final = 0; -static const int myanmar_syllable_machine_error = -1; - -static const int myanmar_syllable_machine_en_main = 0; - - -#line 44 "hb-ot-shape-complex-myanmar-machine.rl" - - - -#line 102 "hb-ot-shape-complex-myanmar-machine.rl" - - -#define found_syllable(syllable_type) \ - HB_STMT_START { \ - if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \ - for (unsigned int i = ts; i < te; i++) \ - info[i].syllable() = (syllable_serial << 4) | syllable_type; \ - syllable_serial++; \ - if (unlikely (syllable_serial == 16)) syllable_serial = 1; \ - } HB_STMT_END - -static void -find_syllables_myanmar (hb_buffer_t *buffer) -{ - unsigned int p, pe, eof, ts, te, act HB_UNUSED; - int cs; - hb_glyph_info_t *info = buffer->info; - -#line 382 "hb-ot-shape-complex-myanmar-machine.hh" - { - cs = myanmar_syllable_machine_start; - ts = 0; - te = 0; - act = 0; - } - -#line 122 "hb-ot-shape-complex-myanmar-machine.rl" - - - p = 0; - pe = eof = buffer->len; - - unsigned int syllable_serial = 1; - -#line 398 "hb-ot-shape-complex-myanmar-machine.hh" - { - int _slen; - int _trans; - const unsigned char *_keys; - const char *_inds; - if ( p == pe ) - goto _test_eof; -_resume: - switch ( _myanmar_syllable_machine_from_state_actions[cs] ) { - case 2: -#line 1 "NONE" - {ts = p;} - break; -#line 412 "hb-ot-shape-complex-myanmar-machine.hh" - } - - _keys = _myanmar_syllable_machine_trans_keys + (cs<<1); - _inds = _myanmar_syllable_machine_indicies + _myanmar_syllable_machine_index_offsets[cs]; - - _slen = _myanmar_syllable_machine_key_spans[cs]; - _trans = _inds[ _slen > 0 && _keys[0] <=( info[p].myanmar_category()) && - ( info[p].myanmar_category()) <= _keys[1] ? - ( info[p].myanmar_category()) - _keys[0] : _slen ]; - -_eof_trans: - cs = _myanmar_syllable_machine_trans_targs[_trans]; - - if ( _myanmar_syllable_machine_trans_actions[_trans] == 0 ) - goto _again; - - switch ( _myanmar_syllable_machine_trans_actions[_trans] ) { - case 6: -#line 94 "hb-ot-shape-complex-myanmar-machine.rl" - {te = p+1;{ found_syllable (myanmar_consonant_syllable); }} - break; - case 4: -#line 95 "hb-ot-shape-complex-myanmar-machine.rl" - {te = p+1;{ found_syllable (myanmar_non_myanmar_cluster); }} - break; - case 10: -#line 96 "hb-ot-shape-complex-myanmar-machine.rl" - {te = p+1;{ found_syllable (myanmar_punctuation_cluster); }} - break; - case 8: -#line 97 "hb-ot-shape-complex-myanmar-machine.rl" - {te = p+1;{ found_syllable (myanmar_broken_cluster); }} - break; - case 3: -#line 98 "hb-ot-shape-complex-myanmar-machine.rl" - {te = p+1;{ found_syllable (myanmar_non_myanmar_cluster); }} - break; - case 5: -#line 94 "hb-ot-shape-complex-myanmar-machine.rl" - {te = p;p--;{ found_syllable (myanmar_consonant_syllable); }} - break; - case 7: -#line 97 "hb-ot-shape-complex-myanmar-machine.rl" - {te = p;p--;{ found_syllable (myanmar_broken_cluster); }} - break; - case 9: -#line 98 "hb-ot-shape-complex-myanmar-machine.rl" - {te = p;p--;{ found_syllable (myanmar_non_myanmar_cluster); }} - break; -#line 462 "hb-ot-shape-complex-myanmar-machine.hh" - } - -_again: - switch ( _myanmar_syllable_machine_to_state_actions[cs] ) { - case 1: -#line 1 "NONE" - {ts = 0;} - break; -#line 471 "hb-ot-shape-complex-myanmar-machine.hh" - } - - if ( ++p != pe ) - goto _resume; - _test_eof: {} - if ( p == eof ) - { - if ( _myanmar_syllable_machine_eof_trans[cs] > 0 ) { - _trans = _myanmar_syllable_machine_eof_trans[cs] - 1; - goto _eof_trans; - } - } - - } - -#line 130 "hb-ot-shape-complex-myanmar-machine.rl" - -} - -#undef found_syllable - -#endif /* HB_OT_SHAPE_COMPLEX_MYANMAR_MACHINE_HH */ diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar.hh b/thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar.hh deleted file mode 100644 index 7fbca3878f..0000000000 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar.hh +++ /dev/null @@ -1,177 +0,0 @@ -/* - * 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_SHAPE_COMPLEX_MYANMAR_HH -#define HB_OT_SHAPE_COMPLEX_MYANMAR_HH - -#include "hb.hh" - -#include "hb-ot-shape-complex-indic.hh" - - -/* buffer var allocations */ -#define myanmar_category() indic_category() /* myanmar_category_t */ -#define myanmar_position() indic_position() /* myanmar_position_t */ - - -/* Note: This enum is duplicated in the -machine.rl source file. - * Not sure how to avoid duplication. */ -enum myanmar_category_t { - OT_As = 18, /* Asat */ - OT_D0 = 20, /* Digit zero */ - OT_DB = OT_N, /* Dot below */ - OT_GB = OT_PLACEHOLDER, - OT_MH = 21, /* Various consonant medial types */ - OT_MR = 22, /* Various consonant medial types */ - OT_MW = 23, /* Various consonant medial types */ - OT_MY = 24, /* Various consonant medial types */ - OT_PT = 25, /* Pwo and other tones */ - //OT_VAbv = 26, - //OT_VBlw = 27, - //OT_VPre = 28, - //OT_VPst = 29, - OT_VS = 30, /* Variation selectors */ - OT_P = 31, /* Punctuation */ - OT_D = 32, /* Digits except zero */ - OT_ML = 33, /* Various consonant medial types */ -}; - -using myanmar_position_t = indic_position_t; - -static inline void -set_myanmar_properties (hb_glyph_info_t &info) -{ - hb_codepoint_t u = info.codepoint; - unsigned int type = hb_indic_get_categories (u); - unsigned int cat = type & 0xFFu; - myanmar_position_t pos = (myanmar_position_t) (type >> 8); - - /* Myanmar - * https://docs.microsoft.com/en-us/typography/script-development/myanmar#analyze - */ - if (unlikely (hb_in_range<hb_codepoint_t> (u, 0xFE00u, 0xFE0Fu))) - cat = OT_VS; - - switch (u) - { - case 0x104Eu: - cat = OT_C; /* The spec says C, IndicSyllableCategory doesn't have. */ - break; - - case 0x002Du: case 0x00A0u: case 0x00D7u: case 0x2012u: - case 0x2013u: case 0x2014u: case 0x2015u: case 0x2022u: - case 0x25CCu: case 0x25FBu: case 0x25FCu: case 0x25FDu: - case 0x25FEu: - cat = OT_GB; - break; - - case 0x1004u: case 0x101Bu: case 0x105Au: - cat = OT_Ra; - break; - - case 0x1032u: case 0x1036u: - cat = OT_A; - break; - - case 0x1039u: - cat = OT_H; - break; - - case 0x103Au: - cat = OT_As; - break; - - case 0x1041u: case 0x1042u: case 0x1043u: case 0x1044u: - case 0x1045u: case 0x1046u: case 0x1047u: case 0x1048u: - case 0x1049u: case 0x1090u: case 0x1091u: case 0x1092u: - case 0x1093u: case 0x1094u: case 0x1095u: case 0x1096u: - case 0x1097u: case 0x1098u: case 0x1099u: - cat = OT_D; - break; - - case 0x1040u: - cat = OT_D; /* XXX The spec says D0, but Uniscribe doesn't seem to do. */ - break; - - case 0x103Eu: - cat = OT_MH; - break; - - case 0x1060u: - cat = OT_ML; - break; - - case 0x103Cu: - cat = OT_MR; - break; - - case 0x103Du: case 0x1082u: - cat = OT_MW; - break; - - case 0x103Bu: case 0x105Eu: case 0x105Fu: - cat = OT_MY; - break; - - case 0x1063u: case 0x1064u: case 0x1069u: case 0x106Au: - case 0x106Bu: case 0x106Cu: case 0x106Du: case 0xAA7Bu: - cat = OT_PT; - break; - - case 0x1038u: case 0x1087u: case 0x1088u: case 0x1089u: - case 0x108Au: case 0x108Bu: case 0x108Cu: case 0x108Du: - case 0x108Fu: case 0x109Au: case 0x109Bu: case 0x109Cu: - cat = OT_SM; - break; - - case 0x104Au: case 0x104Bu: - cat = OT_P; - break; - - case 0xAA74u: case 0xAA75u: case 0xAA76u: - /* https://github.com/harfbuzz/harfbuzz/issues/218 */ - cat = OT_C; - break; - } - - if (cat == OT_M) - { - switch ((int) pos) - { - case POS_PRE_C: cat = (myanmar_category_t) OT_VPre; - pos = POS_PRE_M; break; - case POS_ABOVE_C: cat = (myanmar_category_t) OT_VAbv; break; - case POS_BELOW_C: cat = (myanmar_category_t) OT_VBlw; break; - case POS_POST_C: cat = (myanmar_category_t) OT_VPst; break; - } - } - - info.myanmar_category() = cat; - info.myanmar_position() = pos; -} - - -#endif /* HB_OT_SHAPE_COMPLEX_MYANMAR_HH */ diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-use-machine.hh b/thirdparty/harfbuzz/src/hb-ot-shape-complex-use-machine.hh deleted file mode 100644 index 468bd95c3f..0000000000 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-use-machine.hh +++ /dev/null @@ -1,849 +0,0 @@ - -#line 1 "hb-ot-shape-complex-use-machine.rl" -/* - * Copyright © 2015 Mozilla Foundation. - * Copyright © 2015 Google, Inc. - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Mozilla Author(s): Jonathan Kew - * Google Author(s): Behdad Esfahbod - */ - -#ifndef HB_OT_SHAPE_COMPLEX_USE_MACHINE_HH -#define HB_OT_SHAPE_COMPLEX_USE_MACHINE_HH - -#include "hb.hh" - -#include "hb-ot-shape-complex-syllabic.hh" - -/* buffer var allocations */ -#define use_category() complex_var_u8_category() - -#define USE(Cat) use_syllable_machine_ex_##Cat - -enum use_syllable_type_t { - use_virama_terminated_cluster, - use_sakot_terminated_cluster, - use_standard_cluster, - use_number_joiner_terminated_cluster, - use_numeral_cluster, - use_symbol_cluster, - use_hieroglyph_cluster, - use_broken_cluster, - use_non_cluster, -}; - - -#line 57 "hb-ot-shape-complex-use-machine.hh" -#define use_syllable_machine_ex_B 1u -#define use_syllable_machine_ex_CGJ 6u -#define use_syllable_machine_ex_CMAbv 31u -#define use_syllable_machine_ex_CMBlw 32u -#define use_syllable_machine_ex_CS 43u -#define use_syllable_machine_ex_FAbv 24u -#define use_syllable_machine_ex_FBlw 25u -#define use_syllable_machine_ex_FMAbv 45u -#define use_syllable_machine_ex_FMBlw 46u -#define use_syllable_machine_ex_FMPst 47u -#define use_syllable_machine_ex_FPst 26u -#define use_syllable_machine_ex_G 49u -#define use_syllable_machine_ex_GB 5u -#define use_syllable_machine_ex_H 12u -#define use_syllable_machine_ex_HN 13u -#define use_syllable_machine_ex_IS 44u -#define use_syllable_machine_ex_J 50u -#define use_syllable_machine_ex_MAbv 27u -#define use_syllable_machine_ex_MBlw 28u -#define use_syllable_machine_ex_MPre 30u -#define use_syllable_machine_ex_MPst 29u -#define use_syllable_machine_ex_N 4u -#define use_syllable_machine_ex_O 0u -#define use_syllable_machine_ex_R 18u -#define use_syllable_machine_ex_SB 51u -#define use_syllable_machine_ex_SE 52u -#define use_syllable_machine_ex_SMAbv 41u -#define use_syllable_machine_ex_SMBlw 42u -#define use_syllable_machine_ex_SUB 11u -#define use_syllable_machine_ex_Sk 48u -#define use_syllable_machine_ex_VAbv 33u -#define use_syllable_machine_ex_VBlw 34u -#define use_syllable_machine_ex_VMAbv 37u -#define use_syllable_machine_ex_VMBlw 38u -#define use_syllable_machine_ex_VMPre 23u -#define use_syllable_machine_ex_VMPst 39u -#define use_syllable_machine_ex_VPre 22u -#define use_syllable_machine_ex_VPst 35u -#define use_syllable_machine_ex_WJ 16u -#define use_syllable_machine_ex_ZWNJ 14u - - -#line 100 "hb-ot-shape-complex-use-machine.hh" -static const unsigned char _use_syllable_machine_trans_keys[] = { - 0u, 51u, 11u, 48u, 11u, 48u, 1u, 48u, 23u, 48u, 24u, 47u, 25u, 47u, 26u, 47u, - 45u, 46u, 46u, 46u, 24u, 48u, 24u, 48u, 24u, 48u, 1u, 1u, 24u, 48u, 22u, 48u, - 23u, 48u, 23u, 48u, 23u, 48u, 12u, 48u, 12u, 48u, 12u, 48u, 12u, 48u, 11u, 48u, - 1u, 1u, 11u, 48u, 41u, 42u, 42u, 42u, 11u, 48u, 11u, 48u, 1u, 48u, 23u, 48u, - 24u, 47u, 25u, 47u, 26u, 47u, 45u, 46u, 46u, 46u, 24u, 48u, 24u, 48u, 24u, 48u, - 1u, 1u, 24u, 48u, 22u, 48u, 23u, 48u, 23u, 48u, 23u, 48u, 12u, 48u, 12u, 48u, - 12u, 48u, 12u, 48u, 11u, 48u, 1u, 1u, 13u, 13u, 4u, 4u, 11u, 48u, 11u, 48u, - 1u, 48u, 23u, 48u, 24u, 47u, 25u, 47u, 26u, 47u, 45u, 46u, 46u, 46u, 24u, 48u, - 24u, 48u, 24u, 48u, 1u, 1u, 24u, 48u, 22u, 48u, 23u, 48u, 23u, 48u, 23u, 48u, - 12u, 48u, 12u, 48u, 12u, 48u, 12u, 48u, 11u, 48u, 1u, 1u, 11u, 48u, 11u, 48u, - 1u, 48u, 23u, 48u, 24u, 47u, 25u, 47u, 26u, 47u, 45u, 46u, 46u, 46u, 24u, 48u, - 24u, 48u, 24u, 48u, 1u, 1u, 24u, 48u, 22u, 48u, 23u, 48u, 23u, 48u, 23u, 48u, - 12u, 48u, 12u, 48u, 12u, 48u, 12u, 48u, 11u, 48u, 1u, 1u, 4u, 4u, 13u, 13u, - 1u, 48u, 11u, 48u, 41u, 42u, 42u, 42u, 1u, 5u, 50u, 52u, 49u, 52u, 49u, 51u, - 0 -}; - -static const char _use_syllable_machine_key_spans[] = { - 52, 38, 38, 48, 26, 24, 23, 22, - 2, 1, 25, 25, 25, 1, 25, 27, - 26, 26, 26, 37, 37, 37, 37, 38, - 1, 38, 2, 1, 38, 38, 48, 26, - 24, 23, 22, 2, 1, 25, 25, 25, - 1, 25, 27, 26, 26, 26, 37, 37, - 37, 37, 38, 1, 1, 1, 38, 38, - 48, 26, 24, 23, 22, 2, 1, 25, - 25, 25, 1, 25, 27, 26, 26, 26, - 37, 37, 37, 37, 38, 1, 38, 38, - 48, 26, 24, 23, 22, 2, 1, 25, - 25, 25, 1, 25, 27, 26, 26, 26, - 37, 37, 37, 37, 38, 1, 1, 1, - 48, 38, 2, 1, 5, 3, 4, 3 -}; - -static const short _use_syllable_machine_index_offsets[] = { - 0, 53, 92, 131, 180, 207, 232, 256, - 279, 282, 284, 310, 336, 362, 364, 390, - 418, 445, 472, 499, 537, 575, 613, 651, - 690, 692, 731, 734, 736, 775, 814, 863, - 890, 915, 939, 962, 965, 967, 993, 1019, - 1045, 1047, 1073, 1101, 1128, 1155, 1182, 1220, - 1258, 1296, 1334, 1373, 1375, 1377, 1379, 1418, - 1457, 1506, 1533, 1558, 1582, 1605, 1608, 1610, - 1636, 1662, 1688, 1690, 1716, 1744, 1771, 1798, - 1825, 1863, 1901, 1939, 1977, 2016, 2018, 2057, - 2096, 2145, 2172, 2197, 2221, 2244, 2247, 2249, - 2275, 2301, 2327, 2329, 2355, 2383, 2410, 2437, - 2464, 2502, 2540, 2578, 2616, 2655, 2657, 2659, - 2661, 2710, 2749, 2752, 2754, 2760, 2764, 2769 -}; - -static const char _use_syllable_machine_indicies[] = { - 0, 1, 2, 2, 3, 4, 2, 2, - 2, 2, 2, 5, 6, 7, 2, 2, - 2, 2, 8, 2, 2, 2, 9, 10, - 11, 12, 13, 14, 15, 16, 17, 18, - 19, 20, 21, 22, 2, 23, 24, 25, - 2, 26, 27, 28, 29, 30, 31, 32, - 29, 33, 2, 34, 2, 36, 37, 35, - 35, 35, 35, 35, 35, 35, 35, 35, - 38, 39, 40, 41, 42, 43, 44, 45, - 46, 47, 48, 49, 50, 51, 35, 52, - 53, 54, 35, 55, 56, 35, 57, 58, - 59, 60, 57, 35, 36, 37, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 38, - 39, 40, 41, 42, 43, 44, 45, 46, - 48, 48, 49, 50, 51, 35, 52, 53, - 54, 35, 35, 35, 35, 57, 58, 59, - 60, 57, 35, 36, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, - 35, 39, 40, 41, 42, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 52, - 53, 54, 35, 35, 35, 35, 35, 58, - 59, 60, 61, 35, 39, 40, 41, 42, - 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 52, 53, 54, 35, 35, 35, - 35, 35, 58, 59, 60, 61, 35, 40, - 41, 42, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 58, 59, 60, 35, - 41, 42, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 58, 59, 60, 35, - 42, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 58, 59, 60, 35, 58, - 59, 35, 59, 35, 40, 41, 42, 35, - 35, 35, 35, 35, 35, 35, 35, 35, - 35, 52, 53, 54, 35, 35, 35, 35, - 35, 58, 59, 60, 61, 35, 40, 41, - 42, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 53, 54, 35, 35, - 35, 35, 35, 58, 59, 60, 61, 35, - 40, 41, 42, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 54, - 35, 35, 35, 35, 35, 58, 59, 60, - 61, 35, 62, 35, 40, 41, 42, 35, - 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, - 35, 58, 59, 60, 61, 35, 38, 39, - 40, 41, 42, 35, 35, 35, 35, 35, - 35, 49, 50, 51, 35, 52, 53, 54, - 35, 35, 35, 35, 35, 58, 59, 60, - 61, 35, 39, 40, 41, 42, 35, 35, - 35, 35, 35, 35, 49, 50, 51, 35, - 52, 53, 54, 35, 35, 35, 35, 35, - 58, 59, 60, 61, 35, 39, 40, 41, - 42, 35, 35, 35, 35, 35, 35, 35, - 50, 51, 35, 52, 53, 54, 35, 35, - 35, 35, 35, 58, 59, 60, 61, 35, - 39, 40, 41, 42, 35, 35, 35, 35, - 35, 35, 35, 35, 51, 35, 52, 53, - 54, 35, 35, 35, 35, 35, 58, 59, - 60, 61, 35, 39, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 38, 39, 40, - 41, 42, 35, 44, 45, 35, 35, 35, - 49, 50, 51, 35, 52, 53, 54, 35, - 35, 35, 35, 35, 58, 59, 60, 61, - 35, 39, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 38, 39, 40, 41, 42, - 35, 35, 45, 35, 35, 35, 49, 50, - 51, 35, 52, 53, 54, 35, 35, 35, - 35, 35, 58, 59, 60, 61, 35, 39, - 35, 35, 35, 35, 35, 35, 35, 35, - 35, 38, 39, 40, 41, 42, 35, 35, - 35, 35, 35, 35, 49, 50, 51, 35, - 52, 53, 54, 35, 35, 35, 35, 35, - 58, 59, 60, 61, 35, 39, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 38, - 39, 40, 41, 42, 43, 44, 45, 35, - 35, 35, 49, 50, 51, 35, 52, 53, - 54, 35, 35, 35, 35, 35, 58, 59, - 60, 61, 35, 36, 37, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 35, - 48, 49, 50, 51, 35, 52, 53, 54, - 35, 35, 35, 35, 57, 58, 59, 60, - 57, 35, 36, 35, 36, 37, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 38, - 39, 40, 41, 42, 43, 44, 45, 46, - 47, 48, 49, 50, 51, 35, 52, 53, - 54, 35, 35, 35, 35, 57, 58, 59, - 60, 57, 35, 55, 56, 35, 56, 35, - 64, 65, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 66, 67, 68, 69, 70, - 71, 72, 73, 74, 1, 75, 76, 77, - 78, 63, 79, 80, 81, 63, 63, 63, - 63, 82, 83, 84, 85, 86, 63, 64, - 65, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 66, 67, 68, 69, 70, 71, - 72, 73, 74, 75, 75, 76, 77, 78, - 63, 79, 80, 81, 63, 63, 63, 63, - 82, 83, 84, 85, 86, 63, 64, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 67, 68, 69, 70, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 79, 80, 81, 63, 63, 63, - 63, 63, 83, 84, 85, 87, 63, 67, - 68, 69, 70, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 79, 80, 81, - 63, 63, 63, 63, 63, 83, 84, 85, - 87, 63, 68, 69, 70, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 83, - 84, 85, 63, 69, 70, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 83, - 84, 85, 63, 70, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 83, 84, - 85, 63, 83, 84, 63, 84, 63, 68, - 69, 70, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 79, 80, 81, 63, - 63, 63, 63, 63, 83, 84, 85, 87, - 63, 68, 69, 70, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 80, - 81, 63, 63, 63, 63, 63, 83, 84, - 85, 87, 63, 68, 69, 70, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 81, 63, 63, 63, 63, 63, - 83, 84, 85, 87, 63, 89, 88, 68, - 69, 70, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 83, 84, 85, 87, - 63, 66, 67, 68, 69, 70, 63, 63, - 63, 63, 63, 63, 76, 77, 78, 63, - 79, 80, 81, 63, 63, 63, 63, 63, - 83, 84, 85, 87, 63, 67, 68, 69, - 70, 63, 63, 63, 63, 63, 63, 76, - 77, 78, 63, 79, 80, 81, 63, 63, - 63, 63, 63, 83, 84, 85, 87, 63, - 67, 68, 69, 70, 63, 63, 63, 63, - 63, 63, 63, 77, 78, 63, 79, 80, - 81, 63, 63, 63, 63, 63, 83, 84, - 85, 87, 63, 67, 68, 69, 70, 63, - 63, 63, 63, 63, 63, 63, 63, 78, - 63, 79, 80, 81, 63, 63, 63, 63, - 63, 83, 84, 85, 87, 63, 67, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 66, 67, 68, 69, 70, 63, 72, 73, - 63, 63, 63, 76, 77, 78, 63, 79, - 80, 81, 63, 63, 63, 63, 63, 83, - 84, 85, 87, 63, 67, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 66, 67, - 68, 69, 70, 63, 63, 73, 63, 63, - 63, 76, 77, 78, 63, 79, 80, 81, - 63, 63, 63, 63, 63, 83, 84, 85, - 87, 63, 67, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 66, 67, 68, 69, - 70, 63, 63, 63, 63, 63, 63, 76, - 77, 78, 63, 79, 80, 81, 63, 63, - 63, 63, 63, 83, 84, 85, 87, 63, - 67, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 66, 67, 68, 69, 70, 71, - 72, 73, 63, 63, 63, 76, 77, 78, - 63, 79, 80, 81, 63, 63, 63, 63, - 63, 83, 84, 85, 87, 63, 64, 65, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 66, 67, 68, 69, 70, 71, 72, - 73, 74, 63, 75, 76, 77, 78, 63, - 79, 80, 81, 63, 63, 63, 63, 82, - 83, 84, 85, 86, 63, 64, 90, 92, - 91, 3, 93, 94, 95, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 96, 97, - 98, 99, 100, 101, 102, 103, 104, 105, - 106, 107, 108, 109, 63, 110, 111, 112, - 63, 55, 56, 63, 113, 114, 115, 85, - 116, 63, 94, 95, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 96, 97, 98, - 99, 100, 101, 102, 103, 104, 106, 106, - 107, 108, 109, 63, 110, 111, 112, 63, - 63, 63, 63, 113, 114, 115, 85, 116, - 63, 94, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 97, - 98, 99, 100, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 110, 111, 112, - 63, 63, 63, 63, 63, 114, 115, 85, - 117, 63, 97, 98, 99, 100, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 110, 111, 112, 63, 63, 63, 63, 63, - 114, 115, 85, 117, 63, 98, 99, 100, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 114, 115, 85, 63, 99, 100, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 114, 115, 85, 63, 100, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 114, 115, 85, 63, 114, 115, 63, - 115, 63, 98, 99, 100, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 110, - 111, 112, 63, 63, 63, 63, 63, 114, - 115, 85, 117, 63, 98, 99, 100, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 111, 112, 63, 63, 63, 63, - 63, 114, 115, 85, 117, 63, 98, 99, - 100, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 112, 63, 63, - 63, 63, 63, 114, 115, 85, 117, 63, - 118, 88, 98, 99, 100, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 114, - 115, 85, 117, 63, 96, 97, 98, 99, - 100, 63, 63, 63, 63, 63, 63, 107, - 108, 109, 63, 110, 111, 112, 63, 63, - 63, 63, 63, 114, 115, 85, 117, 63, - 97, 98, 99, 100, 63, 63, 63, 63, - 63, 63, 107, 108, 109, 63, 110, 111, - 112, 63, 63, 63, 63, 63, 114, 115, - 85, 117, 63, 97, 98, 99, 100, 63, - 63, 63, 63, 63, 63, 63, 108, 109, - 63, 110, 111, 112, 63, 63, 63, 63, - 63, 114, 115, 85, 117, 63, 97, 98, - 99, 100, 63, 63, 63, 63, 63, 63, - 63, 63, 109, 63, 110, 111, 112, 63, - 63, 63, 63, 63, 114, 115, 85, 117, - 63, 97, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 96, 97, 98, 99, 100, - 63, 102, 103, 63, 63, 63, 107, 108, - 109, 63, 110, 111, 112, 63, 63, 63, - 63, 63, 114, 115, 85, 117, 63, 97, - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 96, 97, 98, 99, 100, 63, 63, - 103, 63, 63, 63, 107, 108, 109, 63, - 110, 111, 112, 63, 63, 63, 63, 63, - 114, 115, 85, 117, 63, 97, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 96, - 97, 98, 99, 100, 63, 63, 63, 63, - 63, 63, 107, 108, 109, 63, 110, 111, - 112, 63, 63, 63, 63, 63, 114, 115, - 85, 117, 63, 97, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 96, 97, 98, - 99, 100, 101, 102, 103, 63, 63, 63, - 107, 108, 109, 63, 110, 111, 112, 63, - 63, 63, 63, 63, 114, 115, 85, 117, - 63, 94, 95, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 96, 97, 98, 99, - 100, 101, 102, 103, 104, 63, 106, 107, - 108, 109, 63, 110, 111, 112, 63, 63, - 63, 63, 113, 114, 115, 85, 116, 63, - 94, 90, 94, 95, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 96, 97, 98, - 99, 100, 101, 102, 103, 104, 105, 106, - 107, 108, 109, 63, 110, 111, 112, 63, - 63, 63, 63, 113, 114, 115, 85, 116, - 63, 5, 6, 119, 119, 119, 119, 119, - 119, 119, 119, 119, 9, 10, 11, 12, - 13, 14, 15, 16, 17, 19, 19, 20, - 21, 22, 119, 23, 24, 25, 119, 119, - 119, 119, 29, 30, 31, 32, 29, 119, - 5, 119, 119, 119, 119, 119, 119, 119, - 119, 119, 119, 119, 119, 119, 119, 119, - 119, 119, 119, 119, 119, 119, 10, 11, - 12, 13, 119, 119, 119, 119, 119, 119, - 119, 119, 119, 119, 23, 24, 25, 119, - 119, 119, 119, 119, 30, 31, 32, 120, - 119, 10, 11, 12, 13, 119, 119, 119, - 119, 119, 119, 119, 119, 119, 119, 23, - 24, 25, 119, 119, 119, 119, 119, 30, - 31, 32, 120, 119, 11, 12, 13, 119, - 119, 119, 119, 119, 119, 119, 119, 119, - 119, 119, 119, 119, 119, 119, 119, 119, - 119, 30, 31, 32, 119, 12, 13, 119, - 119, 119, 119, 119, 119, 119, 119, 119, - 119, 119, 119, 119, 119, 119, 119, 119, - 119, 30, 31, 32, 119, 13, 119, 119, - 119, 119, 119, 119, 119, 119, 119, 119, - 119, 119, 119, 119, 119, 119, 119, 119, - 30, 31, 32, 119, 30, 31, 119, 31, - 119, 11, 12, 13, 119, 119, 119, 119, - 119, 119, 119, 119, 119, 119, 23, 24, - 25, 119, 119, 119, 119, 119, 30, 31, - 32, 120, 119, 11, 12, 13, 119, 119, - 119, 119, 119, 119, 119, 119, 119, 119, - 119, 24, 25, 119, 119, 119, 119, 119, - 30, 31, 32, 120, 119, 11, 12, 13, - 119, 119, 119, 119, 119, 119, 119, 119, - 119, 119, 119, 119, 25, 119, 119, 119, - 119, 119, 30, 31, 32, 120, 119, 121, - 119, 11, 12, 13, 119, 119, 119, 119, - 119, 119, 119, 119, 119, 119, 119, 119, - 119, 119, 119, 119, 119, 119, 30, 31, - 32, 120, 119, 9, 10, 11, 12, 13, - 119, 119, 119, 119, 119, 119, 20, 21, - 22, 119, 23, 24, 25, 119, 119, 119, - 119, 119, 30, 31, 32, 120, 119, 10, - 11, 12, 13, 119, 119, 119, 119, 119, - 119, 20, 21, 22, 119, 23, 24, 25, - 119, 119, 119, 119, 119, 30, 31, 32, - 120, 119, 10, 11, 12, 13, 119, 119, - 119, 119, 119, 119, 119, 21, 22, 119, - 23, 24, 25, 119, 119, 119, 119, 119, - 30, 31, 32, 120, 119, 10, 11, 12, - 13, 119, 119, 119, 119, 119, 119, 119, - 119, 22, 119, 23, 24, 25, 119, 119, - 119, 119, 119, 30, 31, 32, 120, 119, - 10, 119, 119, 119, 119, 119, 119, 119, - 119, 119, 9, 10, 11, 12, 13, 119, - 15, 16, 119, 119, 119, 20, 21, 22, - 119, 23, 24, 25, 119, 119, 119, 119, - 119, 30, 31, 32, 120, 119, 10, 119, - 119, 119, 119, 119, 119, 119, 119, 119, - 9, 10, 11, 12, 13, 119, 119, 16, - 119, 119, 119, 20, 21, 22, 119, 23, - 24, 25, 119, 119, 119, 119, 119, 30, - 31, 32, 120, 119, 10, 119, 119, 119, - 119, 119, 119, 119, 119, 119, 9, 10, - 11, 12, 13, 119, 119, 119, 119, 119, - 119, 20, 21, 22, 119, 23, 24, 25, - 119, 119, 119, 119, 119, 30, 31, 32, - 120, 119, 10, 119, 119, 119, 119, 119, - 119, 119, 119, 119, 9, 10, 11, 12, - 13, 14, 15, 16, 119, 119, 119, 20, - 21, 22, 119, 23, 24, 25, 119, 119, - 119, 119, 119, 30, 31, 32, 120, 119, - 5, 6, 119, 119, 119, 119, 119, 119, - 119, 119, 119, 9, 10, 11, 12, 13, - 14, 15, 16, 17, 119, 19, 20, 21, - 22, 119, 23, 24, 25, 119, 119, 119, - 119, 29, 30, 31, 32, 29, 119, 5, - 119, 122, 119, 7, 119, 1, 119, 119, - 119, 1, 119, 119, 119, 119, 119, 5, - 6, 7, 119, 119, 119, 119, 119, 119, - 119, 119, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, - 119, 23, 24, 25, 119, 26, 27, 119, - 29, 30, 31, 32, 29, 119, 5, 6, - 119, 119, 119, 119, 119, 119, 119, 119, - 119, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 119, - 23, 24, 25, 119, 119, 119, 119, 29, - 30, 31, 32, 29, 119, 26, 27, 119, - 27, 119, 1, 123, 123, 123, 1, 123, - 125, 124, 33, 124, 33, 125, 124, 125, - 124, 33, 124, 34, 124, 0 -}; - -static const char _use_syllable_machine_trans_targs[] = { - 1, 28, 0, 52, 54, 79, 80, 102, - 104, 92, 81, 82, 83, 84, 96, 97, - 98, 99, 105, 100, 93, 94, 95, 87, - 88, 89, 106, 107, 108, 101, 85, 86, - 0, 109, 111, 0, 2, 3, 15, 4, - 5, 6, 7, 19, 20, 21, 22, 25, - 23, 16, 17, 18, 10, 11, 12, 26, - 27, 24, 8, 9, 0, 13, 14, 0, - 29, 30, 42, 31, 32, 33, 34, 46, - 47, 48, 49, 50, 43, 44, 45, 37, - 38, 39, 51, 35, 36, 0, 51, 40, - 0, 41, 0, 0, 53, 0, 55, 56, - 68, 57, 58, 59, 60, 72, 73, 74, - 75, 78, 76, 69, 70, 71, 63, 64, - 65, 77, 61, 62, 77, 66, 67, 0, - 90, 91, 103, 0, 0, 110 -}; - -static const char _use_syllable_machine_trans_actions[] = { - 0, 0, 3, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 4, 0, 0, 5, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 6, 0, 0, 7, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 8, 0, 0, 9, 10, 0, - 11, 0, 12, 13, 0, 14, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 8, 0, 0, 10, 0, 0, 15, - 0, 0, 0, 16, 17, 0 -}; - -static const char _use_syllable_machine_to_state_actions[] = { - 1, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 -}; - -static const char _use_syllable_machine_from_state_actions[] = { - 2, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 -}; - -static const short _use_syllable_machine_eof_trans[] = { - 0, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 89, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 91, 92, 94, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 89, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 91, 64, 120, - 120, 120, 120, 120, 120, 120, 120, 120, - 120, 120, 120, 120, 120, 120, 120, 120, - 120, 120, 120, 120, 120, 120, 120, 120, - 120, 120, 120, 120, 124, 125, 125, 125 -}; - -static const int use_syllable_machine_start = 0; -static const int use_syllable_machine_first_final = 0; -static const int use_syllable_machine_error = -1; - -static const int use_syllable_machine_en_main = 0; - - -#line 58 "hb-ot-shape-complex-use-machine.rl" - - - -#line 181 "hb-ot-shape-complex-use-machine.rl" - - -#define found_syllable(syllable_type) \ - HB_STMT_START { \ - if (0) fprintf (stderr, "syllable %d..%d %s\n", (*ts).second.first, (*te).second.first, #syllable_type); \ - for (unsigned i = (*ts).second.first; i < (*te).second.first; ++i) \ - info[i].syllable() = (syllable_serial << 4) | syllable_type; \ - syllable_serial++; \ - if (unlikely (syllable_serial == 16)) syllable_serial = 1; \ - } HB_STMT_END - - -template <typename Iter> -struct machine_index_t : - hb_iter_with_fallback_t<machine_index_t<Iter>, - typename Iter::item_t> -{ - machine_index_t (const Iter& it) : it (it) {} - machine_index_t (const machine_index_t& o) : hb_iter_with_fallback_t<machine_index_t<Iter>, - typename Iter::item_t> (), - it (o.it), is_null (o.is_null) {} - - static constexpr bool is_random_access_iterator = Iter::is_random_access_iterator; - static constexpr bool is_sorted_iterator = Iter::is_sorted_iterator; - - typename Iter::item_t __item__ () const { return *it; } - typename Iter::item_t __item_at__ (unsigned i) const { return it[i]; } - unsigned __len__ () const { return it.len (); } - void __next__ () { ++it; } - void __forward__ (unsigned n) { it += n; } - void __prev__ () { --it; } - void __rewind__ (unsigned n) { it -= n; } - - void operator = (unsigned n) - { - assert (n == 0); - is_null = true; - } - explicit operator bool () { return !is_null; } - - void operator = (const machine_index_t& o) - { - is_null = o.is_null; - unsigned index = (*it).first; - unsigned n = (*o.it).first; - if (index < n) it += n - index; else if (index > n) it -= index - n; - } - bool operator == (const machine_index_t& o) const - { return is_null ? o.is_null : !o.is_null && (*it).first == (*o.it).first; } - bool operator != (const machine_index_t& o) const { return !(*this == o); } - - private: - Iter it; - bool is_null = false; -}; -struct -{ - template <typename Iter, - hb_requires (hb_is_iterable (Iter))> - machine_index_t<hb_iter_type<Iter>> - operator () (Iter&& it) const - { return machine_index_t<hb_iter_type<Iter>> (hb_iter (it)); } -} -HB_FUNCOBJ (machine_index); - - - -static bool -not_ccs_default_ignorable (const hb_glyph_info_t &i) -{ return i.use_category() != USE(CGJ); } - -static inline void -find_syllables_use (hb_buffer_t *buffer) -{ - hb_glyph_info_t *info = buffer->info; - auto p = - + hb_iter (info, buffer->len) - | hb_enumerate - | hb_filter ([] (const hb_glyph_info_t &i) { return not_ccs_default_ignorable (i); }, - hb_second) - | hb_filter ([&] (const hb_pair_t<unsigned, const hb_glyph_info_t &> p) - { - if (p.second.use_category() == USE(ZWNJ)) - for (unsigned i = p.first + 1; i < buffer->len; ++i) - if (not_ccs_default_ignorable (info[i])) - return !_hb_glyph_info_is_unicode_mark (&info[i]); - return true; - }) - | hb_enumerate - | machine_index - ; - auto pe = p + p.len (); - auto eof = +pe; - auto ts = +p; - auto te = +p; - unsigned int act HB_UNUSED; - int cs; - -#line 702 "hb-ot-shape-complex-use-machine.hh" - { - cs = use_syllable_machine_start; - ts = 0; - te = 0; - act = 0; - } - -#line 281 "hb-ot-shape-complex-use-machine.rl" - - - unsigned int syllable_serial = 1; - -#line 715 "hb-ot-shape-complex-use-machine.hh" - { - int _slen; - int _trans; - const unsigned char *_keys; - const char *_inds; - if ( p == pe ) - goto _test_eof; -_resume: - switch ( _use_syllable_machine_from_state_actions[cs] ) { - case 2: -#line 1 "NONE" - {ts = p;} - break; -#line 729 "hb-ot-shape-complex-use-machine.hh" - } - - _keys = _use_syllable_machine_trans_keys + (cs<<1); - _inds = _use_syllable_machine_indicies + _use_syllable_machine_index_offsets[cs]; - - _slen = _use_syllable_machine_key_spans[cs]; - _trans = _inds[ _slen > 0 && _keys[0] <=( (*p).second.second.use_category()) && - ( (*p).second.second.use_category()) <= _keys[1] ? - ( (*p).second.second.use_category()) - _keys[0] : _slen ]; - -_eof_trans: - cs = _use_syllable_machine_trans_targs[_trans]; - - if ( _use_syllable_machine_trans_actions[_trans] == 0 ) - goto _again; - - switch ( _use_syllable_machine_trans_actions[_trans] ) { - case 9: -#line 171 "hb-ot-shape-complex-use-machine.rl" - {te = p+1;{ found_syllable (use_standard_cluster); }} - break; - case 6: -#line 174 "hb-ot-shape-complex-use-machine.rl" - {te = p+1;{ found_syllable (use_symbol_cluster); }} - break; - case 4: -#line 176 "hb-ot-shape-complex-use-machine.rl" - {te = p+1;{ found_syllable (use_broken_cluster); }} - break; - case 3: -#line 177 "hb-ot-shape-complex-use-machine.rl" - {te = p+1;{ found_syllable (use_non_cluster); }} - break; - case 11: -#line 170 "hb-ot-shape-complex-use-machine.rl" - {te = p;p--;{ found_syllable (use_sakot_terminated_cluster); }} - break; - case 7: -#line 171 "hb-ot-shape-complex-use-machine.rl" - {te = p;p--;{ found_syllable (use_standard_cluster); }} - break; - case 14: -#line 172 "hb-ot-shape-complex-use-machine.rl" - {te = p;p--;{ found_syllable (use_number_joiner_terminated_cluster); }} - break; - case 13: -#line 173 "hb-ot-shape-complex-use-machine.rl" - {te = p;p--;{ found_syllable (use_numeral_cluster); }} - break; - case 5: -#line 174 "hb-ot-shape-complex-use-machine.rl" - {te = p;p--;{ found_syllable (use_symbol_cluster); }} - break; - case 17: -#line 175 "hb-ot-shape-complex-use-machine.rl" - {te = p;p--;{ found_syllable (use_hieroglyph_cluster); }} - break; - case 15: -#line 176 "hb-ot-shape-complex-use-machine.rl" - {te = p;p--;{ found_syllable (use_broken_cluster); }} - break; - case 16: -#line 177 "hb-ot-shape-complex-use-machine.rl" - {te = p;p--;{ found_syllable (use_non_cluster); }} - break; - case 12: -#line 1 "NONE" - { switch( act ) { - case 1: - {{p = ((te))-1;} found_syllable (use_virama_terminated_cluster); } - break; - case 2: - {{p = ((te))-1;} found_syllable (use_sakot_terminated_cluster); } - break; - } - } - break; - case 8: -#line 1 "NONE" - {te = p+1;} -#line 169 "hb-ot-shape-complex-use-machine.rl" - {act = 1;} - break; - case 10: -#line 1 "NONE" - {te = p+1;} -#line 170 "hb-ot-shape-complex-use-machine.rl" - {act = 2;} - break; -#line 819 "hb-ot-shape-complex-use-machine.hh" - } - -_again: - switch ( _use_syllable_machine_to_state_actions[cs] ) { - case 1: -#line 1 "NONE" - {ts = 0;} - break; -#line 828 "hb-ot-shape-complex-use-machine.hh" - } - - if ( ++p != pe ) - goto _resume; - _test_eof: {} - if ( p == eof ) - { - if ( _use_syllable_machine_eof_trans[cs] > 0 ) { - _trans = _use_syllable_machine_eof_trans[cs] - 1; - goto _eof_trans; - } - } - - } - -#line 286 "hb-ot-shape-complex-use-machine.rl" - -} - -#undef found_syllable - -#endif /* HB_OT_SHAPE_COMPLEX_USE_MACHINE_HH */ diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-normalize.cc b/thirdparty/harfbuzz/src/hb-ot-shape-normalize.cc index aa5a8eeaa3..7db0b25b73 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape-normalize.cc +++ b/thirdparty/harfbuzz/src/hb-ot-shape-normalize.cc @@ -29,7 +29,7 @@ #ifndef HB_NO_OT_SHAPE #include "hb-ot-shape-normalize.hh" -#include "hb-ot-shape-complex.hh" +#include "hb-ot-shaper.hh" #include "hb-ot-shape.hh" @@ -69,7 +69,7 @@ * - When a font does not support a character but supports its canonical * decomposition, well, use the decomposition. * - * - The complex shapers can customize the compose and decompose functions to + * - The shapers can customize the compose and decompose functions to * offload some of their requirements to the normalizer. For example, the * Indic shaper may want to disallow recomposing of two matras. */ @@ -143,8 +143,7 @@ decompose (const hb_ot_shape_normalize_context_t *c, bool shortest, hb_codepoint return 1; } - unsigned int ret; - if ((ret = decompose (c, shortest, a))) { + if (unsigned ret = decompose (c, shortest, a)) { if (b) { output_char (buffer, b, b_glyph); return ret + 1; @@ -223,7 +222,7 @@ handle_variation_selector_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end, bool short_circuit HB_UNUSED) { - /* TODO Currently if there's a variation-selector we give-up, it's just too hard. */ + /* Currently if there's a variation-selector we give-up on normalization, it's just too hard. */ hb_buffer_t * const buffer = c->buffer; hb_font_t * const font = c->font; for (; buffer->idx < end - 1 && buffer->successful;) { @@ -395,7 +394,7 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan, break; /* We are going to do a O(n^2). Only do this if the sequence is short. */ - if (end - i > HB_OT_SHAPE_COMPLEX_MAX_COMBINING_MARKS) { + if (end - i > HB_OT_SHAPE_MAX_COMBINING_MARKS) { i = end; continue; } diff --git a/thirdparty/harfbuzz/src/hb-ot-shape.cc b/thirdparty/harfbuzz/src/hb-ot-shape.cc index 298cf47786..0806abb7dd 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape.cc +++ b/thirdparty/harfbuzz/src/hb-ot-shape.cc @@ -37,7 +37,7 @@ #include "hb-shaper-impl.hh" #include "hb-ot-shape.hh" -#include "hb-ot-shape-complex.hh" +#include "hb-ot-shaper.hh" #include "hb-ot-shape-fallback.hh" #include "hb-ot-shape-normalize.hh" @@ -47,6 +47,9 @@ #include "hb-aat-layout.hh" +static inline bool +_hb_codepoint_is_regional_indicator (hb_codepoint_t u) +{ return hb_in_range<hb_codepoint_t> (u, 0x1F1E6u, 0x1F1FFu); } #ifndef HB_NO_AAT_SHAPE static inline bool @@ -83,14 +86,14 @@ hb_ot_shape_planner_t::hb_ot_shape_planner_t (hb_face_t *fac , apply_morx (_hb_apply_morx (face, props)) #endif { - shaper = hb_ot_shape_complex_categorize (this); + shaper = hb_ot_shaper_categorize (this); script_zero_marks = shaper->zero_width_marks != HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE; script_fallback_mark_positioning = shaper->fallback_position; /* https://github.com/harfbuzz/harfbuzz/issues/1528 */ - if (apply_morx && shaper != &_hb_ot_complex_shaper_default) - shaper = &_hb_ot_complex_shaper_dumber; + if (apply_morx && shaper != &_hb_ot_shaper_default) + shaper = &_hb_ot_shaper_dumber; } void @@ -504,9 +507,9 @@ hb_set_unicode_props (hb_buffer_t *buffer) } /* Regional_Indicators are hairy as hell... * https://github.com/harfbuzz/harfbuzz/issues/2265 */ - else if (unlikely (i && hb_in_range<hb_codepoint_t> (info[i].codepoint, 0x1F1E6u, 0x1F1FFu))) + else if (unlikely (i && _hb_codepoint_is_regional_indicator (info[i].codepoint))) { - if (hb_in_range<hb_codepoint_t> (info[i - 1].codepoint, 0x1F1E6u, 0x1F1FFu) && + if (_hb_codepoint_is_regional_indicator (info[i - 1].codepoint) && !_hb_glyph_info_is_continuation (&info[i - 1])) _hb_glyph_info_set_continuation (&info[i]); } @@ -598,24 +601,33 @@ hb_ensure_native_direction (hb_buffer_t *buffer) * direction, so that features like ligatures will work as intended. * * https://github.com/harfbuzz/harfbuzz/issues/501 + * + * Similar thing about Regional_Indicators; They are bidi=L, but Script=Common. + * If they are present in a run of natively-RTL text, they get assigned a script + * with natively RTL direction, which would result in wrong shaping if we + * assign such native RTL direction to them then. Detect that as well. + * + * https://github.com/harfbuzz/harfbuzz/issues/3314 */ if (unlikely (horiz_dir == HB_DIRECTION_RTL && direction == HB_DIRECTION_LTR)) { - bool found_number = false, found_letter = false; + bool found_number = false, found_letter = false, found_ri = false; const auto* info = buffer->info; const auto count = buffer->len; for (unsigned i = 0; i < count; i++) { auto gc = _hb_glyph_info_get_general_category (&info[i]); if (gc == HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER) - found_number = true; + found_number = true; else if (HB_UNICODE_GENERAL_CATEGORY_IS_LETTER (gc)) { - found_letter = true; - break; + found_letter = true; + break; } + else if (_hb_codepoint_is_regional_indicator (info[i].codepoint)) + found_ri = true; } - if (found_number && !found_letter) + if ((found_number || found_ri) && !found_letter) horiz_dir = HB_DIRECTION_LTR; } @@ -915,7 +927,7 @@ hb_ot_substitute_default (const hb_ot_shape_context_t *c) } static inline void -hb_ot_substitute_complex (const hb_ot_shape_context_t *c) +hb_ot_substitute_plan (const hb_ot_shape_context_t *c) { hb_buffer_t *buffer = c->buffer; @@ -934,7 +946,7 @@ hb_ot_substitute_pre (const hb_ot_shape_context_t *c) _hb_buffer_allocate_gsubgpos_vars (c->buffer); - hb_ot_substitute_complex (c); + hb_ot_substitute_plan (c); #ifndef HB_NO_AAT_SHAPE if (c->plan->apply_morx && c->plan->apply_gpos) @@ -1027,7 +1039,7 @@ hb_ot_position_default (const hb_ot_shape_context_t *c) } static inline void -hb_ot_position_complex (const hb_ot_shape_context_t *c) +hb_ot_position_plan (const hb_ot_shape_context_t *c) { unsigned int count = c->buffer->len; hb_glyph_info_t *info = c->buffer->info; @@ -1112,7 +1124,7 @@ hb_ot_position (const hb_ot_shape_context_t *c) hb_ot_position_default (c); - hb_ot_position_complex (c); + hb_ot_position_plan (c); if (HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction)) hb_buffer_reverse (c->buffer); @@ -1147,8 +1159,6 @@ hb_propagate_flags (hb_buffer_t *buffer) static void hb_ot_shape_internal (hb_ot_shape_context_t *c) { - c->buffer->enter (); - /* Save the original direction, we use it later. */ c->target_direction = c->buffer->props.direction; diff --git a/thirdparty/harfbuzz/src/hb-ot-shape.hh b/thirdparty/harfbuzz/src/hb-ot-shape.hh index e8c81015c7..17fa58b337 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape.hh +++ b/thirdparty/harfbuzz/src/hb-ot-shape.hh @@ -61,7 +61,7 @@ struct hb_shape_plan_key_t; struct hb_ot_shape_plan_t { hb_segment_properties_t props; - const struct hb_ot_complex_shaper_t *shaper; + const struct hb_ot_shaper_t *shaper; hb_ot_map_t map; hb_aat_map_t aat_map; const void *data; @@ -158,7 +158,7 @@ struct hb_ot_shape_planner_t #endif bool script_zero_marks : 1; bool script_fallback_mark_positioning : 1; - const struct hb_ot_complex_shaper_t *shaper; + const struct hb_ot_shaper_t *shaper; HB_INTERNAL hb_ot_shape_planner_t (hb_face_t *face, const hb_segment_properties_t *props); diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic-fallback.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-arabic-fallback.hh index 78f46c1cac..b9f92f72d6 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic-fallback.hh +++ b/thirdparty/harfbuzz/src/hb-ot-shaper-arabic-fallback.hh @@ -24,8 +24,8 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_FALLBACK_HH -#define HB_OT_SHAPE_COMPLEX_ARABIC_FALLBACK_HH +#ifndef HB_OT_SHAPER_ARABIC_FALLBACK_HH +#define HB_OT_SHAPER_ARABIC_FALLBACK_HH #include "hb.hh" @@ -34,7 +34,11 @@ /* Features ordered the same as the entries in shaping_table rows, - * followed by rlig. Don't change. */ + * followed by rlig. Don't change. + * + * We currently support one subtable per lookup, and one lookup + * per feature. But we allow duplicate features, so we use that! + */ static const hb_tag_t arabic_fallback_features[] = { HB_TAG('i','n','i','t'), @@ -42,6 +46,8 @@ static const hb_tag_t arabic_fallback_features[] = HB_TAG('f','i','n','a'), HB_TAG('i','s','o','l'), HB_TAG('r','l','i','g'), + HB_TAG('r','l','i','g'), + HB_TAG('r','l','i','g'), }; static OT::SubstLookup * @@ -95,20 +101,25 @@ arabic_fallback_synthesize_lookup_single (const hb_ot_shape_plan_t *plan HB_UNUS return ret && !c.in_error () ? c.copy<OT::SubstLookup> () : nullptr; } +template <typename T> static OT::SubstLookup * arabic_fallback_synthesize_lookup_ligature (const hb_ot_shape_plan_t *plan HB_UNUSED, - hb_font_t *font) + hb_font_t *font, + const T &ligature_table, + unsigned lookup_flags) { OT::HBGlyphID16 first_glyphs[ARRAY_LENGTH_CONST (ligature_table)]; unsigned int first_glyphs_indirection[ARRAY_LENGTH_CONST (ligature_table)]; unsigned int ligature_per_first_glyph_count_list[ARRAY_LENGTH_CONST (first_glyphs)]; unsigned int num_first_glyphs = 0; - /* We know that all our ligatures are 2-component */ + /* We know that all our ligatures have the same number of components. */ OT::HBGlyphID16 ligature_list[ARRAY_LENGTH_CONST (first_glyphs) * ARRAY_LENGTH_CONST(ligature_table[0].ligatures)]; unsigned int component_count_list[ARRAY_LENGTH_CONST (ligature_list)]; - OT::HBGlyphID16 component_list[ARRAY_LENGTH_CONST (ligature_list) * 1/* One extra component per ligature */]; + OT::HBGlyphID16 component_list[ARRAY_LENGTH_CONST (ligature_list) * + ARRAY_LENGTH_CONST (ligature_table[0].ligatures[0].components)]; unsigned int num_ligatures = 0; + unsigned int num_components = 0; /* Populate arrays */ @@ -133,21 +144,32 @@ arabic_fallback_synthesize_lookup_ligature (const hb_ot_shape_plan_t *plan HB_UN { unsigned int first_glyph_idx = first_glyphs_indirection[i]; - for (unsigned int second_glyph_idx = 0; second_glyph_idx < ARRAY_LENGTH (ligature_table[0].ligatures); second_glyph_idx++) + for (unsigned int ligature_idx = 0; ligature_idx < ARRAY_LENGTH (ligature_table[0].ligatures); ligature_idx++) { - hb_codepoint_t second_u = ligature_table[first_glyph_idx].ligatures[second_glyph_idx].second; - hb_codepoint_t ligature_u = ligature_table[first_glyph_idx].ligatures[second_glyph_idx].ligature; - hb_codepoint_t second_glyph, ligature_glyph; - if (!second_u || - !hb_font_get_glyph (font, second_u, 0, &second_glyph) || - !hb_font_get_glyph (font, ligature_u, 0, &ligature_glyph)) + hb_codepoint_t ligature_u = ligature_table[first_glyph_idx].ligatures[ligature_idx].ligature; + hb_codepoint_t ligature_glyph; + if (!hb_font_get_glyph (font, ligature_u, 0, &ligature_glyph)) continue; - ligature_per_first_glyph_count_list[i]++; + const auto &components = ligature_table[first_glyph_idx].ligatures[ligature_idx].components; + unsigned component_count = ARRAY_LENGTH_CONST (components); + + for (unsigned i = 0; i < component_count; i++) + { + hb_codepoint_t component_u = ligature_table[first_glyph_idx].ligatures[ligature_idx].components[i]; + hb_codepoint_t component_glyph; + if (!component_u || + !hb_font_get_glyph (font, component_u, 0, &component_glyph)) + continue; + component_list[num_components++] = component_glyph; + } + + component_count_list[num_ligatures] = 1 + component_count; ligature_list[num_ligatures] = ligature_glyph; - component_count_list[num_ligatures] = 2; - component_list[num_ligatures] = second_glyph; + + ligature_per_first_glyph_count_list[i]++; + num_ligatures++; } } @@ -161,14 +183,13 @@ arabic_fallback_synthesize_lookup_ligature (const hb_ot_shape_plan_t *plan HB_UN hb_serialize_context_t c (buf, sizeof (buf)); OT::SubstLookup *lookup = c.start_serialize<OT::SubstLookup> (); bool ret = lookup->serialize_ligature (&c, - OT::LookupFlag::IgnoreMarks, + lookup_flags, hb_sorted_array (first_glyphs, num_first_glyphs), hb_array (ligature_per_first_glyph_count_list, num_first_glyphs), hb_array (ligature_list, num_ligatures), hb_array (component_count_list, num_ligatures), - hb_array (component_list, num_ligatures)); + hb_array (component_list, num_components)); c.end_serialize (); - /* TODO sanitize the results? */ return ret && !c.in_error () ? c.copy<OT::SubstLookup> () : nullptr; } @@ -181,10 +202,18 @@ arabic_fallback_synthesize_lookup (const hb_ot_shape_plan_t *plan, if (feature_index < 4) return arabic_fallback_synthesize_lookup_single (plan, font, feature_index); else - return arabic_fallback_synthesize_lookup_ligature (plan, font); + { + switch (feature_index) { + case 4: return arabic_fallback_synthesize_lookup_ligature (plan, font, ligature_3_table, OT::LookupFlag::IgnoreMarks); + case 5: return arabic_fallback_synthesize_lookup_ligature (plan, font, ligature_table, OT::LookupFlag::IgnoreMarks); + case 6: return arabic_fallback_synthesize_lookup_ligature (plan, font, ligature_mark_table, 0); + } + } + assert (false); + return nullptr; } -#define ARABIC_FALLBACK_MAX_LOOKUPS 5 +#define ARABIC_FALLBACK_MAX_LOOKUPS ARRAY_LENGTH_CONST (arabic_fallback_features) struct arabic_fallback_plan_t { @@ -201,7 +230,7 @@ struct arabic_fallback_plan_t #endif #ifdef HB_WITH_WIN1256 -#include "hb-ot-shape-complex-arabic-win1256.hh" +#include "hb-ot-shaper-arabic-win1256.hh" #endif struct ManifestLookup @@ -230,9 +259,8 @@ arabic_fallback_plan_init_win1256 (arabic_fallback_plan_t *fallback_plan HB_UNUS return false; const Manifest &manifest = reinterpret_cast<const Manifest&> (arabic_win1256_gsub_lookups.manifest); - static_assert (sizeof (arabic_win1256_gsub_lookups.manifestData) == + static_assert (sizeof (arabic_win1256_gsub_lookups.manifestData) <= ARABIC_FALLBACK_MAX_LOOKUPS * sizeof (ManifestLookup), ""); - /* TODO sanitize the table? */ unsigned j = 0; unsigned int count = manifest.len; @@ -264,7 +292,7 @@ arabic_fallback_plan_init_unicode (arabic_fallback_plan_t *fallback_plan, const hb_ot_shape_plan_t *plan, hb_font_t *font) { - static_assert ((ARRAY_LENGTH_CONST(arabic_fallback_features) <= ARABIC_FALLBACK_MAX_LOOKUPS), ""); + static_assert ((ARRAY_LENGTH_CONST (arabic_fallback_features) <= ARABIC_FALLBACK_MAX_LOOKUPS), ""); unsigned int j = 0; for (unsigned int i = 0; i < ARRAY_LENGTH(arabic_fallback_features) ; i++) { @@ -345,4 +373,4 @@ arabic_fallback_plan_shape (arabic_fallback_plan_t *fallback_plan, } -#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_FALLBACK_HH */ +#endif /* HB_OT_SHAPER_ARABIC_FALLBACK_HH */ diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic-joining-list.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-arabic-joining-list.hh index e6339ee72b..a5ce3a6c93 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic-joining-list.hh +++ b/thirdparty/harfbuzz/src/hb-ot-shaper-arabic-joining-list.hh @@ -12,8 +12,8 @@ * # Date: 2021-07-10, 00:35:31 GMT */ -#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_JOINING_LIST_HH -#define HB_OT_SHAPE_COMPLEX_ARABIC_JOINING_LIST_HH +#ifndef HB_OT_SHAPER_ARABIC_JOINING_LIST_HH +#define HB_OT_SHAPER_ARABIC_JOINING_LIST_HH static bool has_arabic_joining (hb_script_t script) @@ -42,6 +42,6 @@ has_arabic_joining (hb_script_t script) } -#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_JOINING_LIST_HH */ +#endif /* HB_OT_SHAPER_ARABIC_JOINING_LIST_HH */ /* == End of generated function == */ diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-arabic-pua.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-arabic-pua.hh new file mode 100644 index 0000000000..ba86772f84 --- /dev/null +++ b/thirdparty/harfbuzz/src/hb-ot-shaper-arabic-pua.hh @@ -0,0 +1,118 @@ +/* == Start of generated table == */ +/* + * The following table is generated by running: + * + * ./gen-arabic-pua.py + * + */ + +#ifndef HB_OT_SHAPER_ARABIC_PUA_HH +#define HB_OT_SHAPER_ARABIC_PUA_HH + +static const uint8_t +_hb_arabic_u8[464] = +{ + 84, 86, 85, 85, 85, 85, 85,213, 16, 34, 34, 34, 34, 34, 35, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 36, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 82, 16, 0, 0, 0, 0, 1, 2, 3, 4, + 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 7, + 0, 0, 8, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 0, 0, 0, 22, 0, 23, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 16, 34, 34, 34, 35, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 66, 16, 50, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68,101, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, + 71, 68, 68, 68, 68, 68, 68, 68,152,186, 76, 77, 68,254, 16, 50, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 0, 0, 5, 6, + 0, 0, 0, 0, 0, 0, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 10, 0, + 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 13, 0, 0, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 23, 23, 29, 30, 31, 32, 33, 0, 0, 0, 0, + 0, 0, 0, 34, 0, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 36, 37, 38, 0, 0, 0, 0, 0, 0, 0, 39, 0, 0, 40, + 41, 42, 0, 43, 44, 0, 0, 45, 46, 0, 47, 48, 49, 0, 0, 0, + 0, 50, 0, 0, 51, 52, 0, 53, 54, 55, 56, 57, 58, 0, 0, 0, + 0, 0, 59, 60, 61, 62, 63, 64, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 0, 66, + 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, + 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, +}; +static const uint16_t +_hb_arabic_u16[720] = +{ + 0, 0, 0, 0, 0, 0, 0, 0,61728,61729,61730, 0, 0,61733, 0, 0, + 61736,61737,61738,61739,61790,61741,61742,61743,61872,61873,61874,61875,61876,61877,61878,61879, + 61880,61881,61754,61755, 0,61757, 0,61759, 0, 0, 0,61787,61788,61789, 0, 0, + 0, 0, 0,61731, 0, 0, 0, 0, 0, 0, 0,61732, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0,61734, 0, 0, 0, 0, 0, 0, 0,61735, + 0, 0, 0, 0,61740, 0, 0, 0, 0, 0, 0,61755, 0, 0, 0,61759, + 0,61869,61765,61763,61883,61767,61882,61761,61770,61865,61772,61774,61777,61780,61783,61784, + 61785,61786,61792,61794,61796,61798,61800,61801,61802,61806,61810,61696,61696,61696,61696,61696, + 61791,61813,61816,61818,61820,61822,61921,61860,61861,61868,61864,61895,61896,61899,61892,61893, + 61898,61897,61894,61696,61696,61696,61696,61696,61696,61696,61696,61696,61696,61696,61696, 0, + 61744,61745,61746,61747,61748,61749,61750,61751,61752,61753, 0,61790,61790, 0, 0, 0, + 0, 0, 0, 0,61708,61709,61710,61711,61756,61758, 0, 0, 0, 0, 0, 0, + 0,61765,61766,61763,61764,61883,61883,61767,61768,61882,61871,61870,61870,61761,61762,61770, + 61770,61769,61769,61865,61866,61772,61772,61771,61771,61774,61774,61773,61773,61777,61776,61775, + 61775,61780,61779,61778,61778,61783,61782,61781,61781,61784,61784,61785,61785,61786,61786,61792, + 61792,61794,61794,61793,61793,61796,61796,61795,61795,61798,61798,61797,61797,61800,61800,61799, + 61799,61801,61801,61801,61801,61802,61802,61802,61802,61806,61805,61803,61804,61810,61809,61807, + 61808,61813,61813,61811,61812,61816,61816,61814,61815,61818,61818,61817,61817,61820,61820,61819, + 61819,61822,61822,61821,61821,61921,61921,61823,61823,61860,61859,61857,61858,61861,61861,61868, + 61867,61864,61863,61862,61862,61888,61889,61886,61887,61890,61891,61885,61884, 0, 0, 0, + 0, 0, 0, 0,61984,61985,61986, 0, 0,61989, 0, 0,61992,61993,61994,61995, + 62046,61997,61998,61999, 0, 0,62010,62011, 0,62013, 0,62015, 0, 0, 0,62043, + 0,62045, 0, 0, 0, 0, 0,61987, 0, 0, 0,61988, 0, 0, 0,61990, + 0, 0, 0,61991,61996, 0, 0, 0, 0, 0, 0,62011, 0, 0, 0,62015, + 0,62165,62021,62019,62170,62023,62169,62017,62028,62161,62032,62036,62040,62048,62052,62053, + 62055,62057,62059,62064,62068,62072,62078,62114,62115,62122,62126,61952,61952,61952,61952,61952, + 62047,62130,62134,62138,62142,62146,62150,62154,62155,62164,62160,62183,62184,62187,62180,62181, + 62186,62185,62182,61952,61952,61952,61952, 0,62000,62001,62002,62003,62004,62005,62006,62007, + 62008,62009, 0,62046,62046, 0, 0, 0,61964,61965,61966,61967,62012,62014, 0, 0, + 61954, 0,61981, 0, 0, 0,61955, 0,61982, 0,61956, 0, 0, 0,62111, 0, + 0, 0, 0,61970,61971,61972,61957, 0,61980, 0, 0, 0, 0, 0,61958, 0, + 61983, 0, 0, 0, 0, 0,62191, 0,62188,62189,62192, 0, 0, 0,61973, 0, + 0,62098, 0, 0,61974, 0, 0,62099, 0, 0,62101, 0, 0,61975, 0, 0, + 62100, 0, 0, 0,62080,62081,62082,62102, 0,62083,62084,62085,62103, 0, 0, 0, + 62106, 0,62107, 0,62108, 0, 0, 0,61976, 0, 0, 0, 0,62086,62087,62088, + 62109,61978,62089,62090,62091,62110,62093,62094, 0,62104, 0, 0, 0, 0,62095,62096, + 62097,62105, 0, 0,61977, 0, 0, 0, 0, 0,62075,62077,61968, 0, 0, 0, + 0,62021,62022,62019,62020,62170,62171,62023,62024,62169,62168,62166,62167,62017,62018,62028, + 62027,62025,62026,62161,62162,62032,62031,62029,62030,62036,62035,62033,62034,62040,62039,62037, + 62038,62048,62044,62041,62042,62052,62051,62049,62050,62053,62054,62055,62056,62057,62058,62059, + 62060,62064,62063,62061,62062,62068,62067,62065,62066,62072,62071,62069,62070,62078,62076,62073, + 62074,62114,62113,62079,62193,62118,62117,62115,62116,62122,62121,62119,62120,62126,62125,62123, + 62124,62130,62129,62127,62128,62134,62133,62131,62132,62138,62137,62135,62136,62142,62141,62139, + 62140,62146,62145,62143,62144,62150,62149,62147,62148,62154,62153,62151,62152,62155,62156,62164, + 62163,62160,62159,62157,62158,62176,62177,62174,62175,62178,62179,62172,62173, 0, 0, 0, +}; + +static inline unsigned +_hb_arabic_b2 (const uint8_t* a, unsigned i) +{ + return (a[i>>2]>>((i&3u)<<1))&3u; +} +static inline unsigned +_hb_arabic_b4 (const uint8_t* a, unsigned i) +{ + return (a[i>>1]>>((i&1u)<<2))&15u; +} +static inline uint_fast16_t +_hb_arabic_pua_simp_map (unsigned u) +{ + return u<65277u?_hb_arabic_u16[((_hb_arabic_u8[40+(((_hb_arabic_b4(8+_hb_arabic_u8,((_hb_arabic_b2(_hb_arabic_u8,u>>3>>4>>4))<<4)+((u>>3>>4)&15u)))<<4)+((u>>3)&15u))])<<3)+((u)&7u)]:0; +} +static inline uint_fast16_t +_hb_arabic_pua_trad_map (unsigned u) +{ + return u<65277u?_hb_arabic_u16[320+(((_hb_arabic_u8[208+(((_hb_arabic_b4(168+_hb_arabic_u8,((_hb_arabic_b4(136+_hb_arabic_u8,u>>2>>4>>4))<<4)+((u>>2>>4)&15u)))<<4)+((u>>2)&15u))])<<2)+((u)&3u))]:0; +} + +#endif /* HB_OT_SHAPER_ARABIC_PUA_HH */ + +/* == End of generated table == */ diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic-table.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-arabic-table.hh index c158964f2c..fd3d8645d1 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-shaper-arabic-table.hh @@ -13,8 +13,8 @@ * UnicodeData.txt does not have a header. */ -#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH -#define HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH +#ifndef HB_OT_SHAPER_ARABIC_TABLE_HH +#define HB_OT_SHAPER_ARABIC_TABLE_HH #define A JOINING_GROUP_ALAPH @@ -416,26 +416,141 @@ static const uint16_t shaping_table[][4] = static const struct ligature_set_t { uint16_t first; struct ligature_pairs_t { - uint16_t second; + uint16_t components[1]; uint16_t ligature; - } ligatures[4]; + } ligatures[14]; } ligature_table[] = { + { 0xFE91u, { + { {0xFEE2u}, 0xFC08u }, /* ARABIC LIGATURE BEH WITH MEEM ISOLATED FORM */ + { {0xFEE4u}, 0xFC9Fu }, /* ARABIC LIGATURE BEH WITH MEEM INITIAL FORM */ + { {0xFEA0u}, 0xFC9Cu }, /* ARABIC LIGATURE BEH WITH JEEM INITIAL FORM */ + { {0xFEA4u}, 0xFC9Du }, /* ARABIC LIGATURE BEH WITH HAH INITIAL FORM */ + { {0xFEA8u}, 0xFC9Eu }, /* ARABIC LIGATURE BEH WITH KHAH INITIAL FORM */ + }}, + { 0xFE92u, { + { {0xFEAEu}, 0xFC6Au }, /* ARABIC LIGATURE BEH WITH REH FINAL FORM */ + { {0xFEE6u}, 0xFC6Du }, /* ARABIC LIGATURE BEH WITH NOON FINAL FORM */ + { {0xFEF2u}, 0xFC6Fu }, /* ARABIC LIGATURE BEH WITH YEH FINAL FORM */ + }}, + { 0xFE97u, { + { {0xFEE2u}, 0xFC0Eu }, /* ARABIC LIGATURE TEH WITH MEEM ISOLATED FORM */ + { {0xFEE4u}, 0xFCA4u }, /* ARABIC LIGATURE TEH WITH MEEM INITIAL FORM */ + { {0xFEA0u}, 0xFCA1u }, /* ARABIC LIGATURE TEH WITH JEEM INITIAL FORM */ + { {0xFEA4u}, 0xFCA2u }, /* ARABIC LIGATURE TEH WITH HAH INITIAL FORM */ + { {0xFEA8u}, 0xFCA3u }, /* ARABIC LIGATURE TEH WITH KHAH INITIAL FORM */ + }}, + { 0xFE98u, { + { {0xFEAEu}, 0xFC70u }, /* ARABIC LIGATURE TEH WITH REH FINAL FORM */ + { {0xFEE6u}, 0xFC73u }, /* ARABIC LIGATURE TEH WITH NOON FINAL FORM */ + { {0xFEF2u}, 0xFC75u }, /* ARABIC LIGATURE TEH WITH YEH FINAL FORM */ + }}, + { 0xFE9Bu, { + { {0xFEE2u}, 0xFC12u }, /* ARABIC LIGATURE THEH WITH MEEM ISOLATED FORM */ + }}, + { 0xFE9Fu, { + { {0xFEE4u}, 0xFCA8u }, /* ARABIC LIGATURE JEEM WITH MEEM INITIAL FORM */ + }}, + { 0xFEA3u, { + { {0xFEE4u}, 0xFCAAu }, /* ARABIC LIGATURE HAH WITH MEEM INITIAL FORM */ + }}, + { 0xFEA7u, { + { {0xFEE4u}, 0xFCACu }, /* ARABIC LIGATURE KHAH WITH MEEM INITIAL FORM */ + }}, + { 0xFEB3u, { + { {0xFEE4u}, 0xFCB0u }, /* ARABIC LIGATURE SEEN WITH MEEM INITIAL FORM */ + }}, + { 0xFEB7u, { + { {0xFEE4u}, 0xFD30u }, /* ARABIC LIGATURE SHEEN WITH MEEM INITIAL FORM */ + }}, + { 0xFED3u, { + { {0xFEF2u}, 0xFC32u }, /* ARABIC LIGATURE FEH WITH YEH ISOLATED FORM */ + }}, { 0xFEDFu, { - { 0xFE82u, 0xFEF5u }, /* ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM */ - { 0xFE84u, 0xFEF7u }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM */ - { 0xFE88u, 0xFEF9u }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM */ - { 0xFE8Eu, 0xFEFBu }, /* ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM */ + { {0xFE9Eu}, 0xFC3Fu }, /* ARABIC LIGATURE LAM WITH JEEM ISOLATED FORM */ + { {0xFEA0u}, 0xFCC9u }, /* ARABIC LIGATURE LAM WITH JEEM INITIAL FORM */ + { {0xFEA2u}, 0xFC40u }, /* ARABIC LIGATURE LAM WITH HAH ISOLATED FORM */ + { {0xFEA4u}, 0xFCCAu }, /* ARABIC LIGATURE LAM WITH HAH INITIAL FORM */ + { {0xFEA6u}, 0xFC41u }, /* ARABIC LIGATURE LAM WITH KHAH ISOLATED FORM */ + { {0xFEA8u}, 0xFCCBu }, /* ARABIC LIGATURE LAM WITH KHAH INITIAL FORM */ + { {0xFEE2u}, 0xFC42u }, /* ARABIC LIGATURE LAM WITH MEEM ISOLATED FORM */ + { {0xFEE4u}, 0xFCCCu }, /* ARABIC LIGATURE LAM WITH MEEM INITIAL FORM */ + { {0xFEF2u}, 0xFC44u }, /* ARABIC LIGATURE LAM WITH YEH ISOLATED FORM */ + { {0xFEECu}, 0xFCCDu }, /* ARABIC LIGATURE LAM WITH HEH INITIAL FORM */ + { {0xFE82u}, 0xFEF5u }, /* ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM */ + { {0xFE84u}, 0xFEF7u }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM */ + { {0xFE88u}, 0xFEF9u }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM */ + { {0xFE8Eu}, 0xFEFBu }, /* ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM */ }}, { 0xFEE0u, { - { 0xFE82u, 0xFEF6u }, /* ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM */ - { 0xFE84u, 0xFEF8u }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORM */ - { 0xFE88u, 0xFEFAu }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW FINAL FORM */ - { 0xFE8Eu, 0xFEFCu }, /* ARABIC LIGATURE LAM WITH ALEF FINAL FORM */ + { {0xFEF0u}, 0xFC86u }, /* ARABIC LIGATURE LAM WITH ALEF MAKSURA FINAL FORM */ + { {0xFE82u}, 0xFEF6u }, /* ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM */ + { {0xFE84u}, 0xFEF8u }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORM */ + { {0xFE88u}, 0xFEFAu }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW FINAL FORM */ + { {0xFE8Eu}, 0xFEFCu }, /* ARABIC LIGATURE LAM WITH ALEF FINAL FORM */ + }}, + { 0xFEE3u, { + { {0xFEA0u}, 0xFCCEu }, /* ARABIC LIGATURE MEEM WITH JEEM INITIAL FORM */ + { {0xFEA4u}, 0xFCCFu }, /* ARABIC LIGATURE MEEM WITH HAH INITIAL FORM */ + { {0xFEA8u}, 0xFCD0u }, /* ARABIC LIGATURE MEEM WITH KHAH INITIAL FORM */ + { {0xFEE4u}, 0xFCD1u }, /* ARABIC LIGATURE MEEM WITH MEEM INITIAL FORM */ + }}, + { 0xFEE7u, { + { {0xFEE2u}, 0xFC4Eu }, /* ARABIC LIGATURE NOON WITH MEEM ISOLATED FORM */ + { {0xFEE4u}, 0xFCD5u }, /* ARABIC LIGATURE NOON WITH MEEM INITIAL FORM */ + { {0xFEA0u}, 0xFCD2u }, /* ARABIC LIGATURE NOON WITH JEEM INITIAL FORM */ + { {0xFEA4u}, 0xFCD3u }, /* ARABIC LIGATURE NOON WITH HAH INITIAL FORM */ + }}, + { 0xFEE8u, { + { {0xFEF2u}, 0xFC8Fu }, /* ARABIC LIGATURE NOON WITH YEH FINAL FORM */ + }}, + { 0xFEF3u, { + { {0xFEA0u}, 0xFCDAu }, /* ARABIC LIGATURE YEH WITH JEEM INITIAL FORM */ + { {0xFEA4u}, 0xFCDBu }, /* ARABIC LIGATURE YEH WITH HAH INITIAL FORM */ + { {0xFEA8u}, 0xFCDCu }, /* ARABIC LIGATURE YEH WITH KHAH INITIAL FORM */ + { {0xFEE4u}, 0xFCDDu }, /* ARABIC LIGATURE YEH WITH MEEM INITIAL FORM */ + }}, + { 0xFEF4u, { + { {0xFEAEu}, 0xFC91u }, /* ARABIC LIGATURE YEH WITH REH FINAL FORM */ + { {0xFEE6u}, 0xFC94u }, /* ARABIC LIGATURE YEH WITH NOON FINAL FORM */ + }}, +}; + + +static const struct ligature_mark_set_t { + uint16_t first; + struct ligature_pairs_t { + uint16_t components[1]; + uint16_t ligature; + } ligatures[5]; +} ligature_mark_table[] = +{ + { 0x0651u, { + { {0x064Cu}, 0xFC5Eu }, /* ARABIC LIGATURE SHADDA WITH DAMMATAN ISOLATED FORM */ + { {0x064Eu}, 0xFC60u }, /* ARABIC LIGATURE SHADDA WITH FATHA ISOLATED FORM */ + { {0x064Fu}, 0xFC61u }, /* ARABIC LIGATURE SHADDA WITH DAMMA ISOLATED FORM */ + { {0x0650u}, 0xFC62u }, /* ARABIC LIGATURE SHADDA WITH KASRA ISOLATED FORM */ + { {0x064Bu}, 0xF2EEu }, /* PUA ARABIC LIGATURE SHADDA WITH FATHATAN ISOLATED FORM */ + }}, +}; + + +static const struct ligature_3_set_t { + uint16_t first; + struct ligature_triplets_t { + uint16_t components[2]; + uint16_t ligature; + } ligatures[3]; +} ligature_3_table[] = +{ + { 0xFEDFu, { + { {0xFEE4u, 0xFEA4u}, 0xFD88u}, /* ARABIC LIGATURE LAM WITH MEEM WITH HAH INITIAL FORM */ + { {0xFEE0u, 0xFEEAu}, 0xF201u}, /* PUA ARABIC LIGATURE LELLAH ISOLATED FORM */ + { {0xFEE4u, 0xFEA0u}, 0xF211u}, /* PUA ARABIC LIGATURE LAM WITH MEEM WITH JEEM INITIAL FORM */ }}, }; -#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH */ +#endif /* HB_OT_SHAPER_ARABIC_TABLE_HH */ /* == End of generated table == */ diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic-win1256.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-arabic-win1256.hh index 429974d05b..b8d481c813 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic-win1256.hh +++ b/thirdparty/harfbuzz/src/hb-ot-shaper-arabic-win1256.hh @@ -24,7 +24,7 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_WIN1256_HH +#ifndef HB_OT_SHAPER_ARABIC_WIN1256_HH /* @@ -342,8 +342,8 @@ OT_TABLE_END #include "hb.hh" /* Make check-includes.sh happy. */ #endif #ifdef OT_MEASURE -#include "hb-ot-shape-complex-arabic-win1256.hh" +#include "hb-ot-shaper-arabic-win1256.hh" #endif -#define HB_OT_SHAPE_COMPLEX_ARABIC_WIN1256_HH -#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_WIN1256_HH */ +#define HB_OT_SHAPER_ARABIC_WIN1256_HH +#endif /* HB_OT_SHAPER_ARABIC_WIN1256_HH */ diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic.cc b/thirdparty/harfbuzz/src/hb-ot-shaper-arabic.cc index 224f8b842e..e869d78509 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic.cc +++ b/thirdparty/harfbuzz/src/hb-ot-shaper-arabic.cc @@ -28,14 +28,14 @@ #ifndef HB_NO_OT_SHAPE -#include "hb-ot-shape-complex-arabic.hh" +#include "hb-ot-shaper-arabic.hh" #include "hb-ot-shape.hh" /* buffer var allocations */ -#define arabic_shaping_action() complex_var_u8_auxiliary() /* arabic shaping action */ +#define arabic_shaping_action() ot_shaper_var_u8_auxiliary() /* arabic shaping action */ -#define HB_BUFFER_SCRATCH_FLAG_ARABIC_HAS_STCH HB_BUFFER_SCRATCH_FLAG_COMPLEX0 +#define HB_BUFFER_SCRATCH_FLAG_ARABIC_HAS_STCH HB_BUFFER_SCRATCH_FLAG_SHAPER0 /* See: * https://github.com/harfbuzz/harfbuzz/commit/6e6f82b6f3dde0fc6c3c7d991d9ec6cfff57823d#commitcomment-14248516 */ @@ -81,7 +81,7 @@ enum hb_arabic_joining_type_t { JOINING_TYPE_X = 8 /* means: use general-category to choose between U or T. */ }; -#include "hb-ot-shape-complex-arabic-table.hh" +#include "hb-ot-shaper-arabic-table.hh" static unsigned int get_joining_type (hb_codepoint_t u, hb_unicode_general_category_t gen_cat) { @@ -172,6 +172,14 @@ record_stch (const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer); static void +deallocate_buffer_var (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer) +{ + HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action); +} + +static void collect_features_arabic (hb_ot_shape_planner_t *plan) { hb_ot_map_builder_t *map = &plan->map; @@ -213,6 +221,7 @@ collect_features_arabic (hb_ot_shape_planner_t *plan) map->add_feature (arabic_features[i], has_fallback ? F_HAS_FALLBACK : F_NONE); map->add_gsub_pause (nullptr); } + map->add_gsub_pause (deallocate_buffer_var); /* Normally, Unicode says a ZWNJ means "don't ligate". In Arabic script * however, it says a ZWJ should also mean "don't ligate". So we run @@ -240,7 +249,7 @@ collect_features_arabic (hb_ot_shape_planner_t *plan) map->enable_feature (HB_TAG('m','s','e','t')); } -#include "hb-ot-shape-complex-arabic-fallback.hh" +#include "hb-ot-shaper-arabic-fallback.hh" struct arabic_shape_plan_t { @@ -405,7 +414,7 @@ arabic_fallback_shape (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) { -#ifdef HB_NO_OT_SHAPE_COMPLEX_ARABIC_FALLBACK +#ifdef HB_NO_OT_SHAPER_ARABIC_FALLBACK return; #endif @@ -619,8 +628,6 @@ postprocess_glyphs_arabic (const hb_ot_shape_plan_t *plan, hb_font_t *font) { apply_stch (plan, buffer, font); - - HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action); } /* https://www.unicode.org/reports/tr53/ */ @@ -689,7 +696,7 @@ reorder_marks_arabic (const hb_ot_shape_plan_t *plan HB_UNUSED, /* Shift it! */ DEBUG_MSG (ARABIC, buffer, "Shifting %d's: %d %d", cc, i, j); - hb_glyph_info_t temp[HB_OT_SHAPE_COMPLEX_MAX_COMBINING_MARKS]; + hb_glyph_info_t temp[HB_OT_SHAPE_MAX_COMBINING_MARKS]; assert (j - i <= ARRAY_LENGTH (temp)); buffer->merge_clusters (start, j); memmove (temp, &info[i], (j - i) * sizeof (hb_glyph_info_t)); @@ -720,7 +727,7 @@ reorder_marks_arabic (const hb_ot_shape_plan_t *plan HB_UNUSED, } } -const hb_ot_complex_shaper_t _hb_ot_complex_shaper_arabic = +const hb_ot_shaper_t _hb_ot_shaper_arabic = { collect_features_arabic, nullptr, /* override_features */ diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-arabic.hh index 5bf6ff6338..a025b1a399 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic.hh +++ b/thirdparty/harfbuzz/src/hb-ot-shaper-arabic.hh @@ -26,12 +26,12 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_HH -#define HB_OT_SHAPE_COMPLEX_ARABIC_HH +#ifndef HB_OT_SHAPER_ARABIC_HH +#define HB_OT_SHAPER_ARABIC_HH #include "hb.hh" -#include "hb-ot-shape-complex.hh" +#include "hb-ot-shaper.hh" struct arabic_shape_plan_t; @@ -47,4 +47,4 @@ setup_masks_arabic_plan (const arabic_shape_plan_t *arabic_plan, hb_buffer_t *buffer, hb_script_t script); -#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_HH */ +#endif /* HB_OT_SHAPER_ARABIC_HH */ diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-default.cc b/thirdparty/harfbuzz/src/hb-ot-shaper-default.cc index a755aea098..25716aa81f 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-default.cc +++ b/thirdparty/harfbuzz/src/hb-ot-shaper-default.cc @@ -28,10 +28,10 @@ #ifndef HB_NO_OT_SHAPE -#include "hb-ot-shape-complex.hh" +#include "hb-ot-shaper.hh" -const hb_ot_complex_shaper_t _hb_ot_complex_shaper_default = +const hb_ot_shaper_t _hb_ot_shaper_default = { nullptr, /* collect_features */ nullptr, /* override_features */ @@ -51,7 +51,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_default = /* Same as default but no mark advance zeroing / fallback positioning. * Dumbest shaper ever, basically. */ -const hb_ot_complex_shaper_t _hb_ot_complex_shaper_dumber = +const hb_ot_shaper_t _hb_ot_shaper_dumber = { nullptr, /* collect_features */ nullptr, /* override_features */ diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-hangul.cc b/thirdparty/harfbuzz/src/hb-ot-shaper-hangul.cc index 3bc9e9b961..aa507c75ca 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-hangul.cc +++ b/thirdparty/harfbuzz/src/hb-ot-shaper-hangul.cc @@ -28,7 +28,7 @@ #ifndef HB_NO_OT_SHAPE -#include "hb-ot-shape-complex.hh" +#include "hb-ot-shaper.hh" /* Hangul shaper */ @@ -119,7 +119,7 @@ data_destroy_hangul (void *data) #define isHangulTone(u) (hb_in_range<hb_codepoint_t> ((u), 0x302Eu, 0x302Fu)) /* buffer var allocations */ -#define hangul_shaping_feature() complex_var_u8_auxiliary() /* hangul jamo shaping feature */ +#define hangul_shaping_feature() ot_shaper_var_u8_auxiliary() /* hangul jamo shaping feature */ static bool is_zero_width_char (hb_font_t *font, @@ -414,7 +414,7 @@ setup_masks_hangul (const hb_ot_shape_plan_t *plan, } -const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hangul = +const hb_ot_shaper_t _hb_ot_shaper_hangul = { collect_features_hangul, override_features_hangul, diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-hebrew.cc b/thirdparty/harfbuzz/src/hb-ot-shaper-hebrew.cc index 334d3ded82..f3b6cde179 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-hebrew.cc +++ b/thirdparty/harfbuzz/src/hb-ot-shaper-hebrew.cc @@ -28,7 +28,7 @@ #ifndef HB_NO_OT_SHAPE -#include "hb-ot-shape-complex.hh" +#include "hb-ot-shaper.hh" static bool @@ -74,7 +74,7 @@ compose_hebrew (const hb_ot_shape_normalize_context_t *c, bool found = (bool) c->unicode->compose (a, b, ab); -#ifdef HB_NO_OT_SHAPE_COMPLEX_HEBREW_FALLBACK +#ifdef HB_NO_OT_SHAPER_HEBREW_FALLBACK return found; #endif @@ -163,7 +163,7 @@ compose_hebrew (const hb_ot_shape_normalize_context_t *c, } -const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hebrew = +const hb_ot_shaper_t _hb_ot_shaper_hebrew = { nullptr, /* collect_features */ nullptr, /* override_features */ diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-indic-machine.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-indic-machine.hh new file mode 100644 index 0000000000..d52b13f616 --- /dev/null +++ b/thirdparty/harfbuzz/src/hb-ot-shaper-indic-machine.hh @@ -0,0 +1,589 @@ + +#line 1 "hb-ot-shaper-indic-machine.rl" +/* + * Copyright © 2011,2012 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_OT_SHAPER_INDIC_MACHINE_HH +#define HB_OT_SHAPER_INDIC_MACHINE_HH + +#include "hb.hh" + +#include "hb-ot-layout.hh" +#include "hb-ot-shaper-indic.hh" + +/* buffer var allocations */ +#define indic_category() ot_shaper_var_u8_category() /* indic_category_t */ +#define indic_position() ot_shaper_var_u8_auxiliary() /* indic_position_t */ + +using indic_category_t = unsigned; +using indic_position_t = ot_position_t; + +#define I_Cat(Cat) indic_syllable_machine_ex_##Cat + +enum indic_syllable_type_t { + indic_consonant_syllable, + indic_vowel_syllable, + indic_standalone_cluster, + indic_symbol_cluster, + indic_broken_cluster, + indic_non_indic_cluster, +}; + + +#line 57 "hb-ot-shaper-indic-machine.hh" +#define indic_syllable_machine_ex_A 9u +#define indic_syllable_machine_ex_C 1u +#define indic_syllable_machine_ex_CM 16u +#define indic_syllable_machine_ex_CS 18u +#define indic_syllable_machine_ex_DOTTEDCIRCLE 11u +#define indic_syllable_machine_ex_H 4u +#define indic_syllable_machine_ex_M 7u +#define indic_syllable_machine_ex_N 3u +#define indic_syllable_machine_ex_PLACEHOLDER 10u +#define indic_syllable_machine_ex_RS 12u +#define indic_syllable_machine_ex_Ra 15u +#define indic_syllable_machine_ex_Repha 14u +#define indic_syllable_machine_ex_SM 8u +#define indic_syllable_machine_ex_Symbol 17u +#define indic_syllable_machine_ex_V 2u +#define indic_syllable_machine_ex_VD 9u +#define indic_syllable_machine_ex_X 0u +#define indic_syllable_machine_ex_ZWJ 6u +#define indic_syllable_machine_ex_ZWNJ 5u + + +#line 79 "hb-ot-shaper-indic-machine.hh" +static const unsigned char _indic_syllable_machine_trans_keys[] = { + 8u, 8u, 4u, 8u, 5u, 7u, 5u, 8u, 4u, 8u, 4u, 12u, 4u, 8u, 8u, 8u, + 5u, 7u, 5u, 8u, 4u, 8u, 4u, 12u, 4u, 12u, 4u, 12u, 8u, 8u, 5u, 7u, + 5u, 8u, 4u, 8u, 4u, 8u, 4u, 12u, 8u, 8u, 5u, 7u, 5u, 8u, 4u, 8u, + 4u, 8u, 5u, 8u, 8u, 8u, 1u, 18u, 3u, 16u, 3u, 16u, 4u, 16u, 1u, 15u, + 5u, 9u, 5u, 9u, 9u, 9u, 5u, 9u, 1u, 15u, 1u, 15u, 1u, 15u, 3u, 9u, + 4u, 9u, 5u, 9u, 4u, 9u, 5u, 9u, 3u, 9u, 5u, 9u, 3u, 16u, 3u, 16u, + 3u, 16u, 3u, 16u, 4u, 16u, 1u, 15u, 3u, 16u, 3u, 16u, 4u, 16u, 1u, 15u, + 5u, 9u, 9u, 9u, 5u, 9u, 1u, 15u, 1u, 15u, 3u, 9u, 4u, 9u, 5u, 9u, + 4u, 9u, 5u, 9u, 5u, 9u, 3u, 9u, 5u, 9u, 3u, 16u, 3u, 16u, 4u, 8u, + 3u, 16u, 3u, 16u, 4u, 16u, 1u, 15u, 3u, 16u, 1u, 15u, 5u, 9u, 9u, 9u, + 5u, 9u, 1u, 15u, 1u, 15u, 3u, 9u, 4u, 9u, 5u, 9u, 3u, 16u, 4u, 9u, + 5u, 9u, 5u, 9u, 3u, 9u, 5u, 9u, 3u, 16u, 4u, 12u, 4u, 8u, 3u, 16u, + 3u, 16u, 4u, 16u, 1u, 15u, 3u, 16u, 1u, 15u, 5u, 9u, 9u, 9u, 5u, 9u, + 1u, 15u, 1u, 15u, 3u, 9u, 4u, 9u, 5u, 9u, 3u, 16u, 4u, 9u, 5u, 9u, + 5u, 9u, 3u, 9u, 5u, 9u, 1u, 16u, 3u, 16u, 1u, 16u, 4u, 12u, 5u, 9u, + 9u, 9u, 5u, 9u, 1u, 15u, 3u, 9u, 5u, 9u, 5u, 9u, 9u, 9u, 5u, 9u, + 1u, 15u, 0 +}; + +static const char _indic_syllable_machine_key_spans[] = { + 1, 5, 3, 4, 5, 9, 5, 1, + 3, 4, 5, 9, 9, 9, 1, 3, + 4, 5, 5, 9, 1, 3, 4, 5, + 5, 4, 1, 18, 14, 14, 13, 15, + 5, 5, 1, 5, 15, 15, 15, 7, + 6, 5, 6, 5, 7, 5, 14, 14, + 14, 14, 13, 15, 14, 14, 13, 15, + 5, 1, 5, 15, 15, 7, 6, 5, + 6, 5, 5, 7, 5, 14, 14, 5, + 14, 14, 13, 15, 14, 15, 5, 1, + 5, 15, 15, 7, 6, 5, 14, 6, + 5, 5, 7, 5, 14, 9, 5, 14, + 14, 13, 15, 14, 15, 5, 1, 5, + 15, 15, 7, 6, 5, 14, 6, 5, + 5, 7, 5, 16, 14, 16, 9, 5, + 1, 5, 15, 7, 5, 5, 1, 5, + 15 +}; + +static const short _indic_syllable_machine_index_offsets[] = { + 0, 2, 8, 12, 17, 23, 33, 39, + 41, 45, 50, 56, 66, 76, 86, 88, + 92, 97, 103, 109, 119, 121, 125, 130, + 136, 142, 147, 149, 168, 183, 198, 212, + 228, 234, 240, 242, 248, 264, 280, 296, + 304, 311, 317, 324, 330, 338, 344, 359, + 374, 389, 404, 418, 434, 449, 464, 478, + 494, 500, 502, 508, 524, 540, 548, 555, + 561, 568, 574, 580, 588, 594, 609, 624, + 630, 645, 660, 674, 690, 705, 721, 727, + 729, 735, 751, 767, 775, 782, 788, 803, + 810, 816, 822, 830, 836, 851, 861, 867, + 882, 897, 911, 927, 942, 958, 964, 966, + 972, 988, 1004, 1012, 1019, 1025, 1040, 1047, + 1053, 1059, 1067, 1073, 1090, 1105, 1122, 1132, + 1138, 1140, 1146, 1162, 1170, 1176, 1182, 1184, + 1190 +}; + +static const unsigned char _indic_syllable_machine_indicies[] = { + 1, 0, 2, 3, 3, 4, 1, 0, + 3, 3, 4, 0, 3, 3, 4, 1, + 0, 5, 3, 3, 4, 1, 0, 2, + 3, 3, 4, 1, 0, 0, 0, 6, + 0, 8, 9, 9, 10, 11, 7, 11, + 7, 9, 9, 10, 7, 9, 9, 10, + 11, 7, 12, 9, 9, 10, 11, 7, + 8, 9, 9, 10, 11, 7, 7, 7, + 13, 7, 8, 9, 9, 10, 11, 7, + 7, 7, 14, 7, 16, 17, 17, 18, + 19, 15, 15, 15, 20, 15, 19, 15, + 17, 17, 18, 21, 17, 17, 18, 19, + 15, 16, 17, 17, 18, 19, 15, 22, + 17, 17, 18, 19, 15, 24, 25, 25, + 26, 27, 23, 23, 23, 28, 23, 27, + 23, 25, 25, 26, 23, 25, 25, 26, + 27, 23, 24, 25, 25, 26, 27, 23, + 29, 25, 25, 26, 27, 23, 17, 17, + 18, 1, 0, 31, 30, 33, 34, 35, + 36, 37, 38, 18, 19, 39, 40, 40, + 20, 32, 41, 42, 43, 44, 45, 32, + 47, 48, 49, 50, 4, 1, 51, 46, + 46, 6, 46, 46, 46, 52, 46, 53, + 48, 54, 54, 4, 1, 51, 46, 46, + 46, 46, 46, 46, 52, 46, 48, 54, + 54, 4, 1, 51, 46, 46, 46, 46, + 46, 46, 52, 46, 33, 46, 46, 46, + 55, 56, 46, 1, 51, 46, 46, 46, + 46, 46, 33, 46, 57, 57, 46, 1, + 51, 46, 51, 46, 46, 58, 51, 46, + 51, 46, 51, 46, 46, 46, 51, 46, + 33, 46, 59, 46, 57, 57, 46, 1, + 51, 46, 46, 46, 46, 46, 33, 46, + 33, 46, 46, 46, 57, 57, 46, 1, + 51, 46, 46, 46, 46, 46, 33, 46, + 33, 46, 46, 46, 57, 56, 46, 1, + 51, 46, 46, 46, 46, 46, 33, 46, + 60, 61, 62, 62, 4, 1, 51, 46, + 61, 62, 62, 4, 1, 51, 46, 62, + 62, 4, 1, 51, 46, 63, 64, 64, + 4, 1, 51, 46, 55, 65, 46, 1, + 51, 46, 55, 46, 57, 57, 46, 1, + 51, 46, 57, 65, 46, 1, 51, 46, + 47, 48, 54, 54, 4, 1, 51, 46, + 46, 46, 46, 46, 46, 52, 46, 47, + 48, 49, 54, 4, 1, 51, 46, 46, + 6, 46, 46, 46, 52, 46, 67, 68, + 69, 70, 10, 11, 71, 66, 66, 14, + 66, 66, 66, 72, 66, 73, 68, 74, + 70, 10, 11, 71, 66, 66, 66, 66, + 66, 66, 72, 66, 68, 74, 70, 10, + 11, 71, 66, 66, 66, 66, 66, 66, + 72, 66, 75, 66, 66, 66, 76, 77, + 66, 11, 71, 66, 66, 66, 66, 66, + 75, 66, 78, 68, 79, 80, 10, 11, + 71, 66, 66, 13, 66, 66, 66, 72, + 66, 81, 68, 74, 74, 10, 11, 71, + 66, 66, 66, 66, 66, 66, 72, 66, + 68, 74, 74, 10, 11, 71, 66, 66, + 66, 66, 66, 66, 72, 66, 75, 66, + 66, 66, 82, 77, 66, 11, 71, 66, + 66, 66, 66, 66, 75, 66, 71, 66, + 66, 83, 71, 66, 71, 66, 71, 66, + 66, 66, 71, 66, 75, 66, 84, 66, + 82, 82, 66, 11, 71, 66, 66, 66, + 66, 66, 75, 66, 75, 66, 66, 66, + 82, 82, 66, 11, 71, 66, 66, 66, + 66, 66, 75, 66, 85, 86, 87, 87, + 10, 11, 71, 66, 86, 87, 87, 10, + 11, 71, 66, 87, 87, 10, 11, 71, + 66, 88, 89, 89, 10, 11, 71, 66, + 76, 90, 66, 11, 71, 66, 82, 82, + 66, 11, 71, 66, 76, 66, 82, 82, + 66, 11, 71, 66, 82, 90, 66, 11, + 71, 66, 78, 68, 74, 74, 10, 11, + 71, 66, 66, 66, 66, 66, 66, 72, + 66, 78, 68, 79, 74, 10, 11, 71, + 66, 66, 13, 66, 66, 66, 72, 66, + 8, 9, 9, 10, 11, 66, 67, 68, + 74, 70, 10, 11, 71, 66, 66, 66, + 66, 66, 66, 72, 66, 92, 36, 93, + 93, 18, 19, 39, 91, 91, 91, 91, + 91, 91, 43, 91, 36, 93, 93, 18, + 19, 39, 91, 91, 91, 91, 91, 91, + 43, 91, 94, 91, 91, 91, 95, 96, + 91, 19, 39, 91, 91, 91, 91, 91, + 94, 91, 35, 36, 97, 98, 18, 19, + 39, 91, 91, 20, 91, 91, 91, 43, + 91, 94, 91, 91, 91, 99, 96, 91, + 19, 39, 91, 91, 91, 91, 91, 94, + 91, 39, 91, 91, 100, 39, 91, 39, + 91, 39, 91, 91, 91, 39, 91, 94, + 91, 101, 91, 99, 99, 91, 19, 39, + 91, 91, 91, 91, 91, 94, 91, 94, + 91, 91, 91, 99, 99, 91, 19, 39, + 91, 91, 91, 91, 91, 94, 91, 102, + 103, 104, 104, 18, 19, 39, 91, 103, + 104, 104, 18, 19, 39, 91, 104, 104, + 18, 19, 39, 91, 35, 36, 93, 93, + 18, 19, 39, 91, 91, 91, 91, 91, + 91, 43, 91, 105, 106, 106, 18, 19, + 39, 91, 95, 107, 91, 19, 39, 91, + 99, 99, 91, 19, 39, 91, 95, 91, + 99, 99, 91, 19, 39, 91, 99, 107, + 91, 19, 39, 91, 35, 36, 97, 93, + 18, 19, 39, 91, 91, 20, 91, 91, + 91, 43, 91, 16, 17, 17, 18, 19, + 108, 108, 108, 20, 108, 16, 17, 17, + 18, 19, 108, 110, 111, 112, 113, 26, + 27, 114, 109, 109, 28, 109, 109, 109, + 115, 109, 116, 111, 113, 113, 26, 27, + 114, 109, 109, 109, 109, 109, 109, 115, + 109, 111, 113, 113, 26, 27, 114, 109, + 109, 109, 109, 109, 109, 115, 109, 117, + 109, 109, 109, 118, 119, 109, 27, 114, + 109, 109, 109, 109, 109, 117, 109, 110, + 111, 112, 40, 26, 27, 114, 109, 109, + 28, 109, 109, 109, 115, 109, 117, 109, + 109, 109, 120, 119, 109, 27, 114, 109, + 109, 109, 109, 109, 117, 109, 114, 109, + 109, 121, 114, 109, 114, 109, 114, 109, + 109, 109, 114, 109, 117, 109, 122, 109, + 120, 120, 109, 27, 114, 109, 109, 109, + 109, 109, 117, 109, 117, 109, 109, 109, + 120, 120, 109, 27, 114, 109, 109, 109, + 109, 109, 117, 109, 123, 124, 125, 125, + 26, 27, 114, 109, 124, 125, 125, 26, + 27, 114, 109, 125, 125, 26, 27, 114, + 109, 110, 111, 113, 113, 26, 27, 114, + 109, 109, 109, 109, 109, 109, 115, 109, + 126, 127, 127, 26, 27, 114, 109, 118, + 128, 109, 27, 114, 109, 120, 120, 109, + 27, 114, 109, 118, 109, 120, 120, 109, + 27, 114, 109, 120, 128, 109, 27, 114, + 109, 33, 34, 35, 36, 97, 93, 18, + 19, 39, 40, 40, 20, 91, 91, 33, + 43, 91, 47, 129, 49, 50, 4, 1, + 51, 46, 46, 6, 46, 46, 46, 52, + 46, 33, 34, 35, 36, 130, 131, 18, + 132, 133, 46, 40, 20, 46, 46, 33, + 43, 46, 16, 134, 134, 18, 132, 51, + 46, 46, 20, 46, 133, 46, 46, 135, + 133, 46, 133, 46, 133, 46, 46, 46, + 133, 46, 33, 46, 59, 16, 134, 134, + 18, 132, 51, 46, 46, 46, 46, 46, + 33, 46, 137, 136, 138, 138, 136, 31, + 139, 136, 138, 138, 136, 31, 139, 136, + 139, 136, 136, 140, 139, 136, 139, 136, + 139, 136, 136, 136, 139, 136, 33, 108, + 108, 108, 108, 108, 108, 108, 108, 40, + 108, 108, 108, 108, 33, 108, 0 +}; + +static const unsigned char _indic_syllable_machine_trans_targs[] = { + 27, 33, 38, 2, 39, 45, 46, 27, + 55, 8, 61, 56, 68, 69, 72, 27, + 77, 15, 83, 78, 86, 27, 91, 27, + 100, 21, 106, 101, 109, 114, 27, 125, + 27, 28, 48, 73, 75, 93, 94, 79, + 95, 115, 116, 87, 123, 128, 27, 29, + 31, 5, 47, 34, 42, 30, 1, 32, + 36, 0, 35, 37, 40, 41, 3, 43, + 4, 44, 27, 49, 51, 12, 71, 57, + 64, 50, 6, 52, 66, 59, 53, 11, + 70, 54, 7, 58, 60, 62, 63, 9, + 65, 10, 67, 27, 74, 17, 76, 89, + 81, 13, 92, 14, 80, 82, 84, 85, + 16, 88, 18, 90, 27, 27, 96, 98, + 19, 23, 102, 110, 97, 99, 112, 104, + 20, 103, 105, 107, 108, 22, 111, 24, + 113, 117, 118, 122, 119, 120, 25, 121, + 27, 124, 26, 126, 127 +}; + +static const char _indic_syllable_machine_trans_actions[] = { + 1, 0, 2, 0, 2, 2, 2, 3, + 2, 0, 2, 0, 2, 2, 2, 4, + 2, 0, 5, 0, 5, 6, 2, 7, + 2, 0, 2, 0, 2, 2, 8, 0, + 11, 2, 2, 5, 0, 12, 12, 0, + 2, 5, 2, 5, 2, 0, 13, 2, + 0, 0, 2, 0, 2, 2, 0, 2, + 2, 0, 0, 2, 2, 2, 0, 0, + 0, 2, 14, 2, 0, 0, 2, 0, + 2, 2, 0, 2, 2, 2, 2, 0, + 2, 2, 0, 0, 2, 2, 2, 0, + 0, 0, 2, 15, 5, 0, 5, 2, + 2, 0, 5, 0, 0, 2, 5, 5, + 0, 0, 0, 2, 16, 17, 2, 0, + 0, 0, 0, 2, 2, 2, 2, 2, + 0, 0, 2, 2, 2, 0, 0, 0, + 2, 0, 18, 18, 0, 0, 0, 0, + 19, 2, 0, 0, 0 +}; + +static const char _indic_syllable_machine_to_state_actions[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 9, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0 +}; + +static const char _indic_syllable_machine_from_state_actions[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 10, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0 +}; + +static const short _indic_syllable_machine_eof_trans[] = { + 1, 1, 1, 1, 1, 1, 8, 8, + 8, 8, 8, 8, 8, 16, 16, 22, + 16, 16, 16, 24, 24, 24, 24, 24, + 24, 1, 31, 0, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, + 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, + 67, 92, 92, 92, 92, 92, 92, 92, + 92, 92, 92, 92, 92, 92, 92, 92, + 92, 92, 92, 92, 92, 109, 109, 110, + 110, 110, 110, 110, 110, 110, 110, 110, + 110, 110, 110, 110, 110, 110, 110, 110, + 110, 110, 110, 92, 47, 47, 47, 47, + 47, 47, 47, 137, 137, 137, 137, 137, + 109 +}; + +static const int indic_syllable_machine_start = 27; +static const int indic_syllable_machine_first_final = 27; +static const int indic_syllable_machine_error = -1; + +static const int indic_syllable_machine_en_main = 27; + + +#line 58 "hb-ot-shaper-indic-machine.rl" + + + +#line 117 "hb-ot-shaper-indic-machine.rl" + + +#define found_syllable(syllable_type) \ + HB_STMT_START { \ + if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \ + for (unsigned int i = ts; i < te; i++) \ + info[i].syllable() = (syllable_serial << 4) | syllable_type; \ + syllable_serial++; \ + if (unlikely (syllable_serial == 16)) syllable_serial = 1; \ + } HB_STMT_END + +inline void +find_syllables_indic (hb_buffer_t *buffer) +{ + unsigned int p, pe, eof, ts, te, act; + int cs; + hb_glyph_info_t *info = buffer->info; + +#line 426 "hb-ot-shaper-indic-machine.hh" + { + cs = indic_syllable_machine_start; + ts = 0; + te = 0; + act = 0; + } + +#line 137 "hb-ot-shaper-indic-machine.rl" + + + p = 0; + pe = eof = buffer->len; + + unsigned int syllable_serial = 1; + +#line 442 "hb-ot-shaper-indic-machine.hh" + { + int _slen; + int _trans; + const unsigned char *_keys; + const unsigned char *_inds; + if ( p == pe ) + goto _test_eof; +_resume: + switch ( _indic_syllable_machine_from_state_actions[cs] ) { + case 10: +#line 1 "NONE" + {ts = p;} + break; +#line 456 "hb-ot-shaper-indic-machine.hh" + } + + _keys = _indic_syllable_machine_trans_keys + (cs<<1); + _inds = _indic_syllable_machine_indicies + _indic_syllable_machine_index_offsets[cs]; + + _slen = _indic_syllable_machine_key_spans[cs]; + _trans = _inds[ _slen > 0 && _keys[0] <=( info[p].indic_category()) && + ( info[p].indic_category()) <= _keys[1] ? + ( info[p].indic_category()) - _keys[0] : _slen ]; + +_eof_trans: + cs = _indic_syllable_machine_trans_targs[_trans]; + + if ( _indic_syllable_machine_trans_actions[_trans] == 0 ) + goto _again; + + switch ( _indic_syllable_machine_trans_actions[_trans] ) { + case 2: +#line 1 "NONE" + {te = p+1;} + break; + case 11: +#line 113 "hb-ot-shaper-indic-machine.rl" + {te = p+1;{ found_syllable (indic_non_indic_cluster); }} + break; + case 13: +#line 108 "hb-ot-shaper-indic-machine.rl" + {te = p;p--;{ found_syllable (indic_consonant_syllable); }} + break; + case 14: +#line 109 "hb-ot-shaper-indic-machine.rl" + {te = p;p--;{ found_syllable (indic_vowel_syllable); }} + break; + case 17: +#line 110 "hb-ot-shaper-indic-machine.rl" + {te = p;p--;{ found_syllable (indic_standalone_cluster); }} + break; + case 19: +#line 111 "hb-ot-shaper-indic-machine.rl" + {te = p;p--;{ found_syllable (indic_symbol_cluster); }} + break; + case 15: +#line 112 "hb-ot-shaper-indic-machine.rl" + {te = p;p--;{ found_syllable (indic_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; }} + break; + case 16: +#line 113 "hb-ot-shaper-indic-machine.rl" + {te = p;p--;{ found_syllable (indic_non_indic_cluster); }} + break; + case 1: +#line 108 "hb-ot-shaper-indic-machine.rl" + {{p = ((te))-1;}{ found_syllable (indic_consonant_syllable); }} + break; + case 3: +#line 109 "hb-ot-shaper-indic-machine.rl" + {{p = ((te))-1;}{ found_syllable (indic_vowel_syllable); }} + break; + case 7: +#line 110 "hb-ot-shaper-indic-machine.rl" + {{p = ((te))-1;}{ found_syllable (indic_standalone_cluster); }} + break; + case 8: +#line 111 "hb-ot-shaper-indic-machine.rl" + {{p = ((te))-1;}{ found_syllable (indic_symbol_cluster); }} + break; + case 4: +#line 112 "hb-ot-shaper-indic-machine.rl" + {{p = ((te))-1;}{ found_syllable (indic_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; }} + break; + case 6: +#line 1 "NONE" + { switch( act ) { + case 1: + {{p = ((te))-1;} found_syllable (indic_consonant_syllable); } + break; + case 5: + {{p = ((te))-1;} found_syllable (indic_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; } + break; + case 6: + {{p = ((te))-1;} found_syllable (indic_non_indic_cluster); } + break; + } + } + break; + case 18: +#line 1 "NONE" + {te = p+1;} +#line 108 "hb-ot-shaper-indic-machine.rl" + {act = 1;} + break; + case 5: +#line 1 "NONE" + {te = p+1;} +#line 112 "hb-ot-shaper-indic-machine.rl" + {act = 5;} + break; + case 12: +#line 1 "NONE" + {te = p+1;} +#line 113 "hb-ot-shaper-indic-machine.rl" + {act = 6;} + break; +#line 559 "hb-ot-shaper-indic-machine.hh" + } + +_again: + switch ( _indic_syllable_machine_to_state_actions[cs] ) { + case 9: +#line 1 "NONE" + {ts = 0;} + break; +#line 568 "hb-ot-shaper-indic-machine.hh" + } + + if ( ++p != pe ) + goto _resume; + _test_eof: {} + if ( p == eof ) + { + if ( _indic_syllable_machine_eof_trans[cs] > 0 ) { + _trans = _indic_syllable_machine_eof_trans[cs] - 1; + goto _eof_trans; + } + } + + } + +#line 145 "hb-ot-shaper-indic-machine.rl" + +} + +#undef found_syllable + +#endif /* HB_OT_SHAPER_INDIC_MACHINE_HH */ diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-indic-table.cc b/thirdparty/harfbuzz/src/hb-ot-shaper-indic-table.cc new file mode 100644 index 0000000000..8994f3ca59 --- /dev/null +++ b/thirdparty/harfbuzz/src/hb-ot-shaper-indic-table.cc @@ -0,0 +1,560 @@ +/* == Start of generated table == */ +/* + * The following table is generated by running: + * + * ./gen-indic-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt Blocks.txt + * + * on files with these headers: + * + * # IndicSyllabicCategory-14.0.0.txt + * # Date: 2021-05-22, 01:01:00 GMT [KW, RP] + * # IndicPositionalCategory-14.0.0.txt + * # Date: 2021-05-22, 01:01:00 GMT [KW, RP] + * # Blocks-14.0.0.txt + * # Date: 2021-01-22, 23:29:00 GMT [KW] + */ + +#include "hb.hh" + +#ifndef HB_NO_OT_SHAPE + +#include "hb-ot-shaper-indic.hh" + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-macros" + +#include "hb-ot-shaper-indic-machine.hh" +#include "hb-ot-shaper-khmer-machine.hh" +#include "hb-ot-shaper-myanmar-machine.hh" + +/* indic */ +#define OT_X I_Cat(X) +#define OT_C I_Cat(C) +#define OT_V I_Cat(V) +#define OT_N I_Cat(N) +#define OT_H I_Cat(H) +#define OT_ZWNJ I_Cat(ZWNJ) +#define OT_ZWJ I_Cat(ZWJ) +#define OT_M I_Cat(M) +#define OT_SM I_Cat(SM) +#define OT_A I_Cat(A) +#define OT_VD I_Cat(VD) +#define OT_PLACEHOLDER I_Cat(PLACEHOLDER) +#define OT_DOTTEDCIRCLE I_Cat(DOTTEDCIRCLE) +#define OT_RS I_Cat(RS) +#define OT_Repha I_Cat(Repha) +#define OT_Ra I_Cat(Ra) +#define OT_CM I_Cat(CM) +#define OT_Symbol I_Cat(Symbol) +#define OT_CS I_Cat(CS) +/* khmer */ +#define OT_VAbv K_Cat(VAbv) +#define OT_VBlw K_Cat(VBlw) +#define OT_VPre K_Cat(VPre) +#define OT_VPst K_Cat(VPst) +#define OT_Robatic K_Cat(Robatic) +#define OT_Xgroup K_Cat(Xgroup) +#define OT_Ygroup K_Cat(Ygroup) +/* myanmar */ +static_assert (OT_VAbv == M_Cat(VAbv), ""); +static_assert (OT_VBlw == M_Cat(VBlw), ""); +static_assert (OT_VPre == M_Cat(VPre), ""); +static_assert (OT_VPst == M_Cat(VPst), ""); +#define OT_IV M_Cat(IV) +#define OT_As M_Cat(As) +#define OT_DB M_Cat(DB) +#define OT_GB M_Cat(GB) +#define OT_MH M_Cat(MH) +#define OT_MR M_Cat(MR) +#define OT_MW M_Cat(MW) +#define OT_MY M_Cat(MY) +#define OT_PT M_Cat(PT) +#define OT_VS M_Cat(VS) +#define OT_ML M_Cat(ML) + + +#define _OT_A OT_A /* 53 chars; A */ +#define _OT_As OT_As /* 1 chars; As */ +#define _OT_C OT_C /* 478 chars; C */ +#define _OT_CM OT_CM /* 1 chars; CM */ +#define _OT_CS OT_CS /* 2 chars; CS */ +#define _OT_DC OT_DOTTEDCIRCLE /* 1 chars; DOTTEDCIRCLE */ +#define _OT_H OT_H /* 11 chars; H */ +#define _OT_M OT_M /* 143 chars; M */ +#define _OT_MH OT_MH /* 1 chars; MH */ +#define _OT_ML OT_ML /* 1 chars; ML */ +#define _OT_MR OT_MR /* 1 chars; MR */ +#define _OT_MW OT_MW /* 2 chars; MW */ +#define _OT_MY OT_MY /* 3 chars; MY */ +#define _OT_N OT_N /* 17 chars; N */ +#define _OT_GB OT_PLACEHOLDER /* 165 chars; PLACEHOLDER */ +#define _OT_PT OT_PT /* 8 chars; PT */ +#define _OT_R OT_Ra /* 14 chars; Ra */ +#define _OT_Rf OT_Repha /* 1 chars; Repha */ +#define _OT_Rt OT_Robatic /* 3 chars; Robatic */ +#define _OT_SM OT_SM /* 55 chars; SM */ +#define _OT_S OT_Symbol /* 22 chars; Symbol */ +#define _OT_V OT_V /* 172 chars; V */ +#define _OT_VA OT_VAbv /* 18 chars; VAbv */ +#define _OT_VB OT_VBlw /* 7 chars; VBlw */ +#define _OT_VL OT_VPre /* 5 chars; VPre */ +#define _OT_VR OT_VPst /* 13 chars; VPst */ +#define _OT_VS OT_VS /* 16 chars; VS */ +#define _OT_X OT_X /* 2 chars; X */ +#define _OT_Xg OT_Xgroup /* 7 chars; Xgroup */ +#define _OT_Yg OT_Ygroup /* 4 chars; Ygroup */ +#define _OT_ZWJ OT_ZWJ /* 1 chars; ZWJ */ +#define _OT_ZWNJ OT_ZWNJ /* 1 chars; ZWNJ */ + +#define _POS_T POS_ABOVE_C /* 22 chars; ABOVE_C */ +#define _POS_A POS_AFTER_MAIN /* 3 chars; AFTER_MAIN */ +#define _POS_AP POS_AFTER_POST /* 50 chars; AFTER_POST */ +#define _POS_AS POS_AFTER_SUB /* 51 chars; AFTER_SUB */ +#define _POS_C POS_BASE_C /* 833 chars; BASE_C */ +#define _POS_BS POS_BEFORE_SUB /* 25 chars; BEFORE_SUB */ +#define _POS_B POS_BELOW_C /* 13 chars; BELOW_C */ +#define _POS_X POS_END /* 71 chars; END */ +#define _POS_R POS_POST_C /* 13 chars; POST_C */ +#define _POS_L POS_PRE_C /* 5 chars; PRE_C */ +#define _POS_LM POS_PRE_M /* 14 chars; PRE_M */ +#define _POS_SM POS_SMVD /* 129 chars; SMVD */ + +#pragma GCC diagnostic pop + +#define INDIC_COMBINE_CATEGORIES(S,M) ((S) | ((M) << 8)) + +#define _(S,M) INDIC_COMBINE_CATEGORIES (_OT_##S, _POS_##M) + + +static const uint16_t indic_table[] = { + + +#define indic_offset_0x0028u 0 + + + /* Basic Latin */ + + /* 0028 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(GB,C), _(X,X), _(X,X), + /* 0030 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), + /* 0038 */ _(GB,C), _(GB,C), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), + +#define indic_offset_0x00b0u 24 + + + /* Latin-1 Supplement */ + + /* 00B0 */ _(X,X), _(X,X),_(SM,SM),_(SM,SM), _(X,X), _(X,X), _(X,X), _(X,X), + /* 00B8 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), + /* 00C0 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), + /* 00C8 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), + /* 00D0 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(GB,C), + +#define indic_offset_0x0900u 64 + + + /* Devanagari */ + + /* 0900 */_(SM,SM),_(SM,SM),_(SM,SM),_(SM,SM), _(V,C), _(V,C), _(V,C), _(V,C), + /* 0908 */ _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), + /* 0910 */ _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(C,C), _(C,C), _(C,C), + /* 0918 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), + /* 0920 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), + /* 0928 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), + /* 0930 */ _(R,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), + /* 0938 */ _(C,C), _(C,C), _(M,AS), _(M,AS), _(N,X), _(S,SM), _(M,AS), _(M,LM), + /* 0940 */ _(M,AS), _(M,AS), _(M,AS), _(M,AS), _(M,AS), _(M,AS), _(M,AS), _(M,AS), + /* 0948 */ _(M,AS), _(M,AS), _(M,AS), _(M,AS), _(M,AS), _(H,B), _(M,LM), _(M,AS), + /* 0950 */ _(X,X), _(A,SM), _(A,SM),_(SM,SM),_(SM,SM), _(M,AS), _(M,AS), _(M,AS), + /* 0958 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), + /* 0960 */ _(V,C), _(V,C), _(M,AS), _(M,AS), _(X,X), _(X,X), _(GB,C), _(GB,C), + /* 0968 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), + /* 0970 */ _(X,X), _(X,X), _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), + /* 0978 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), + + /* Bengali */ + + /* 0980 */ _(GB,C),_(SM,SM),_(SM,SM),_(SM,SM), _(X,X), _(V,C), _(V,C), _(V,C), + /* 0988 */ _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(X,X), _(X,X), _(V,C), + /* 0990 */ _(V,C), _(X,X), _(X,X), _(V,C), _(V,C), _(C,C), _(C,C), _(C,C), + /* 0998 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), + /* 09A0 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), + /* 09A8 */ _(C,C), _(X,X), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), + /* 09B0 */ _(R,C), _(X,X), _(C,C), _(X,X), _(X,X), _(X,X), _(C,C), _(C,C), + /* 09B8 */ _(C,C), _(C,C), _(X,X), _(X,X), _(N,X), _(S,SM), _(M,AP), _(M,LM), + /* 09C0 */ _(M,AP), _(M,AS), _(M,AS), _(M,AS), _(M,AS), _(X,X), _(X,X), _(M,LM), + /* 09C8 */ _(M,LM), _(X,X), _(X,X), _(M,AP), _(M,AP), _(H,B), _(C,C), _(X,X), + /* 09D0 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(M,AP), + /* 09D8 */ _(X,X), _(X,X), _(X,X), _(X,X), _(C,C), _(C,C), _(X,X), _(C,C), + /* 09E0 */ _(V,C), _(V,C), _(M,AS), _(M,AS), _(X,X), _(X,X), _(GB,C), _(GB,C), + /* 09E8 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), + /* 09F0 */ _(R,C), _(C,C), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), + /* 09F8 */ _(X,X), _(X,X), _(X,X), _(X,X), _(GB,C), _(X,X),_(SM,SM), _(X,X), + + /* Gurmukhi */ + + /* 0A00 */ _(X,X),_(SM,SM),_(SM,SM),_(SM,SM), _(X,X), _(V,C), _(V,C), _(V,C), + /* 0A08 */ _(V,C), _(V,C), _(V,C), _(X,X), _(X,X), _(X,X), _(X,X), _(V,C), + /* 0A10 */ _(V,C), _(X,X), _(X,X), _(V,C), _(V,C), _(C,C), _(C,C), _(C,C), + /* 0A18 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), + /* 0A20 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), + /* 0A28 */ _(C,C), _(X,X), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), + /* 0A30 */ _(R,C), _(X,X), _(C,C), _(C,C), _(X,X), _(C,C), _(C,C), _(X,X), + /* 0A38 */ _(C,C), _(C,C), _(X,X), _(X,X), _(N,X), _(X,X), _(M,AP), _(M,LM), + /* 0A40 */ _(M,AP), _(M,AP), _(M,AP), _(X,X), _(X,X), _(X,X), _(X,X), _(M,AP), + /* 0A48 */ _(M,AP), _(X,X), _(X,X), _(M,AP), _(M,AP), _(H,B), _(X,X), _(X,X), + /* 0A50 */ _(X,X), _(M,B), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), + /* 0A58 */ _(X,X), _(C,C), _(C,C), _(C,C), _(C,C), _(X,X), _(C,C), _(X,X), + /* 0A60 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(GB,C), _(GB,C), + /* 0A68 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), + /* 0A70 */_(SM,SM),_(SM,SM), _(C,C), _(C,C), _(X,X), _(CM,C), _(X,X), _(X,X), + /* 0A78 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), + + /* Gujarati */ + + /* 0A80 */ _(X,X),_(SM,SM),_(SM,SM),_(SM,SM), _(X,X), _(V,C), _(V,C), _(V,C), + /* 0A88 */ _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(X,X), _(V,C), + /* 0A90 */ _(V,C), _(V,C), _(X,X), _(V,C), _(V,C), _(C,C), _(C,C), _(C,C), + /* 0A98 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), + /* 0AA0 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), + /* 0AA8 */ _(C,C), _(X,X), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), + /* 0AB0 */ _(R,C), _(X,X), _(C,C), _(C,C), _(X,X), _(C,C), _(C,C), _(C,C), + /* 0AB8 */ _(C,C), _(C,C), _(X,X), _(X,X), _(N,X), _(S,SM), _(M,AP), _(M,LM), + /* 0AC0 */ _(M,AP), _(M,AP), _(M,AP), _(M,AP), _(M,AP), _(M,AS), _(X,X), _(M,AS), + /* 0AC8 */ _(M,AS), _(M,AP), _(X,X), _(M,AP), _(M,AP), _(H,B), _(X,X), _(X,X), + /* 0AD0 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), + /* 0AD8 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), + /* 0AE0 */ _(V,C), _(V,C), _(M,AP), _(M,AP), _(X,X), _(X,X), _(GB,C), _(GB,C), + /* 0AE8 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), + /* 0AF0 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), + /* 0AF8 */ _(X,X), _(C,C), _(A,SM), _(N,X), _(A,SM), _(N,X), _(N,X), _(N,X), + + /* Oriya */ + + /* 0B00 */ _(X,X),_(SM,BS),_(SM,SM),_(SM,SM), _(X,X), _(V,C), _(V,C), _(V,C), + /* 0B08 */ _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(X,X), _(X,X), _(V,C), + /* 0B10 */ _(V,C), _(X,X), _(X,X), _(V,C), _(V,C), _(C,C), _(C,C), _(C,C), + /* 0B18 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), + /* 0B20 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), + /* 0B28 */ _(C,C), _(X,X), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), + /* 0B30 */ _(R,C), _(X,X), _(C,C), _(C,C), _(X,X), _(C,C), _(C,C), _(C,C), + /* 0B38 */ _(C,C), _(C,C), _(X,X), _(X,X), _(N,X), _(S,SM), _(M,AP), _(M,A), + /* 0B40 */ _(M,AP), _(M,AS), _(M,AS), _(M,AS), _(M,AS), _(X,X), _(X,X), _(M,LM), + /* 0B48 */ _(M,A), _(X,X), _(X,X), _(M,AP), _(M,AP), _(H,B), _(X,X), _(X,X), + /* 0B50 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(N,X), _(M,A), _(M,AP), + /* 0B58 */ _(X,X), _(X,X), _(X,X), _(X,X), _(C,C), _(C,C), _(X,X), _(C,C), + /* 0B60 */ _(V,C), _(V,C), _(M,AS), _(M,AS), _(X,X), _(X,X), _(GB,C), _(GB,C), + /* 0B68 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), + /* 0B70 */ _(X,X), _(C,C), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), + /* 0B78 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), + + /* Tamil */ + + /* 0B80 */ _(X,X), _(X,X),_(SM,SM), _(X,X), _(X,X), _(V,C), _(V,C), _(V,C), + /* 0B88 */ _(V,C), _(V,C), _(V,C), _(X,X), _(X,X), _(X,X), _(V,C), _(V,C), + /* 0B90 */ _(V,C), _(X,X), _(V,C), _(V,C), _(V,C), _(C,C), _(X,X), _(X,X), + /* 0B98 */ _(X,X), _(C,C), _(C,C), _(X,X), _(C,C), _(X,X), _(C,C), _(C,C), + /* 0BA0 */ _(X,X), _(X,X), _(X,X), _(C,C), _(C,C), _(X,X), _(X,X), _(X,X), + /* 0BA8 */ _(C,C), _(C,C), _(C,C), _(X,X), _(X,X), _(X,X), _(C,C), _(C,C), + /* 0BB0 */ _(R,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), + /* 0BB8 */ _(C,C), _(C,C), _(X,X), _(X,X), _(X,X), _(X,X), _(M,AP), _(M,AP), + /* 0BC0 */ _(M,AS), _(M,AP), _(M,AP), _(X,X), _(X,X), _(X,X), _(M,LM), _(M,LM), + /* 0BC8 */ _(M,LM), _(X,X), _(M,AP), _(M,AP), _(M,AP), _(H,T), _(X,X), _(X,X), + /* 0BD0 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(M,AP), + /* 0BD8 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), + /* 0BE0 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(GB,C), _(GB,C), + /* 0BE8 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), + /* 0BF0 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), + /* 0BF8 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), + + /* Telugu */ + + /* 0C00 */_(SM,SM),_(SM,SM),_(SM,SM),_(SM,SM),_(SM,SM), _(V,C), _(V,C), _(V,C), + /* 0C08 */ _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(X,X), _(V,C), _(V,C), + /* 0C10 */ _(V,C), _(X,X), _(V,C), _(V,C), _(V,C), _(C,C), _(C,C), _(C,C), + /* 0C18 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), + /* 0C20 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), + /* 0C28 */ _(C,C), _(X,X), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), + /* 0C30 */ _(R,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), + /* 0C38 */ _(C,C), _(C,C), _(X,X), _(X,X), _(N,X), _(S,SM), _(M,BS), _(M,BS), + /* 0C40 */ _(M,BS), _(M,BS), _(M,BS), _(M,AS), _(M,AS), _(X,X), _(M,BS), _(M,BS), + /* 0C48 */ _(M,BS), _(X,X), _(M,BS), _(M,BS), _(M,BS), _(H,T), _(X,X), _(X,X), + /* 0C50 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(M,BS), _(M,BS), _(X,X), + /* 0C58 */ _(C,C), _(C,C), _(C,C), _(X,X), _(X,X), _(C,C), _(X,X), _(X,X), + /* 0C60 */ _(V,C), _(V,C), _(M,BS), _(M,BS), _(X,X), _(X,X), _(GB,C), _(GB,C), + /* 0C68 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), + /* 0C70 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), + /* 0C78 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), + + /* Kannada */ + + /* 0C80 */ _(GB,C),_(SM,SM),_(SM,SM),_(SM,SM), _(X,X), _(V,C), _(V,C), _(V,C), + /* 0C88 */ _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(X,X), _(V,C), _(V,C), + /* 0C90 */ _(V,C), _(X,X), _(V,C), _(V,C), _(V,C), _(C,C), _(C,C), _(C,C), + /* 0C98 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), + /* 0CA0 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), + /* 0CA8 */ _(C,C), _(X,X), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), + /* 0CB0 */ _(R,C), _(C,C), _(C,C), _(C,C), _(X,X), _(C,C), _(C,C), _(C,C), + /* 0CB8 */ _(C,C), _(C,C), _(X,X), _(X,X), _(N,X), _(S,SM), _(M,BS), _(M,BS), + /* 0CC0 */ _(M,BS), _(M,BS), _(M,BS), _(M,AS), _(M,AS), _(X,X), _(M,BS), _(M,AS), + /* 0CC8 */ _(M,AS), _(X,X), _(M,AS), _(M,AS), _(M,BS), _(H,T), _(X,X), _(X,X), + /* 0CD0 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(M,AS), _(M,AS), _(X,X), + /* 0CD8 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(C,C), _(C,C), _(X,X), + /* 0CE0 */ _(V,C), _(V,C), _(M,BS), _(M,BS), _(X,X), _(X,X), _(GB,C), _(GB,C), + /* 0CE8 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), + /* 0CF0 */ _(X,X), _(CS,C), _(CS,C), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), + /* 0CF8 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), + + /* Malayalam */ + + /* 0D00 */_(SM,SM),_(SM,SM),_(SM,SM),_(SM,SM), _(GB,C), _(V,C), _(V,C), _(V,C), + /* 0D08 */ _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(X,X), _(V,C), _(V,C), + /* 0D10 */ _(V,C), _(X,X), _(V,C), _(V,C), _(V,C), _(C,C), _(C,C), _(C,C), + /* 0D18 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), + /* 0D20 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), + /* 0D28 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), + /* 0D30 */ _(R,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), + /* 0D38 */ _(C,C), _(C,C), _(C,C), _(M,AS), _(M,AS), _(S,SM), _(M,AP), _(M,AP), + /* 0D40 */ _(M,AP), _(M,AP), _(M,AP), _(M,AP), _(M,AP), _(X,X), _(M,LM), _(M,LM), + /* 0D48 */ _(M,LM), _(X,X), _(M,AP), _(M,AP), _(M,AP), _(H,T), _(Rf,X), _(X,X), + /* 0D50 */ _(X,X), _(X,X), _(X,X), _(X,X), _(C,C), _(C,C), _(C,C), _(M,AP), + /* 0D58 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(V,C), + /* 0D60 */ _(V,C), _(V,C), _(M,AP), _(M,AP), _(X,X), _(X,X), _(GB,C), _(GB,C), + /* 0D68 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), + /* 0D70 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), + /* 0D78 */ _(X,X), _(X,X), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), + +#define indic_offset_0x1000u 1216 + + + /* Myanmar */ + + /* 1000 */ _(C,C), _(C,C), _(C,C), _(C,C), _(R,C), _(C,C), _(C,C), _(C,C), + /* 1008 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), + /* 1010 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), + /* 1018 */ _(C,C), _(C,C), _(C,C), _(R,C), _(C,C), _(C,C), _(C,C), _(C,C), + /* 1020 */ _(C,C), _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), + /* 1028 */ _(V,C), _(V,C), _(V,C), _(VR,R), _(VR,R), _(VA,T), _(VA,T), _(VB,B), + /* 1030 */ _(VB,B), _(VL,L), _(A,SM), _(VA,T), _(VA,T), _(VA,T), _(A,SM), _(N,X), + /* 1038 */_(SM,SM), _(H,X), _(As,X), _(MY,X), _(MR,X), _(MW,X), _(MH,X), _(C,C), + /* 1040 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), + /* 1048 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(X,X), _(X,X), _(C,C), _(X,X), + /* 1050 */ _(C,C), _(C,C), _(V,C), _(V,C), _(V,C), _(V,C), _(VR,R), _(VR,R), + /* 1058 */ _(VB,B), _(VB,B), _(R,C), _(C,C), _(C,C), _(C,C), _(MY,X), _(MY,X), + /* 1060 */ _(ML,X), _(C,C), _(VR,R), _(PT,X), _(PT,X), _(C,C), _(C,C), _(VR,R), + /* 1068 */ _(VR,R), _(PT,X), _(PT,X), _(PT,X), _(PT,X), _(PT,X), _(C,C), _(C,C), + /* 1070 */ _(C,C), _(VA,T), _(VA,T), _(VA,T), _(VA,T), _(C,C), _(C,C), _(C,C), + /* 1078 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), + /* 1080 */ _(C,C), _(C,C), _(MW,X), _(VR,R), _(VL,L), _(VA,T), _(VA,T),_(SM,SM), + /* 1088 */_(SM,SM),_(SM,SM),_(SM,SM),_(SM,SM),_(SM,SM),_(SM,SM), _(C,C),_(SM,SM), + /* 1090 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), + /* 1098 */ _(GB,C), _(GB,C),_(SM,SM),_(SM,SM),_(SM,SM), _(VA,T), _(X,X), _(X,X), + +#define indic_offset_0x1780u 1376 + + + /* Khmer */ + + /* 1780 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), + /* 1788 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), + /* 1790 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), + /* 1798 */ _(C,C), _(C,C), _(R,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), + /* 17A0 */ _(C,C), _(C,C), _(C,C), _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), + /* 17A8 */ _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), _(V,C), + /* 17B0 */ _(V,C), _(V,C), _(V,C), _(V,C), _(X,X), _(X,X), _(VR,R), _(VA,T), + /* 17B8 */ _(VA,T), _(VA,T), _(VA,T), _(VB,B), _(VB,B), _(VB,B), _(VA,T), _(VR,R), + /* 17C0 */ _(VR,R), _(VL,L), _(VL,L), _(VL,L), _(VR,R), _(VR,R), _(Xg,X), _(Yg,X), + /* 17C8 */ _(Yg,X), _(Rt,X), _(Rt,X), _(Xg,X), _(Rt,X), _(Xg,X), _(Xg,X), _(Xg,X), + /* 17D0 */ _(Xg,X), _(Xg,X), _(H,X), _(Yg,X), _(X,X), _(X,X), _(X,X), _(X,X), + /* 17D8 */ _(X,X), _(GB,C), _(X,X), _(X,X), _(S,SM), _(Yg,X), _(X,X), _(X,X), + /* 17E0 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), + /* 17E8 */ _(GB,C), _(GB,C), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), + +#define indic_offset_0x1cd0u 1488 + + + /* Vedic Extensions */ + + /* 1CD0 */ _(A,SM), _(A,SM), _(A,SM), _(X,X), _(A,SM), _(A,SM), _(A,SM), _(A,SM), + /* 1CD8 */ _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), + /* 1CE0 */ _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), + /* 1CE8 */ _(A,SM), _(S,SM), _(S,SM), _(S,SM), _(S,SM), _(A,SM), _(S,SM), _(S,SM), + /* 1CF0 */ _(S,SM), _(S,SM), _(C,C), _(C,C), _(A,SM), _(C,C), _(C,C), _(A,SM), + /* 1CF8 */ _(A,SM), _(A,SM), _(GB,C), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), + +#define indic_offset_0x2008u 1536 + + + /* General Punctuation */ + + /* 2008 */ _(X,X), _(X,X), _(X,X), _(X,X),_(ZWNJ,X),_(ZWJ,X), _(X,X), _(X,X), + /* 2010 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(X,X), _(X,X), + /* 2018 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), + /* 2020 */ _(X,X), _(X,X), _(GB,C), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), + +#define indic_offset_0x2070u 1568 + + + /* Superscripts and Subscripts */ + + /* 2070 */ _(X,X), _(X,X), _(X,X), _(X,X),_(SM,SM), _(X,X), _(X,X), _(X,X), + /* 2078 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), + /* 2080 */ _(X,X), _(X,X),_(SM,SM),_(SM,SM),_(SM,SM), _(X,X), _(X,X), _(X,X), + +#define indic_offset_0x25f8u 1592 + + + /* Geometric Shapes */ + + /* 25F8 */ _(X,X), _(X,X), _(X,X), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(X,X), + +#define indic_offset_0xa8e0u 1600 + + + /* Devanagari Extended */ + + /* A8E0 */ _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), + /* A8E8 */ _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), _(A,SM), + /* A8F0 */ _(A,SM), _(A,SM), _(S,SM), _(S,SM), _(S,SM), _(S,SM), _(S,SM), _(S,SM), + /* A8F8 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(V,C), _(M,AS), + +#define indic_offset_0xa9e0u 1632 + + + /* Myanmar Extended-B */ + + /* A9E0 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(VA,T), _(X,X), _(C,C), + /* A9E8 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), + /* A9F0 */ _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), _(GB,C), + /* A9F8 */ _(GB,C), _(GB,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(X,X), + +#define indic_offset_0xaa60u 1664 + + + /* Myanmar Extended-A */ + + /* AA60 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), + /* AA68 */ _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), _(C,C), + /* AA70 */ _(X,X), _(C,C), _(C,C), _(C,C), _(GB,C), _(GB,C), _(GB,C), _(X,X), + /* AA78 */ _(X,X), _(X,X), _(C,C), _(PT,X), _(N,X), _(N,X), _(C,C), _(C,C), + +#define indic_offset_0xfe00u 1696 + + + /* Variation Selectors */ + + /* FE00 */ _(VS,X), _(VS,X), _(VS,X), _(VS,X), _(VS,X), _(VS,X), _(VS,X), _(VS,X), + /* FE08 */ _(VS,X), _(VS,X), _(VS,X), _(VS,X), _(VS,X), _(VS,X), _(VS,X), _(VS,X), + +#define indic_offset_0x11300u 1712 + + + /* Grantha */ + + /* 11300 */ _(X,X),_(SM,SM),_(SM,SM),_(SM,SM), _(X,X), _(X,X), _(X,X), _(X,X), + /* 11308 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), + /* 11310 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), + /* 11318 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), + /* 11320 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), + /* 11328 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), + /* 11330 */ _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), _(X,X), + /* 11338 */ _(X,X), _(X,X), _(X,X), _(N,X), _(N,X), _(X,X), _(X,X), _(X,X), + +}; /* Table items: 1776; occupancy: 69% */ + +uint16_t +hb_indic_get_categories (hb_codepoint_t u) +{ + switch (u >> 12) + { + case 0x0u: + if (unlikely (u == 0x00A0u)) return _(GB,C); + if (hb_in_range<hb_codepoint_t> (u, 0x0028u, 0x003Fu)) return indic_table[u - 0x0028u + indic_offset_0x0028u]; + if (hb_in_range<hb_codepoint_t> (u, 0x00B0u, 0x00D7u)) return indic_table[u - 0x00B0u + indic_offset_0x00b0u]; + if (hb_in_range<hb_codepoint_t> (u, 0x0900u, 0x0D7Fu)) return indic_table[u - 0x0900u + indic_offset_0x0900u]; + break; + + case 0x1u: + if (hb_in_range<hb_codepoint_t> (u, 0x1000u, 0x109Fu)) return indic_table[u - 0x1000u + indic_offset_0x1000u]; + if (hb_in_range<hb_codepoint_t> (u, 0x1780u, 0x17EFu)) return indic_table[u - 0x1780u + indic_offset_0x1780u]; + if (hb_in_range<hb_codepoint_t> (u, 0x1CD0u, 0x1CFFu)) return indic_table[u - 0x1CD0u + indic_offset_0x1cd0u]; + break; + + case 0x2u: + if (unlikely (u == 0x25CCu)) return _(DC,C); + if (hb_in_range<hb_codepoint_t> (u, 0x2008u, 0x2027u)) return indic_table[u - 0x2008u + indic_offset_0x2008u]; + if (hb_in_range<hb_codepoint_t> (u, 0x2070u, 0x2087u)) return indic_table[u - 0x2070u + indic_offset_0x2070u]; + if (hb_in_range<hb_codepoint_t> (u, 0x25F8u, 0x25FFu)) return indic_table[u - 0x25F8u + indic_offset_0x25f8u]; + break; + + case 0xAu: + if (hb_in_range<hb_codepoint_t> (u, 0xA8E0u, 0xA8FFu)) return indic_table[u - 0xA8E0u + indic_offset_0xa8e0u]; + if (hb_in_range<hb_codepoint_t> (u, 0xA9E0u, 0xA9FFu)) return indic_table[u - 0xA9E0u + indic_offset_0xa9e0u]; + if (hb_in_range<hb_codepoint_t> (u, 0xAA60u, 0xAA7Fu)) return indic_table[u - 0xAA60u + indic_offset_0xaa60u]; + break; + + case 0xFu: + if (hb_in_range<hb_codepoint_t> (u, 0xFE00u, 0xFE0Fu)) return indic_table[u - 0xFE00u + indic_offset_0xfe00u]; + break; + + case 0x11u: + if (hb_in_range<hb_codepoint_t> (u, 0x11300u, 0x1133Fu)) return indic_table[u - 0x11300u + indic_offset_0x11300u]; + break; + + default: + break; + } + return _(X,X); +} + +#undef _ +#undef INDIC_COMBINE_CATEGORIES + +#undef _OT_A +#undef _OT_As +#undef _OT_C +#undef _OT_CM +#undef _OT_CS +#undef _OT_DC +#undef _OT_H +#undef _OT_M +#undef _OT_MH +#undef _OT_ML +#undef _OT_MR +#undef _OT_MW +#undef _OT_MY +#undef _OT_N +#undef _OT_GB +#undef _OT_PT +#undef _OT_R +#undef _OT_Rf +#undef _OT_Rt +#undef _OT_SM +#undef _OT_S +#undef _OT_V +#undef _OT_VA +#undef _OT_VB +#undef _OT_VL +#undef _OT_VR +#undef _OT_VS +#undef _OT_X +#undef _OT_Xg +#undef _OT_Yg +#undef _OT_ZWJ +#undef _OT_ZWNJ + +#undef _POS_T +#undef _POS_A +#undef _POS_AP +#undef _POS_AS +#undef _POS_C +#undef _POS_BS +#undef _POS_B +#undef _POS_X +#undef _POS_R +#undef _POS_L +#undef _POS_LM +#undef _POS_SM + +#endif + +/* == End of generated table == */ diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic.cc b/thirdparty/harfbuzz/src/hb-ot-shaper-indic.cc index c80f7df6a9..48a3c74463 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-indic.cc +++ b/thirdparty/harfbuzz/src/hb-ot-shaper-indic.cc @@ -28,9 +28,9 @@ #ifndef HB_NO_OT_SHAPE -#include "hb-ot-shape-complex-indic.hh" -#include "hb-ot-shape-complex-indic-machine.hh" -#include "hb-ot-shape-complex-vowel-constraints.hh" +#include "hb-ot-shaper-indic.hh" +#include "hb-ot-shaper-indic-machine.hh" +#include "hb-ot-shaper-vowel-constraints.hh" #include "hb-ot-layout.hh" @@ -39,6 +39,81 @@ */ +static inline void +set_indic_properties (hb_glyph_info_t &info) +{ + hb_codepoint_t u = info.codepoint; + unsigned int type = hb_indic_get_categories (u); + + info.indic_category() = (indic_category_t) (type & 0xFFu); + info.indic_position() = (indic_position_t) (type >> 8); +} + + +static inline bool +is_one_of (const hb_glyph_info_t &info, unsigned int flags) +{ + /* If it ligated, all bets are off. */ + if (_hb_glyph_info_ligated (&info)) return false; + return !!(FLAG_UNSAFE (info.indic_category()) & flags); +} + +/* Note: + * + * We treat Vowels and placeholders as if they were consonants. This is safe because Vowels + * cannot happen in a consonant syllable. The plus side however is, we can call the + * consonant syllable logic from the vowel syllable function and get it all right! + * + * Keep in sync with consonant_categories in the generator. */ +#define CONSONANT_FLAGS_INDIC (FLAG (I_Cat(C)) | FLAG (I_Cat(CS)) | FLAG (I_Cat(Ra)) | FLAG (I_Cat(CM)) | FLAG (I_Cat(V)) | FLAG (I_Cat(PLACEHOLDER)) | FLAG (I_Cat(DOTTEDCIRCLE))) + +static inline bool +is_consonant (const hb_glyph_info_t &info) +{ + return is_one_of (info, CONSONANT_FLAGS_INDIC); +} + +#define JOINER_FLAGS (FLAG (I_Cat(ZWJ)) | FLAG (I_Cat(ZWNJ))) + +static inline bool +is_joiner (const hb_glyph_info_t &info) +{ + return is_one_of (info, JOINER_FLAGS); +} + +static inline bool +is_halant (const hb_glyph_info_t &info) +{ + return is_one_of (info, FLAG (I_Cat(H))); +} + +struct hb_indic_would_substitute_feature_t +{ + void init (const hb_ot_map_t *map, hb_tag_t feature_tag, bool zero_context_) + { + zero_context = zero_context_; + map->get_stage_lookups (0/*GSUB*/, + map->get_feature_stage (0/*GSUB*/, feature_tag), + &lookups, &count); + } + + bool would_substitute (const hb_codepoint_t *glyphs, + unsigned int glyphs_count, + hb_face_t *face) const + { + for (unsigned int i = 0; i < count; i++) + if (hb_ot_layout_lookup_would_substitute (face, lookups[i].index, glyphs, glyphs_count, zero_context)) + return true; + return false; + } + + private: + const hb_ot_map_t::lookup_map_t *lookups; + unsigned int count; + bool zero_context; +}; + + /* * Indic configurations. Note that we do not want to keep every single script-specific * behavior in these tables necessarily. This should mainly be used for per-script @@ -47,10 +122,6 @@ * instead of adding a new flag in these structs. */ -enum base_position_t { - BASE_POS_LAST_SINHALA, - BASE_POS_LAST -}; enum reph_position_t { REPH_POS_AFTER_MAIN = POS_AFTER_MAIN, REPH_POS_BEFORE_SUB = POS_BEFORE_SUB, @@ -72,7 +143,6 @@ struct indic_config_t hb_script_t script; bool has_old_spec; hb_codepoint_t virama; - base_position_t base_pos; reph_position_t reph_pos; reph_mode_t reph_mode; blwf_mode_t blwf_mode; @@ -81,26 +151,19 @@ struct indic_config_t static const indic_config_t indic_configs[] = { /* Default. Should be first. */ - {HB_SCRIPT_INVALID, false, 0,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST}, - {HB_SCRIPT_DEVANAGARI,true, 0x094Du,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST}, - {HB_SCRIPT_BENGALI, true, 0x09CDu,BASE_POS_LAST, REPH_POS_AFTER_SUB, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST}, - {HB_SCRIPT_GURMUKHI, true, 0x0A4Du,BASE_POS_LAST, REPH_POS_BEFORE_SUB, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST}, - {HB_SCRIPT_GUJARATI, true, 0x0ACDu,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST}, - {HB_SCRIPT_ORIYA, true, 0x0B4Du,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST}, - {HB_SCRIPT_TAMIL, true, 0x0BCDu,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST}, - {HB_SCRIPT_TELUGU, true, 0x0C4Du,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_EXPLICIT, BLWF_MODE_POST_ONLY}, - {HB_SCRIPT_KANNADA, true, 0x0CCDu,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT, BLWF_MODE_POST_ONLY}, - {HB_SCRIPT_MALAYALAM, true, 0x0D4Du,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_LOG_REPHA,BLWF_MODE_PRE_AND_POST}, - {HB_SCRIPT_SINHALA, false,0x0DCAu,BASE_POS_LAST_SINHALA, - REPH_POS_AFTER_POST, REPH_MODE_EXPLICIT, BLWF_MODE_PRE_AND_POST}, + {HB_SCRIPT_INVALID, false, 0,REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST}, + {HB_SCRIPT_DEVANAGARI,true, 0x094Du,REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST}, + {HB_SCRIPT_BENGALI, true, 0x09CDu,REPH_POS_AFTER_SUB, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST}, + {HB_SCRIPT_GURMUKHI, true, 0x0A4Du,REPH_POS_BEFORE_SUB, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST}, + {HB_SCRIPT_GUJARATI, true, 0x0ACDu,REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST}, + {HB_SCRIPT_ORIYA, true, 0x0B4Du,REPH_POS_AFTER_MAIN, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST}, + {HB_SCRIPT_TAMIL, true, 0x0BCDu,REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST}, + {HB_SCRIPT_TELUGU, true, 0x0C4Du,REPH_POS_AFTER_POST, REPH_MODE_EXPLICIT, BLWF_MODE_POST_ONLY}, + {HB_SCRIPT_KANNADA, true, 0x0CCDu,REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT, BLWF_MODE_POST_ONLY}, + {HB_SCRIPT_MALAYALAM, true, 0x0D4Du,REPH_POS_AFTER_MAIN, REPH_MODE_LOG_REPHA,BLWF_MODE_PRE_AND_POST}, }; - -/* - * Indic shaper. - */ - static const hb_ot_map_feature_t indic_features[] = { @@ -207,6 +270,7 @@ static void override_features_indic (hb_ot_shape_planner_t *plan) { plan->map.disable_feature (HB_TAG('l','i','g','a')); + plan->map.add_gsub_pause (hb_syllabic_clear_var); // Don't need syllables anymore, use stop to free buffer var } @@ -356,6 +420,7 @@ setup_syllables_indic (const hb_ot_shape_plan_t *plan HB_UNUSED, hb_font_t *font HB_UNUSED, hb_buffer_t *buffer) { + HB_BUFFER_ALLOCATE_VAR (buffer, syllable); find_syllables_indic (buffer); foreach_syllable (buffer, start, end) buffer->unsafe_to_break (start, end); @@ -367,7 +432,7 @@ compare_indic_order (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb) int a = pa->indic_position(); int b = pb->indic_position(); - return a < b ? -1 : a == b ? 0 : +1; + return (int) a - (int) b; } @@ -379,9 +444,6 @@ update_consonant_positions_indic (const hb_ot_shape_plan_t *plan, { const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data; - if (indic_plan->config->base_pos != BASE_POS_LAST) - return; - hb_codepoint_t virama; if (indic_plan->load_virama_glyph (font, &virama)) { @@ -416,9 +478,9 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, */ if (buffer->props.script == HB_SCRIPT_KANNADA && start + 3 <= end && - is_one_of (info[start ], FLAG (OT_Ra)) && - is_one_of (info[start+1], FLAG (OT_H)) && - is_one_of (info[start+2], FLAG (OT_ZWJ))) + is_one_of (info[start ], FLAG (I_Cat(Ra))) && + is_one_of (info[start+1], FLAG (I_Cat(H))) && + is_one_of (info[start+2], FLAG (I_Cat(ZWJ)))) { buffer->merge_clusters (start+1, start+3); hb_glyph_info_t tmp = info[start+1]; @@ -452,7 +514,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, start + 3 <= end && ( (indic_plan->config->reph_mode == REPH_MODE_IMPLICIT && !is_joiner (info[start + 2])) || - (indic_plan->config->reph_mode == REPH_MODE_EXPLICIT && info[start + 2].indic_category() == OT_ZWJ) + (indic_plan->config->reph_mode == REPH_MODE_EXPLICIT && info[start + 2].indic_category() == I_Cat(ZWJ)) )) { /* See if it matches the 'rphf' feature. */ @@ -470,7 +532,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, base = start; has_reph = true; } - } else if (indic_plan->config->reph_mode == REPH_MODE_LOG_REPHA && info[start].indic_category() == OT_Repha) + } else if (indic_plan->config->reph_mode == REPH_MODE_LOG_REPHA && info[start].indic_category() == I_Cat(Repha)) { limit += 1; while (limit < end && is_joiner (info[limit])) @@ -479,84 +541,51 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, has_reph = true; } - switch (indic_plan->config->base_pos) { - case BASE_POS_LAST: - { - /* -> starting from the end of the syllable, move backwards */ - unsigned int i = end; - bool seen_below = false; - do { - i--; - /* -> until a consonant is found */ - if (is_consonant (info[i])) + /* -> starting from the end of the syllable, move backwards */ + unsigned int i = end; + bool seen_below = false; + do { + i--; + /* -> until a consonant is found */ + if (is_consonant (info[i])) + { + /* -> that does not have a below-base or post-base form + * (post-base forms have to follow below-base forms), */ + if (info[i].indic_position() != POS_BELOW_C && + (info[i].indic_position() != POS_POST_C || seen_below)) { - /* -> that does not have a below-base or post-base form - * (post-base forms have to follow below-base forms), */ - if (info[i].indic_position() != POS_BELOW_C && - (info[i].indic_position() != POS_POST_C || seen_below)) - { - base = i; - break; - } - if (info[i].indic_position() == POS_BELOW_C) - seen_below = true; - - /* -> or that is not a pre-base-reordering Ra, - * - * IMPLEMENTATION NOTES: - * - * Our pre-base-reordering Ra's are marked POS_POST_C, so will be skipped - * by the logic above already. - */ - - /* -> or arrive at the first consonant. The consonant stopped at will - * be the base. */ base = i; + break; } - else - { - /* A ZWJ after a Halant stops the base search, and requests an explicit - * half form. - * A ZWJ before a Halant, requests a subjoined form instead, and hence - * search continues. This is particularly important for Bengali - * sequence Ra,H,Ya that should form Ya-Phalaa by subjoining Ya. */ - if (start < i && - info[i].indic_category() == OT_ZWJ && - info[i - 1].indic_category() == OT_H) - break; - } - } while (i > limit); - } - break; - - case BASE_POS_LAST_SINHALA: - { - /* Sinhala base positioning is slightly different from main Indic, in that: - * 1. Its ZWJ behavior is different, - * 2. We don't need to look into the font for consonant positions. - */ - - if (!has_reph) - base = limit; + if (info[i].indic_position() == POS_BELOW_C) + seen_below = true; - /* Find the last base consonant that is not blocked by ZWJ. If there is - * a ZWJ right before a base consonant, that would request a subjoined form. */ - for (unsigned int i = limit; i < end; i++) - if (is_consonant (info[i])) - { - if (limit < i && info[i - 1].indic_category() == OT_ZWJ) - break; - else - base = i; - } + /* -> or that is not a pre-base-reordering Ra, + * + * IMPLEMENTATION NOTES: + * + * Our pre-base-reordering Ra's are marked POS_POST_C, so will be skipped + * by the logic above already. + */ - /* Mark all subsequent consonants as below. */ - for (unsigned int i = base + 1; i < end; i++) - if (is_consonant (info[i])) - info[i].indic_position() = POS_BELOW_C; - } - break; + /* -> or arrive at the first consonant. The consonant stopped at will + * be the base. */ + base = i; + } + else + { + /* A ZWJ after a Halant stops the base search, and requests an explicit + * half form. + * A ZWJ before a Halant, requests a subjoined form instead, and hence + * search continues. This is particularly important for Bengali + * sequence Ra,H,Ya that should form Ya-Phalaa by subjoining Ya. */ + if (start < i && + info[i].indic_category() == I_Cat(ZWJ) && + info[i - 1].indic_category() == I_Cat(H)) + break; + } + } while (i > limit); } /* -> If the syllable starts with Ra + Halant (in a script that has Reph) @@ -611,18 +640,6 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, if (base < end) info[base].indic_position() = POS_BASE_C; - /* Mark final consonants. A final consonant is one appearing after a matra. - * Happens in Sinhala. */ - for (unsigned int i = base + 1; i < end; i++) - if (info[i].indic_category() == OT_M) { - for (unsigned int j = i + 1; j < end; j++) - if (is_consonant (info[j])) { - info[j].indic_position() = POS_FINAL_C; - break; - } - break; - } - /* Handle beginning Ra */ if (has_reph) info[start].indic_position() = POS_RA_TO_BECOME_REPH; @@ -659,14 +676,14 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, { bool disallow_double_halants = buffer->props.script == HB_SCRIPT_KANNADA; for (unsigned int i = base + 1; i < end; i++) - if (info[i].indic_category() == OT_H) + if (info[i].indic_category() == I_Cat(H)) { unsigned int j; for (j = end - 1; j > i; j--) if (is_consonant (info[j]) || - (disallow_double_halants && info[j].indic_category() == OT_H)) + (disallow_double_halants && info[j].indic_category() == I_Cat(H))) break; - if (info[j].indic_category() != OT_H && j > i) { + if (info[j].indic_category() != I_Cat(H) && j > i) { /* Move Halant to after last consonant. */ hb_glyph_info_t t = info[i]; memmove (&info[i], &info[i + 1], (j - i) * sizeof (info[0])); @@ -681,20 +698,16 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, indic_position_t last_pos = POS_START; for (unsigned int i = start; i < end; i++) { - if ((FLAG_UNSAFE (info[i].indic_category()) & (JOINER_FLAGS | FLAG (OT_N) | FLAG (OT_RS) | MEDIAL_FLAGS | FLAG (OT_H)))) + if ((FLAG_UNSAFE (info[i].indic_category()) & (JOINER_FLAGS | FLAG (I_Cat(N)) | FLAG (I_Cat(RS)) | FLAG (I_Cat(CM)) | FLAG (I_Cat(H))))) { info[i].indic_position() = last_pos; - if (unlikely (info[i].indic_category() == OT_H && + if (unlikely (info[i].indic_category() == I_Cat(H) && info[i].indic_position() == POS_PRE_M)) { /* * Uniscribe doesn't move the Halant with Left Matra. - * TEST: U+092B,U+093F,U+094DE - * We follow. This is important for the Sinhala - * U+0DDA split matra since it decomposes to U+0DD9,U+0DCA - * where U+0DD9 is a left matra and U+0DCA is the virama. - * We don't want to move the virama with the left matra. - * TEST: U+0D9A,U+0DDA + * TEST: U+092B,U+093F,U+094D + * We follow. */ for (unsigned int j = i; j > start; j--) if (info[j - 1].indic_position() != POS_PRE_M) { @@ -718,7 +731,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, if (info[j].indic_position() < POS_SMVD) info[j].indic_position() = info[i].indic_position(); last = i; - } else if (info[i].indic_category() == OT_M) + } else if (info[i].indic_category() == I_Cat(M)) last = i; } @@ -849,10 +862,10 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, * Test case: U+0924,U+094D,U+0930,U+094d,U+200D,U+0915 */ for (unsigned int i = start; i + 1 < base; i++) - if (info[i ].indic_category() == OT_Ra && - info[i+1].indic_category() == OT_H && + if (info[i ].indic_category() == I_Cat(Ra) && + info[i+1].indic_category() == I_Cat(H) && (i + 2 == base || - info[i+2].indic_category() != OT_ZWJ)) + info[i+2].indic_category() != I_Cat(ZWJ))) { info[i ].mask |= indic_plan->mask_array[INDIC_BLWF]; info[i+1].mask |= indic_plan->mask_array[INDIC_BLWF]; @@ -879,7 +892,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, /* Apply ZWJ/ZWNJ effects */ for (unsigned int i = start + 1; i < end; i++) if (is_joiner (info[i])) { - bool non_joiner = info[i].indic_category() == OT_ZWNJ; + bool non_joiner = info[i].indic_category() == I_Cat(ZWNJ); unsigned int j = i; do { @@ -912,7 +925,7 @@ initial_reordering_standalone_cluster (const hb_ot_shape_plan_t *plan, /* For dotted-circle, this is what Uniscribe does: * If dotted-circle is the last glyph, it just does nothing. * Ie. It doesn't form Reph. */ - if (buffer->info[end - 1].indic_category() == OT_DOTTEDCIRCLE) + if (buffer->info[end - 1].indic_category() == I_Cat(DOTTEDCIRCLE)) return; } @@ -955,8 +968,8 @@ initial_reordering_indic (const hb_ot_shape_plan_t *plan, update_consonant_positions_indic (plan, font, buffer); hb_syllabic_insert_dotted_circles (font, buffer, indic_broken_cluster, - OT_DOTTEDCIRCLE, - OT_Repha, + I_Cat(DOTTEDCIRCLE), + I_Cat(Repha), POS_END); foreach_syllable (buffer, start, end) @@ -978,7 +991,7 @@ final_reordering_syllable_indic (const hb_ot_shape_plan_t *plan, * and possibly multiple substitutions happened prior to this * phase, and that might have messed up our properties. Recover * from a particular case of that where we're fairly sure that a - * class of OT_H is desired but has been lost. */ + * class of I_Cat(H) is desired but has been lost. */ /* We don't call load_virama_glyph(), since we know it's already * loaded. */ hb_codepoint_t virama_glyph = indic_plan->virama_glyph.get_relaxed (); @@ -990,7 +1003,7 @@ final_reordering_syllable_indic (const hb_ot_shape_plan_t *plan, _hb_glyph_info_multiplied (&info[i])) { /* This will make sure that this glyph passes is_halant() test. */ - info[i].indic_category() = OT_H; + info[i].indic_category() = I_Cat(H); _hb_glyph_info_clear_ligated_and_multiplied (&info[i]); } } @@ -1056,11 +1069,11 @@ final_reordering_syllable_indic (const hb_ot_shape_plan_t *plan, break; } if (base == end && start < base && - is_one_of (info[base - 1], FLAG (OT_ZWJ))) + is_one_of (info[base - 1], FLAG (I_Cat(ZWJ)))) base--; if (base < end) while (start < base && - is_one_of (info[base], (FLAG (OT_N) | FLAG (OT_H)))) + is_one_of (info[base], (FLAG (I_Cat(N)) | FLAG (I_Cat(H))))) base--; @@ -1105,7 +1118,7 @@ final_reordering_syllable_indic (const hb_ot_shape_plan_t *plan, { search: while (new_pos > start && - !(is_one_of (info[new_pos], (FLAG (OT_M) | FLAG (OT_H))))) + !(is_one_of (info[new_pos], (FLAG (I_Cat(M)) | FLAG (I_Cat(H)))))) new_pos--; /* If we found no Halant we are done. @@ -1122,7 +1135,7 @@ final_reordering_syllable_indic (const hb_ot_shape_plan_t *plan, if (new_pos + 1 < end) { /* -> If ZWJ follows this halant, matra is NOT repositioned after this halant. */ - if (info[new_pos + 1].indic_category() == OT_ZWJ) + if (info[new_pos + 1].indic_category() == I_Cat(ZWJ)) { /* Keep searching. */ if (new_pos > start) @@ -1195,7 +1208,7 @@ final_reordering_syllable_indic (const hb_ot_shape_plan_t *plan, */ if (start + 1 < end && info[start].indic_position() == POS_RA_TO_BECOME_REPH && - ((info[start].indic_category() == OT_Repha) ^ + ((info[start].indic_category() == I_Cat(Repha)) ^ _hb_glyph_info_ligated_and_didnt_multiply (&info[start]))) { unsigned int new_reph_pos; @@ -1305,7 +1318,7 @@ final_reordering_syllable_indic (const hb_ot_shape_plan_t *plan, unlikely (is_halant (info[new_reph_pos]))) { for (unsigned int i = base + 1; i < new_reph_pos; i++) - if (info[i].indic_category() == OT_M) { + if (info[i].indic_category() == I_Cat(M)) { /* Ok, got it. */ new_reph_pos--; } @@ -1365,7 +1378,7 @@ final_reordering_syllable_indic (const hb_ot_shape_plan_t *plan, if (buffer->props.script != HB_SCRIPT_MALAYALAM && buffer->props.script != HB_SCRIPT_TAMIL) { while (new_pos > start && - !(is_one_of (info[new_pos - 1], FLAG(OT_M) | FLAG (OT_H)))) + !(is_one_of (info[new_pos - 1], FLAG(I_Cat(M)) | FLAG (I_Cat(H))))) new_pos--; } @@ -1414,11 +1427,10 @@ final_reordering_syllable_indic (const hb_ot_shape_plan_t *plan, switch ((hb_tag_t) plan->props.script) { case HB_SCRIPT_TAMIL: - case HB_SCRIPT_SINHALA: break; default: - /* Uniscribe merges the entire syllable into a single cluster... Except for Tamil & Sinhala. + /* Uniscribe merges the entire syllable into a single cluster... Except for Tamil. * This means, half forms are submerged into the main consonant's cluster. * This is unnecessary, and makes cursor positioning harder, but that's what * Uniscribe does. */ @@ -1453,7 +1465,9 @@ preprocess_text_indic (const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer, hb_font_t *font) { - _hb_preprocess_text_vowel_constraints (plan, buffer, font); + const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data; + if (!indic_plan->uniscribe_bug_compatible) + _hb_preprocess_text_vowel_constraints (plan, buffer, font); } static bool @@ -1486,48 +1500,6 @@ decompose_indic (const hb_ot_shape_normalize_context_t *c, #endif } - if ((ab == 0x0DDAu || hb_in_range<hb_codepoint_t> (ab, 0x0DDCu, 0x0DDEu))) - { - /* - * Sinhala split matras... Let the fun begin. - * - * These four characters have Unicode decompositions. However, Uniscribe - * decomposes them "Khmer-style", that is, it uses the character itself to - * get the second half. The first half of all four decompositions is always - * U+0DD9. - * - * Now, there are buggy fonts, namely, the widely used lklug.ttf, that are - * broken with Uniscribe. But we need to support them. As such, we only - * do the Uniscribe-style decomposition if the character is transformed into - * its "sec.half" form by the 'pstf' feature. Otherwise, we fall back to - * Unicode decomposition. - * - * Note that we can't unconditionally use Unicode decomposition. That would - * break some other fonts, that are designed to work with Uniscribe, and - * don't have positioning features for the Unicode-style decomposition. - * - * Argh... - * - * The Uniscribe behavior is now documented in the newly published Sinhala - * spec in 2012: - * - * https://docs.microsoft.com/en-us/typography/script-development/sinhala#shaping - */ - - - const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) c->plan->data; - hb_codepoint_t glyph; - if (indic_plan->uniscribe_bug_compatible || - (c->font->get_nominal_glyph (ab, &glyph) && - indic_plan->pstf.would_substitute (&glyph, 1, c->font->face))) - { - /* Ok, safe to use Uniscribe-style decomposition. */ - *a = 0x0DD9u; - *b = ab; - return true; - } - } - return (bool) c->unicode->decompose (ab, a, b); } @@ -1548,7 +1520,7 @@ compose_indic (const hb_ot_shape_normalize_context_t *c, } -const hb_ot_complex_shaper_t _hb_ot_complex_shaper_indic = +const hb_ot_shaper_t _hb_ot_shaper_indic = { collect_features_indic, override_features_indic, diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-indic.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-indic.hh new file mode 100644 index 0000000000..4f822c26e9 --- /dev/null +++ b/thirdparty/harfbuzz/src/hb-ot-shaper-indic.hh @@ -0,0 +1,66 @@ +/* + * Copyright © 2012 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_OT_SHAPER_INDIC_HH +#define HB_OT_SHAPER_INDIC_HH + +#include "hb.hh" + +#include "hb-ot-shaper-syllabic.hh" + + +/* Visual positions in a syllable from left to right. */ +enum ot_position_t { + POS_START = 0, + + POS_RA_TO_BECOME_REPH = 1, + POS_PRE_M = 2, + POS_PRE_C = 3, + + POS_BASE_C = 4, + POS_AFTER_MAIN = 5, + + POS_ABOVE_C = 6, + + POS_BEFORE_SUB = 7, + POS_BELOW_C = 8, + POS_AFTER_SUB = 9, + + POS_BEFORE_POST = 10, + POS_POST_C = 11, + POS_AFTER_POST = 12, + + POS_SMVD = 13, + + POS_END = 14 +}; + + +HB_INTERNAL uint16_t +hb_indic_get_categories (hb_codepoint_t u); + + +#endif /* HB_OT_SHAPER_INDIC_HH */ diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-khmer-machine.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-khmer-machine.hh new file mode 100644 index 0000000000..e18bd75ef1 --- /dev/null +++ b/thirdparty/harfbuzz/src/hb-ot-shaper-khmer-machine.hh @@ -0,0 +1,428 @@ + +#line 1 "hb-ot-shaper-khmer-machine.rl" +/* + * Copyright © 2011,2012 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_OT_SHAPER_KHMER_MACHINE_HH +#define HB_OT_SHAPER_KHMER_MACHINE_HH + +#include "hb.hh" + +#include "hb-ot-layout.hh" +#include "hb-ot-shaper-indic.hh" + +/* buffer var allocations */ +#define khmer_category() ot_shaper_var_u8_category() /* khmer_category_t */ + +using khmer_category_t = unsigned; + +#define K_Cat(Cat) khmer_syllable_machine_ex_##Cat + +enum khmer_syllable_type_t { + khmer_consonant_syllable, + khmer_broken_cluster, + khmer_non_khmer_cluster, +}; + + +#line 52 "hb-ot-shaper-khmer-machine.hh" +#define khmer_syllable_machine_ex_C 1u +#define khmer_syllable_machine_ex_DOTTEDCIRCLE 11u +#define khmer_syllable_machine_ex_H 4u +#define khmer_syllable_machine_ex_PLACEHOLDER 10u +#define khmer_syllable_machine_ex_Ra 15u +#define khmer_syllable_machine_ex_Robatic 25u +#define khmer_syllable_machine_ex_V 2u +#define khmer_syllable_machine_ex_VAbv 20u +#define khmer_syllable_machine_ex_VBlw 21u +#define khmer_syllable_machine_ex_VPre 22u +#define khmer_syllable_machine_ex_VPst 23u +#define khmer_syllable_machine_ex_Xgroup 26u +#define khmer_syllable_machine_ex_Ygroup 27u +#define khmer_syllable_machine_ex_ZWJ 6u +#define khmer_syllable_machine_ex_ZWNJ 5u + + +#line 70 "hb-ot-shaper-khmer-machine.hh" +static const unsigned char _khmer_syllable_machine_trans_keys[] = { + 5u, 26u, 5u, 26u, 1u, 15u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, + 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 1u, 15u, 5u, 26u, 5u, 26u, + 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 1u, 27u, 4u, 27u, 1u, 15u, + 4u, 27u, 4u, 27u, 27u, 27u, 4u, 27u, 4u, 27u, 4u, 27u, 4u, 27u, 4u, 27u, + 4u, 27u, 1u, 15u, 4u, 27u, 4u, 27u, 27u, 27u, 4u, 27u, 4u, 27u, 4u, 27u, + 4u, 27u, 4u, 27u, 5u, 26u, 0 +}; + +static const char _khmer_syllable_machine_key_spans[] = { + 22, 22, 15, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 15, 22, 22, + 22, 22, 22, 22, 22, 27, 24, 15, + 24, 24, 1, 24, 24, 24, 24, 24, + 24, 15, 24, 24, 1, 24, 24, 24, + 24, 24, 22 +}; + +static const short _khmer_syllable_machine_index_offsets[] = { + 0, 23, 46, 62, 85, 108, 131, 154, + 177, 200, 223, 246, 269, 292, 308, 331, + 354, 377, 400, 423, 446, 469, 497, 522, + 538, 563, 588, 590, 615, 640, 665, 690, + 715, 740, 756, 781, 806, 808, 833, 858, + 883, 908, 933 +}; + +static const char _khmer_syllable_machine_indicies[] = { + 1, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 2, + 0, 0, 0, 0, 3, 4, 0, 1, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 4, 0, 5, 5, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 5, 0, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 2, 0, 0, + 0, 0, 0, 4, 0, 6, 6, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2, 0, 7, 7, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 8, 0, 9, 9, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2, 0, 0, 0, 0, 0, + 10, 0, 9, 9, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 10, + 0, 11, 11, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 2, 0, 0, 0, 0, 0, 12, 0, + 11, 11, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 12, 0, 1, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 2, 0, + 0, 0, 0, 13, 4, 0, 15, 15, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 16, 14, 14, + 14, 14, 17, 18, 14, 15, 15, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 18, 19, 20, 20, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 20, 14, 15, 15, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 16, 14, 14, 14, 14, + 14, 18, 14, 21, 21, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 16, 14, 22, 22, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 23, + 14, 24, 24, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 16, 14, 14, 14, 14, 14, 25, 14, + 24, 24, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 25, 14, 26, + 26, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 16, 14, + 14, 14, 14, 14, 27, 14, 26, 26, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 27, 14, 29, 29, 28, + 30, 31, 31, 28, 28, 28, 13, 13, + 28, 28, 28, 29, 28, 28, 28, 28, + 16, 25, 27, 23, 28, 17, 18, 20, + 28, 33, 34, 34, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, + 32, 2, 10, 12, 8, 32, 13, 4, + 5, 32, 35, 35, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, + 35, 32, 33, 36, 36, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 2, 10, 12, 8, 32, 3, + 4, 5, 32, 37, 38, 38, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 2, 10, 12, 8, 32, + 32, 4, 5, 32, 5, 32, 37, 6, + 6, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, + 32, 8, 32, 32, 2, 5, 32, 37, + 7, 7, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 8, 5, 32, + 37, 39, 39, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, + 2, 32, 32, 8, 32, 32, 10, 5, + 32, 37, 40, 40, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, + 32, 2, 10, 32, 8, 32, 32, 12, + 5, 32, 33, 38, 38, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 2, 10, 12, 8, 32, 32, + 4, 5, 32, 33, 38, 38, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 2, 10, 12, 8, 32, + 3, 4, 5, 32, 42, 42, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 42, 41, 30, 43, 43, 41, + 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 16, 25, 27, 23, + 41, 17, 18, 20, 41, 44, 45, 45, + 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 16, 25, 27, + 23, 41, 41, 18, 20, 41, 20, 41, + 44, 21, 21, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 23, 41, 41, 16, 20, + 41, 44, 22, 22, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 23, + 20, 41, 44, 46, 46, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 16, 41, 41, 23, 41, 41, + 25, 20, 41, 44, 47, 47, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 16, 25, 41, 23, 41, + 41, 27, 20, 41, 30, 45, 45, 41, + 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 16, 25, 27, 23, + 41, 41, 18, 20, 41, 15, 15, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 16, 48, 48, 48, + 48, 48, 18, 48, 0 +}; + +static const char _khmer_syllable_machine_trans_targs[] = { + 21, 1, 27, 31, 25, 26, 4, 5, + 28, 7, 29, 9, 30, 32, 21, 12, + 37, 41, 35, 21, 36, 15, 16, 38, + 18, 39, 20, 40, 21, 22, 33, 42, + 21, 23, 10, 24, 0, 2, 3, 6, + 8, 21, 34, 11, 13, 14, 17, 19, + 21 +}; + +static const char _khmer_syllable_machine_trans_actions[] = { + 1, 0, 2, 2, 2, 0, 0, 0, + 2, 0, 2, 0, 2, 2, 3, 0, + 2, 4, 4, 5, 0, 0, 0, 2, + 0, 2, 0, 2, 8, 2, 0, 9, + 10, 0, 0, 2, 0, 0, 0, 0, + 0, 11, 4, 0, 0, 0, 0, 0, + 12 +}; + +static const char _khmer_syllable_machine_to_state_actions[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 6, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0 +}; + +static const char _khmer_syllable_machine_from_state_actions[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 7, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0 +}; + +static const short _khmer_syllable_machine_eof_trans[] = { + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 15, 20, 15, 15, 15, + 15, 15, 15, 15, 15, 0, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, + 33, 42, 42, 42, 42, 42, 42, 42, + 42, 42, 49 +}; + +static const int khmer_syllable_machine_start = 21; +static const int khmer_syllable_machine_first_final = 21; +static const int khmer_syllable_machine_error = -1; + +static const int khmer_syllable_machine_en_main = 21; + + +#line 53 "hb-ot-shaper-khmer-machine.rl" + + + +#line 102 "hb-ot-shaper-khmer-machine.rl" + + +#define found_syllable(syllable_type) \ + HB_STMT_START { \ + if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \ + for (unsigned int i = ts; i < te; i++) \ + info[i].syllable() = (syllable_serial << 4) | syllable_type; \ + syllable_serial++; \ + if (unlikely (syllable_serial == 16)) syllable_serial = 1; \ + } HB_STMT_END + +inline void +find_syllables_khmer (hb_buffer_t *buffer) +{ + unsigned int p, pe, eof, ts, te, act HB_UNUSED; + int cs; + hb_glyph_info_t *info = buffer->info; + +#line 298 "hb-ot-shaper-khmer-machine.hh" + { + cs = khmer_syllable_machine_start; + ts = 0; + te = 0; + act = 0; + } + +#line 122 "hb-ot-shaper-khmer-machine.rl" + + + p = 0; + pe = eof = buffer->len; + + unsigned int syllable_serial = 1; + +#line 314 "hb-ot-shaper-khmer-machine.hh" + { + int _slen; + int _trans; + const unsigned char *_keys; + const char *_inds; + if ( p == pe ) + goto _test_eof; +_resume: + switch ( _khmer_syllable_machine_from_state_actions[cs] ) { + case 7: +#line 1 "NONE" + {ts = p;} + break; +#line 328 "hb-ot-shaper-khmer-machine.hh" + } + + _keys = _khmer_syllable_machine_trans_keys + (cs<<1); + _inds = _khmer_syllable_machine_indicies + _khmer_syllable_machine_index_offsets[cs]; + + _slen = _khmer_syllable_machine_key_spans[cs]; + _trans = _inds[ _slen > 0 && _keys[0] <=( info[p].khmer_category()) && + ( info[p].khmer_category()) <= _keys[1] ? + ( info[p].khmer_category()) - _keys[0] : _slen ]; + +_eof_trans: + cs = _khmer_syllable_machine_trans_targs[_trans]; + + if ( _khmer_syllable_machine_trans_actions[_trans] == 0 ) + goto _again; + + switch ( _khmer_syllable_machine_trans_actions[_trans] ) { + case 2: +#line 1 "NONE" + {te = p+1;} + break; + case 8: +#line 98 "hb-ot-shaper-khmer-machine.rl" + {te = p+1;{ found_syllable (khmer_non_khmer_cluster); }} + break; + case 10: +#line 96 "hb-ot-shaper-khmer-machine.rl" + {te = p;p--;{ found_syllable (khmer_consonant_syllable); }} + break; + case 11: +#line 97 "hb-ot-shaper-khmer-machine.rl" + {te = p;p--;{ found_syllable (khmer_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; }} + break; + case 12: +#line 98 "hb-ot-shaper-khmer-machine.rl" + {te = p;p--;{ found_syllable (khmer_non_khmer_cluster); }} + break; + case 1: +#line 96 "hb-ot-shaper-khmer-machine.rl" + {{p = ((te))-1;}{ found_syllable (khmer_consonant_syllable); }} + break; + case 3: +#line 97 "hb-ot-shaper-khmer-machine.rl" + {{p = ((te))-1;}{ found_syllable (khmer_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; }} + break; + case 5: +#line 1 "NONE" + { switch( act ) { + case 2: + {{p = ((te))-1;} found_syllable (khmer_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; } + break; + case 3: + {{p = ((te))-1;} found_syllable (khmer_non_khmer_cluster); } + break; + } + } + break; + case 4: +#line 1 "NONE" + {te = p+1;} +#line 97 "hb-ot-shaper-khmer-machine.rl" + {act = 2;} + break; + case 9: +#line 1 "NONE" + {te = p+1;} +#line 98 "hb-ot-shaper-khmer-machine.rl" + {act = 3;} + break; +#line 398 "hb-ot-shaper-khmer-machine.hh" + } + +_again: + switch ( _khmer_syllable_machine_to_state_actions[cs] ) { + case 6: +#line 1 "NONE" + {ts = 0;} + break; +#line 407 "hb-ot-shaper-khmer-machine.hh" + } + + if ( ++p != pe ) + goto _resume; + _test_eof: {} + if ( p == eof ) + { + if ( _khmer_syllable_machine_eof_trans[cs] > 0 ) { + _trans = _khmer_syllable_machine_eof_trans[cs] - 1; + goto _eof_trans; + } + } + + } + +#line 130 "hb-ot-shaper-khmer-machine.rl" + +} + +#undef found_syllable + +#endif /* HB_OT_SHAPER_KHMER_MACHINE_HH */ diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer.cc b/thirdparty/harfbuzz/src/hb-ot-shaper-khmer.cc index d7ec1632ea..e04d633195 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer.cc +++ b/thirdparty/harfbuzz/src/hb-ot-shaper-khmer.cc @@ -28,8 +28,8 @@ #ifndef HB_NO_OT_SHAPE -#include "hb-ot-shape-complex-khmer.hh" -#include "hb-ot-shape-complex-khmer-machine.hh" +#include "hb-ot-shaper-khmer-machine.hh" +#include "hb-ot-shaper-indic.hh" #include "hb-ot-layout.hh" @@ -37,6 +37,7 @@ * Khmer shaper. */ + static const hb_ot_map_feature_t khmer_features[] = { @@ -79,6 +80,15 @@ enum { KHMER_BASIC_FEATURES = _KHMER_PRES, /* Don't forget to update this! */ }; +static inline void +set_khmer_properties (hb_glyph_info_t &info) +{ + hb_codepoint_t u = info.codepoint; + unsigned int type = hb_indic_get_categories (u); + + info.khmer_category() = (khmer_category_t) (type & 0xFFu); +} + static void setup_syllables_khmer (const hb_ot_shape_plan_t *plan, hb_font_t *font, @@ -110,7 +120,14 @@ collect_features_khmer (hb_ot_shape_planner_t *plan) map->enable_feature (HB_TAG('l','o','c','l'), F_PER_SYLLABLE); map->enable_feature (HB_TAG('c','c','m','p'), F_PER_SYLLABLE); - for (unsigned i = 0; i < KHMER_NUM_FEATURES; i++) + unsigned int i = 0; + for (; i < KHMER_BASIC_FEATURES; i++) + map->add_feature (khmer_features[i]); + + /* https://github.com/harfbuzz/harfbuzz/issues/3531 */ + map->add_gsub_pause (hb_syllabic_clear_var); // Don't need syllables anymore, use stop to free buffer var + + for (; i < KHMER_NUM_FEATURES; i++) map->add_feature (khmer_features[i]); } @@ -180,6 +197,7 @@ setup_syllables_khmer (const hb_ot_shape_plan_t *plan HB_UNUSED, hb_font_t *font HB_UNUSED, hb_buffer_t *buffer) { + HB_BUFFER_ALLOCATE_VAR (buffer, syllable); find_syllables_khmer (buffer); foreach_syllable (buffer, start, end) buffer->unsafe_to_break (start, end); @@ -223,11 +241,11 @@ reorder_consonant_syllable (const hb_ot_shape_plan_t *plan, * the 'pref' OpenType feature applied to them. * """ */ - if (info[i].khmer_category() == OT_Coeng && num_coengs <= 2 && i + 1 < end) + if (info[i].khmer_category() == K_Cat(H) && num_coengs <= 2 && i + 1 < end) { num_coengs++; - if (info[i + 1].khmer_category() == OT_Ra) + if (info[i + 1].khmer_category() == K_Cat(Ra)) { for (unsigned int j = 0; j < 2; j++) info[i + j].mask |= khmer_plan->mask_array[KHMER_PREF]; @@ -255,7 +273,7 @@ reorder_consonant_syllable (const hb_ot_shape_plan_t *plan, } /* Reorder left matra piece. */ - else if (info[i].khmer_category() == OT_VPre) + else if (info[i].khmer_category() == K_Cat(VPre)) { /* Move to the start. */ buffer->merge_clusters (start, i + 1); @@ -294,8 +312,8 @@ reorder_khmer (const hb_ot_shape_plan_t *plan, { hb_syllabic_insert_dotted_circles (font, buffer, khmer_broken_cluster, - OT_DOTTEDCIRCLE, - OT_Repha); + K_Cat(DOTTEDCIRCLE), + (unsigned) -1); foreach_syllable (buffer, start, end) reorder_syllable_khmer (plan, font->face, buffer, start, end); @@ -342,7 +360,7 @@ compose_khmer (const hb_ot_shape_normalize_context_t *c, } -const hb_ot_complex_shaper_t _hb_ot_complex_shaper_khmer = +const hb_ot_shaper_t _hb_ot_shaper_khmer = { collect_features_khmer, override_features_khmer, diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-myanmar-machine.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-myanmar-machine.hh new file mode 100644 index 0000000000..b109708937 --- /dev/null +++ b/thirdparty/harfbuzz/src/hb-ot-shaper-myanmar-machine.hh @@ -0,0 +1,553 @@ + +#line 1 "hb-ot-shaper-myanmar-machine.rl" +/* + * Copyright © 2011,2012 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_OT_SHAPER_MYANMAR_MACHINE_HH +#define HB_OT_SHAPER_MYANMAR_MACHINE_HH + +#include "hb.hh" + +#include "hb-ot-layout.hh" +#include "hb-ot-shaper-indic.hh" + +/* buffer var allocations */ +#define myanmar_category() ot_shaper_var_u8_category() /* myanmar_category_t */ +#define myanmar_position() ot_shaper_var_u8_auxiliary() /* myanmar_position_t */ + +using myanmar_category_t = unsigned; +using myanmar_position_t = ot_position_t; + +#define M_Cat(Cat) myanmar_syllable_machine_ex_##Cat + +enum myanmar_syllable_type_t { + myanmar_consonant_syllable, + myanmar_broken_cluster, + myanmar_non_myanmar_cluster, +}; + + +#line 54 "hb-ot-shaper-myanmar-machine.hh" +#define myanmar_syllable_machine_ex_A 9u +#define myanmar_syllable_machine_ex_As 32u +#define myanmar_syllable_machine_ex_C 1u +#define myanmar_syllable_machine_ex_CS 18u +#define myanmar_syllable_machine_ex_DB 3u +#define myanmar_syllable_machine_ex_DOTTEDCIRCLE 11u +#define myanmar_syllable_machine_ex_GB 10u +#define myanmar_syllable_machine_ex_H 4u +#define myanmar_syllable_machine_ex_IV 2u +#define myanmar_syllable_machine_ex_MH 35u +#define myanmar_syllable_machine_ex_ML 41u +#define myanmar_syllable_machine_ex_MR 36u +#define myanmar_syllable_machine_ex_MW 37u +#define myanmar_syllable_machine_ex_MY 38u +#define myanmar_syllable_machine_ex_PT 39u +#define myanmar_syllable_machine_ex_Ra 15u +#define myanmar_syllable_machine_ex_SM 8u +#define myanmar_syllable_machine_ex_VAbv 20u +#define myanmar_syllable_machine_ex_VBlw 21u +#define myanmar_syllable_machine_ex_VPre 22u +#define myanmar_syllable_machine_ex_VPst 23u +#define myanmar_syllable_machine_ex_VS 40u +#define myanmar_syllable_machine_ex_ZWJ 6u +#define myanmar_syllable_machine_ex_ZWNJ 5u + + +#line 81 "hb-ot-shaper-myanmar-machine.hh" +static const unsigned char _myanmar_syllable_machine_trans_keys[] = { + 1u, 41u, 3u, 41u, 5u, 39u, 5u, 8u, 3u, 41u, 3u, 39u, 3u, 39u, 5u, 39u, + 5u, 39u, 3u, 39u, 3u, 39u, 3u, 41u, 5u, 39u, 1u, 15u, 3u, 39u, 3u, 39u, + 3u, 40u, 3u, 39u, 3u, 41u, 3u, 41u, 3u, 39u, 3u, 41u, 3u, 41u, 3u, 41u, + 3u, 41u, 3u, 41u, 5u, 39u, 5u, 8u, 3u, 41u, 3u, 39u, 3u, 39u, 5u, 39u, + 5u, 39u, 3u, 39u, 3u, 39u, 3u, 41u, 5u, 39u, 1u, 15u, 3u, 41u, 3u, 39u, + 3u, 39u, 3u, 40u, 3u, 39u, 3u, 41u, 3u, 41u, 3u, 39u, 3u, 41u, 3u, 41u, + 3u, 41u, 3u, 41u, 3u, 41u, 3u, 41u, 3u, 41u, 1u, 41u, 1u, 15u, 0 +}; + +static const char _myanmar_syllable_machine_key_spans[] = { + 41, 39, 35, 4, 39, 37, 37, 35, + 35, 37, 37, 39, 35, 15, 37, 37, + 38, 37, 39, 39, 37, 39, 39, 39, + 39, 39, 35, 4, 39, 37, 37, 35, + 35, 37, 37, 39, 35, 15, 39, 37, + 37, 38, 37, 39, 39, 37, 39, 39, + 39, 39, 39, 39, 39, 41, 15 +}; + +static const short _myanmar_syllable_machine_index_offsets[] = { + 0, 42, 82, 118, 123, 163, 201, 239, + 275, 311, 349, 387, 427, 463, 479, 517, + 555, 594, 632, 672, 712, 750, 790, 830, + 870, 910, 950, 986, 991, 1031, 1069, 1107, + 1143, 1179, 1217, 1255, 1295, 1331, 1347, 1387, + 1425, 1463, 1502, 1540, 1580, 1620, 1658, 1698, + 1738, 1778, 1818, 1858, 1898, 1938, 1980 +}; + +static const char _myanmar_syllable_machine_indicies[] = { + 1, 1, 2, 3, 4, 4, 0, 5, + 6, 1, 1, 0, 0, 0, 7, 0, + 0, 8, 0, 9, 10, 11, 12, 0, + 0, 0, 0, 0, 0, 0, 0, 13, + 0, 0, 14, 15, 16, 17, 18, 19, + 20, 0, 22, 23, 24, 24, 21, 25, + 26, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 27, 28, 29, 30, 21, + 21, 21, 21, 21, 21, 21, 21, 31, + 21, 21, 32, 33, 34, 35, 36, 37, + 38, 21, 24, 24, 21, 25, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 30, 21, 21, 21, + 21, 21, 21, 21, 21, 39, 21, 21, + 21, 21, 21, 21, 36, 21, 24, 24, + 21, 25, 21, 22, 21, 24, 24, 21, + 25, 26, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 40, 21, 21, 30, + 21, 21, 21, 21, 21, 21, 21, 21, + 41, 21, 21, 42, 21, 21, 21, 36, + 21, 41, 21, 22, 21, 24, 24, 21, + 25, 26, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 30, + 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 36, + 21, 43, 21, 24, 24, 21, 25, 36, + 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 44, 21, + 21, 21, 21, 21, 21, 36, 21, 24, + 24, 21, 25, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 44, 21, 21, 21, 21, 21, + 21, 36, 21, 24, 24, 21, 25, 21, + 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 36, 21, 22, + 21, 24, 24, 21, 25, 26, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, + 40, 21, 21, 30, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 36, 21, 22, 21, 24, + 24, 21, 25, 26, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 40, 21, + 21, 30, 21, 21, 21, 21, 21, 21, + 21, 21, 41, 21, 21, 21, 21, 21, + 21, 36, 21, 22, 21, 24, 24, 21, + 25, 26, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 40, 21, 21, 30, + 21, 21, 21, 21, 21, 21, 21, 21, + 41, 21, 21, 21, 21, 21, 21, 36, + 21, 41, 21, 24, 24, 21, 25, 21, + 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 30, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 36, 21, 1, + 1, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 1, 21, 22, + 21, 24, 24, 21, 25, 26, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, + 27, 28, 21, 30, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 36, 21, 22, 21, 24, + 24, 21, 25, 26, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 28, + 21, 30, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, + 21, 36, 21, 22, 21, 24, 24, 21, + 25, 26, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 27, 28, 29, 30, + 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 36, + 45, 21, 22, 21, 24, 24, 21, 25, + 26, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 27, 28, 29, 30, 21, + 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 36, 21, + 22, 21, 24, 24, 21, 25, 26, 21, + 21, 21, 21, 21, 21, 21, 21, 21, + 21, 27, 28, 29, 30, 21, 21, 21, + 21, 21, 21, 21, 21, 31, 21, 21, + 32, 33, 34, 35, 36, 21, 38, 21, + 22, 21, 24, 24, 21, 25, 26, 21, + 21, 21, 21, 21, 21, 21, 21, 21, + 21, 27, 28, 29, 30, 21, 21, 21, + 21, 21, 21, 21, 21, 45, 21, 21, + 21, 21, 21, 21, 36, 21, 38, 21, + 22, 21, 24, 24, 21, 25, 26, 21, + 21, 21, 21, 21, 21, 21, 21, 21, + 21, 27, 28, 29, 30, 21, 21, 21, + 21, 21, 21, 21, 21, 45, 21, 21, + 21, 21, 21, 21, 36, 21, 22, 21, + 24, 24, 21, 25, 26, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 27, + 28, 29, 30, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 32, 21, + 34, 21, 36, 21, 38, 21, 22, 21, + 24, 24, 21, 25, 26, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 27, + 28, 29, 30, 21, 21, 21, 21, 21, + 21, 21, 21, 45, 21, 21, 32, 21, + 21, 21, 36, 21, 38, 21, 22, 21, + 24, 24, 21, 25, 26, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 27, + 28, 29, 30, 21, 21, 21, 21, 21, + 21, 21, 21, 46, 21, 21, 32, 33, + 34, 21, 36, 21, 38, 21, 22, 21, + 24, 24, 21, 25, 26, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 27, + 28, 29, 30, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 32, 33, + 34, 21, 36, 21, 38, 21, 22, 23, + 24, 24, 21, 25, 26, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 27, + 28, 29, 30, 21, 21, 21, 21, 21, + 21, 21, 21, 31, 21, 21, 32, 33, + 34, 35, 36, 21, 38, 21, 48, 48, + 47, 5, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, + 12, 47, 47, 47, 47, 47, 47, 47, + 47, 49, 47, 47, 47, 47, 47, 47, + 18, 47, 48, 48, 47, 5, 47, 2, + 47, 48, 48, 47, 5, 6, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, + 50, 47, 47, 12, 47, 47, 47, 47, + 47, 47, 47, 47, 51, 47, 47, 52, + 47, 47, 47, 18, 47, 51, 47, 2, + 47, 48, 48, 47, 5, 6, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 12, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 18, 47, 53, 47, 48, + 48, 47, 5, 18, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 54, 47, 47, 47, 47, 47, + 47, 18, 47, 48, 48, 47, 5, 47, + 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 54, 47, + 47, 47, 47, 47, 47, 18, 47, 48, + 48, 47, 5, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, + 47, 18, 47, 2, 47, 48, 48, 47, + 5, 6, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 50, 47, 47, 12, + 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 18, + 47, 2, 47, 48, 48, 47, 5, 6, + 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 50, 47, 47, 12, 47, 47, + 47, 47, 47, 47, 47, 47, 51, 47, + 47, 47, 47, 47, 47, 18, 47, 2, + 47, 48, 48, 47, 5, 6, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, + 50, 47, 47, 12, 47, 47, 47, 47, + 47, 47, 47, 47, 51, 47, 47, 47, + 47, 47, 47, 18, 47, 51, 47, 48, + 48, 47, 5, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, + 47, 12, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, + 47, 18, 47, 55, 55, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, + 47, 55, 47, 2, 3, 48, 48, 47, + 5, 6, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 9, 10, 11, 12, + 47, 47, 47, 47, 47, 47, 47, 47, + 13, 47, 47, 14, 15, 16, 17, 18, + 19, 20, 47, 2, 47, 48, 48, 47, + 5, 6, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 9, 10, 47, 12, + 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 18, + 47, 2, 47, 48, 48, 47, 5, 6, + 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 10, 47, 12, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 18, 47, 2, + 47, 48, 48, 47, 5, 6, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, + 9, 10, 11, 12, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 18, 56, 47, 2, 47, + 48, 48, 47, 5, 6, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 9, + 10, 11, 12, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 18, 47, 2, 47, 48, 48, + 47, 5, 6, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 9, 10, 11, + 12, 47, 47, 47, 47, 47, 47, 47, + 47, 13, 47, 47, 14, 15, 16, 17, + 18, 47, 20, 47, 2, 47, 48, 48, + 47, 5, 6, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 9, 10, 11, + 12, 47, 47, 47, 47, 47, 47, 47, + 47, 56, 47, 47, 47, 47, 47, 47, + 18, 47, 20, 47, 2, 47, 48, 48, + 47, 5, 6, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 9, 10, 11, + 12, 47, 47, 47, 47, 47, 47, 47, + 47, 56, 47, 47, 47, 47, 47, 47, + 18, 47, 2, 47, 48, 48, 47, 5, + 6, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 9, 10, 11, 12, 47, + 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 14, 47, 16, 47, 18, 47, + 20, 47, 2, 47, 48, 48, 47, 5, + 6, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 9, 10, 11, 12, 47, + 47, 47, 47, 47, 47, 47, 47, 56, + 47, 47, 14, 47, 47, 47, 18, 47, + 20, 47, 2, 47, 48, 48, 47, 5, + 6, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 9, 10, 11, 12, 47, + 47, 47, 47, 47, 47, 47, 47, 57, + 47, 47, 14, 15, 16, 47, 18, 47, + 20, 47, 2, 47, 48, 48, 47, 5, + 6, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 9, 10, 11, 12, 47, + 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 14, 15, 16, 47, 18, 47, + 20, 47, 2, 3, 48, 48, 47, 5, + 6, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 9, 10, 11, 12, 47, + 47, 47, 47, 47, 47, 47, 47, 13, + 47, 47, 14, 15, 16, 17, 18, 47, + 20, 47, 22, 23, 24, 24, 21, 25, + 26, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 27, 28, 29, 30, 21, + 21, 21, 21, 21, 21, 21, 21, 58, + 21, 21, 32, 33, 34, 35, 36, 37, + 38, 21, 22, 59, 24, 24, 21, 25, + 26, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 27, 28, 29, 30, 21, + 21, 21, 21, 21, 21, 21, 21, 31, + 21, 21, 32, 33, 34, 35, 36, 21, + 38, 21, 1, 1, 2, 3, 48, 48, + 47, 5, 6, 1, 1, 47, 47, 47, + 1, 47, 47, 47, 47, 9, 10, 11, + 12, 47, 47, 47, 47, 47, 47, 47, + 47, 13, 47, 47, 14, 15, 16, 17, + 18, 19, 20, 47, 1, 1, 60, 60, + 60, 60, 60, 60, 60, 1, 1, 60, + 60, 60, 1, 60, 0 +}; + +static const char _myanmar_syllable_machine_trans_targs[] = { + 0, 1, 26, 37, 0, 27, 29, 51, + 54, 39, 40, 41, 28, 43, 44, 46, + 47, 48, 30, 50, 45, 0, 2, 13, + 0, 3, 5, 14, 15, 16, 4, 18, + 19, 21, 22, 23, 6, 25, 20, 12, + 9, 10, 11, 7, 8, 17, 24, 0, + 0, 36, 33, 34, 35, 31, 32, 38, + 42, 49, 52, 53, 0 +}; + +static const char _myanmar_syllable_machine_trans_actions[] = { + 3, 0, 0, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 5, 0, 0, + 6, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 7, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 9 +}; + +static const char _myanmar_syllable_machine_to_state_actions[] = { + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0 +}; + +static const char _myanmar_syllable_machine_from_state_actions[] = { + 2, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0 +}; + +static const short _myanmar_syllable_machine_eof_trans[] = { + 0, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 22, 22, 48, 61 +}; + +static const int myanmar_syllable_machine_start = 0; +static const int myanmar_syllable_machine_first_final = 0; +static const int myanmar_syllable_machine_error = -1; + +static const int myanmar_syllable_machine_en_main = 0; + + +#line 55 "hb-ot-shaper-myanmar-machine.rl" + + + +#line 117 "hb-ot-shaper-myanmar-machine.rl" + + +#define found_syllable(syllable_type) \ + HB_STMT_START { \ + if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \ + for (unsigned int i = ts; i < te; i++) \ + info[i].syllable() = (syllable_serial << 4) | syllable_type; \ + syllable_serial++; \ + if (unlikely (syllable_serial == 16)) syllable_serial = 1; \ + } HB_STMT_END + +inline void +find_syllables_myanmar (hb_buffer_t *buffer) +{ + unsigned int p, pe, eof, ts, te, act HB_UNUSED; + int cs; + hb_glyph_info_t *info = buffer->info; + +#line 447 "hb-ot-shaper-myanmar-machine.hh" + { + cs = myanmar_syllable_machine_start; + ts = 0; + te = 0; + act = 0; + } + +#line 137 "hb-ot-shaper-myanmar-machine.rl" + + + p = 0; + pe = eof = buffer->len; + + unsigned int syllable_serial = 1; + +#line 463 "hb-ot-shaper-myanmar-machine.hh" + { + int _slen; + int _trans; + const unsigned char *_keys; + const char *_inds; + if ( p == pe ) + goto _test_eof; +_resume: + switch ( _myanmar_syllable_machine_from_state_actions[cs] ) { + case 2: +#line 1 "NONE" + {ts = p;} + break; +#line 477 "hb-ot-shaper-myanmar-machine.hh" + } + + _keys = _myanmar_syllable_machine_trans_keys + (cs<<1); + _inds = _myanmar_syllable_machine_indicies + _myanmar_syllable_machine_index_offsets[cs]; + + _slen = _myanmar_syllable_machine_key_spans[cs]; + _trans = _inds[ _slen > 0 && _keys[0] <=( info[p].myanmar_category()) && + ( info[p].myanmar_category()) <= _keys[1] ? + ( info[p].myanmar_category()) - _keys[0] : _slen ]; + +_eof_trans: + cs = _myanmar_syllable_machine_trans_targs[_trans]; + + if ( _myanmar_syllable_machine_trans_actions[_trans] == 0 ) + goto _again; + + switch ( _myanmar_syllable_machine_trans_actions[_trans] ) { + case 6: +#line 110 "hb-ot-shaper-myanmar-machine.rl" + {te = p+1;{ found_syllable (myanmar_consonant_syllable); }} + break; + case 4: +#line 111 "hb-ot-shaper-myanmar-machine.rl" + {te = p+1;{ found_syllable (myanmar_non_myanmar_cluster); }} + break; + case 8: +#line 112 "hb-ot-shaper-myanmar-machine.rl" + {te = p+1;{ found_syllable (myanmar_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; }} + break; + case 3: +#line 113 "hb-ot-shaper-myanmar-machine.rl" + {te = p+1;{ found_syllable (myanmar_non_myanmar_cluster); }} + break; + case 5: +#line 110 "hb-ot-shaper-myanmar-machine.rl" + {te = p;p--;{ found_syllable (myanmar_consonant_syllable); }} + break; + case 7: +#line 112 "hb-ot-shaper-myanmar-machine.rl" + {te = p;p--;{ found_syllable (myanmar_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; }} + break; + case 9: +#line 113 "hb-ot-shaper-myanmar-machine.rl" + {te = p;p--;{ found_syllable (myanmar_non_myanmar_cluster); }} + break; +#line 523 "hb-ot-shaper-myanmar-machine.hh" + } + +_again: + switch ( _myanmar_syllable_machine_to_state_actions[cs] ) { + case 1: +#line 1 "NONE" + {ts = 0;} + break; +#line 532 "hb-ot-shaper-myanmar-machine.hh" + } + + if ( ++p != pe ) + goto _resume; + _test_eof: {} + if ( p == eof ) + { + if ( _myanmar_syllable_machine_eof_trans[cs] > 0 ) { + _trans = _myanmar_syllable_machine_eof_trans[cs] - 1; + goto _eof_trans; + } + } + + } + +#line 145 "hb-ot-shaper-myanmar-machine.rl" + +} + +#undef found_syllable + +#endif /* HB_OT_SHAPER_MYANMAR_MACHINE_HH */ diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar.cc b/thirdparty/harfbuzz/src/hb-ot-shaper-myanmar.cc index c7aa80a79a..1ccafbca7e 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-myanmar.cc +++ b/thirdparty/harfbuzz/src/hb-ot-shaper-myanmar.cc @@ -28,14 +28,16 @@ #ifndef HB_NO_OT_SHAPE -#include "hb-ot-shape-complex-myanmar.hh" -#include "hb-ot-shape-complex-myanmar-machine.hh" +#include "hb-ot-shaper-myanmar-machine.hh" +#include "hb-ot-shaper-indic.hh" +#include "hb-ot-layout.hh" /* * Myanmar shaper. */ + static const hb_tag_t myanmar_basic_features[] = { @@ -62,6 +64,40 @@ myanmar_other_features[] = HB_TAG('p','s','t','s'), }; +static inline void +set_myanmar_properties (hb_glyph_info_t &info) +{ + hb_codepoint_t u = info.codepoint; + unsigned int type = hb_indic_get_categories (u); + + info.myanmar_category() = (myanmar_category_t) (type & 0xFFu); +} + + +static inline bool +is_one_of_myanmar (const hb_glyph_info_t &info, unsigned int flags) +{ + /* If it ligated, all bets are off. */ + if (_hb_glyph_info_ligated (&info)) return false; + return !!(FLAG_UNSAFE (info.myanmar_category()) & flags); +} + +/* Note: + * + * We treat Vowels and placeholders as if they were consonants. This is safe because Vowels + * cannot happen in a consonant syllable. The plus side however is, we can call the + * consonant syllable logic from the vowel syllable function and get it all right! + * + * Keep in sync with consonant_categories in the generator. */ +#define CONSONANT_FLAGS_MYANMAR (FLAG (M_Cat(C)) | FLAG (M_Cat(CS)) | FLAG (M_Cat(Ra)) | /* FLAG (M_Cat(CM)) | */ FLAG (M_Cat(IV)) | FLAG (M_Cat(GB)) | FLAG (M_Cat(DOTTEDCIRCLE))) + +static inline bool +is_consonant_myanmar (const hb_glyph_info_t &info) +{ + return is_one_of_myanmar (info, CONSONANT_FLAGS_MYANMAR); +} + + static void setup_syllables_myanmar (const hb_ot_shape_plan_t *plan, hb_font_t *font, @@ -92,6 +128,7 @@ collect_features_myanmar (hb_ot_shape_planner_t *plan) map->enable_feature (myanmar_basic_features[i], F_MANUAL_ZWJ | F_PER_SYLLABLE); map->add_gsub_pause (nullptr); } + map->add_gsub_pause (hb_syllabic_clear_var); // Don't need syllables anymore, use stop to free buffer var for (unsigned int i = 0; i < ARRAY_LENGTH (myanmar_other_features); i++) map->enable_feature (myanmar_other_features[i], F_MANUAL_ZWJ); @@ -105,8 +142,7 @@ setup_masks_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED, HB_BUFFER_ALLOCATE_VAR (buffer, myanmar_category); HB_BUFFER_ALLOCATE_VAR (buffer, myanmar_position); - /* We cannot setup masks here. We save information about characters - * and setup masks later on in a pause-callback. */ + /* No masks, we just save information about characters. */ unsigned int count = buffer->len; hb_glyph_info_t *info = buffer->info; @@ -119,6 +155,7 @@ setup_syllables_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED, hb_font_t *font HB_UNUSED, hb_buffer_t *buffer) { + HB_BUFFER_ALLOCATE_VAR (buffer, syllable); find_syllables_myanmar (buffer); foreach_syllable (buffer, start, end) buffer->unsafe_to_break (start, end); @@ -130,7 +167,7 @@ compare_myanmar_order (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb) int a = pa->myanmar_position(); int b = pb->myanmar_position(); - return a < b ? -1 : a == b ? 0 : +1; + return (int) a - (int) b; } @@ -149,9 +186,9 @@ initial_reordering_consonant_syllable (hb_buffer_t *buffer, { unsigned int limit = start; if (start + 3 <= end && - info[start ].myanmar_category() == OT_Ra && - info[start+1].myanmar_category() == OT_As && - info[start+2].myanmar_category() == OT_H) + info[start ].myanmar_category() == M_Cat(Ra) && + info[start+1].myanmar_category() == M_Cat(As) && + info[start+2].myanmar_category() == M_Cat(H)) { limit += 3; base = start; @@ -163,7 +200,7 @@ initial_reordering_consonant_syllable (hb_buffer_t *buffer, base = limit; for (unsigned int i = limit; i < end; i++) - if (is_consonant (info[i])) + if (is_consonant_myanmar (info[i])) { base = i; break; @@ -188,39 +225,40 @@ initial_reordering_consonant_syllable (hb_buffer_t *buffer, * Myanmar reordering! */ for (; i < end; i++) { - if (info[i].myanmar_category() == OT_MR) /* Pre-base reordering */ + if (info[i].myanmar_category() == M_Cat(MR)) /* Pre-base reordering */ { info[i].myanmar_position() = POS_PRE_C; continue; } - if (info[i].myanmar_position() < POS_BASE_C) /* Left matra */ + if (info[i].myanmar_category() == M_Cat(VPre)) /* Left matra */ { + info[i].myanmar_position() = POS_PRE_M; continue; } - if (info[i].myanmar_category() == OT_VS) + if (info[i].myanmar_category() == M_Cat(VS)) { info[i].myanmar_position() = info[i - 1].myanmar_position(); continue; } - if (pos == POS_AFTER_MAIN && info[i].myanmar_category() == OT_VBlw) + if (pos == POS_AFTER_MAIN && info[i].myanmar_category() == M_Cat(VBlw)) { pos = POS_BELOW_C; info[i].myanmar_position() = pos; continue; } - if (pos == POS_BELOW_C && info[i].myanmar_category() == OT_A) + if (pos == POS_BELOW_C && info[i].myanmar_category() == M_Cat(A)) { info[i].myanmar_position() = POS_BEFORE_SUB; continue; } - if (pos == POS_BELOW_C && info[i].myanmar_category() == OT_VBlw) + if (pos == POS_BELOW_C && info[i].myanmar_category() == M_Cat(VBlw)) { info[i].myanmar_position() = pos; continue; } - if (pos == POS_BELOW_C && info[i].myanmar_category() != OT_A) + if (pos == POS_BELOW_C && info[i].myanmar_category() != M_Cat(A)) { pos = POS_AFTER_SUB; info[i].myanmar_position() = pos; @@ -248,7 +286,6 @@ reorder_syllable_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED, initial_reordering_consonant_syllable (buffer, start, end); break; - case myanmar_punctuation_cluster: case myanmar_non_myanmar_cluster: break; } @@ -263,7 +300,7 @@ reorder_myanmar (const hb_ot_shape_plan_t *plan, { hb_syllabic_insert_dotted_circles (font, buffer, myanmar_broken_cluster, - OT_GB); + M_Cat(DOTTEDCIRCLE)); foreach_syllable (buffer, start, end) reorder_syllable_myanmar (plan, font->face, buffer, start, end); @@ -275,7 +312,7 @@ reorder_myanmar (const hb_ot_shape_plan_t *plan, } -const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar = +const hb_ot_shaper_t _hb_ot_shaper_myanmar = { collect_features_myanmar, nullptr, /* override_features */ @@ -297,7 +334,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar = /* Ugly Zawgyi encoding. * Disable all auto processing. * https://github.com/harfbuzz/harfbuzz/issues/1162 */ -const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar_zawgyi = +const hb_ot_shaper_t _hb_ot_shaper_myanmar_zawgyi = { nullptr, /* collect_features */ nullptr, /* override_features */ diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-syllabic.cc b/thirdparty/harfbuzz/src/hb-ot-shaper-syllabic.cc index 76092c7f38..a8e0d8e8c1 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-syllabic.cc +++ b/thirdparty/harfbuzz/src/hb-ot-shaper-syllabic.cc @@ -26,7 +26,7 @@ #ifndef HB_NO_OT_SHAPE -#include "hb-ot-shape-complex-syllabic.hh" +#include "hb-ot-shaper-syllabic.hh" void @@ -39,31 +39,18 @@ hb_syllabic_insert_dotted_circles (hb_font_t *font, { if (unlikely (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE)) return; - - /* Note: This loop is extra overhead, but should not be measurable. - * TODO Use a buffer scratch flag to remove the loop. */ - bool has_broken_syllables = false; - unsigned int count = buffer->len; - hb_glyph_info_t *info = buffer->info; - for (unsigned int i = 0; i < count; i++) - if ((info[i].syllable() & 0x0F) == broken_syllable_type) - { - has_broken_syllables = true; - break; - } - if (likely (!has_broken_syllables)) + if (likely (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE))) return; - hb_codepoint_t dottedcircle_glyph; if (!font->get_nominal_glyph (0x25CCu, &dottedcircle_glyph)) return; hb_glyph_info_t dottedcircle = {0}; dottedcircle.codepoint = 0x25CCu; - dottedcircle.complex_var_u8_category() = dottedcircle_category; + dottedcircle.ot_shaper_var_u8_category() = dottedcircle_category; if (dottedcircle_position != -1) - dottedcircle.complex_var_u8_auxiliary() = dottedcircle_position; + dottedcircle.ot_shaper_var_u8_auxiliary() = dottedcircle_position; dottedcircle.codepoint = dottedcircle_glyph; buffer->clear_output (); @@ -87,7 +74,7 @@ hb_syllabic_insert_dotted_circles (hb_font_t *font, { while (buffer->idx < buffer->len && buffer->successful && last_syllable == buffer->cur().syllable() && - buffer->cur().complex_var_u8_category() == (unsigned) repha_category) + buffer->cur().ot_shaper_var_u8_category() == (unsigned) repha_category) (void) buffer->next_glyph (); } @@ -99,5 +86,13 @@ hb_syllabic_insert_dotted_circles (hb_font_t *font, buffer->sync (); } +HB_INTERNAL void +hb_syllabic_clear_var (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer) +{ + HB_BUFFER_DEALLOCATE_VAR (buffer, syllable); +} + #endif diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-syllabic.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-syllabic.hh index b901a660d3..e8a15bb48a 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-syllabic.hh +++ b/thirdparty/harfbuzz/src/hb-ot-shaper-syllabic.hh @@ -22,12 +22,12 @@ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ -#ifndef HB_OT_SHAPE_COMPLEX_SYLLABIC_HH -#define HB_OT_SHAPE_COMPLEX_SYLLABIC_HH +#ifndef HB_OT_SHAPER_SYLLABIC_HH +#define HB_OT_SHAPER_SYLLABIC_HH #include "hb.hh" -#include "hb-ot-shape-complex.hh" +#include "hb-ot-shaper.hh" HB_INTERNAL void @@ -38,5 +38,10 @@ hb_syllabic_insert_dotted_circles (hb_font_t *font, int repha_category = -1, int dottedcircle_position = -1); +HB_INTERNAL void +hb_syllabic_clear_var (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer); + -#endif /* HB_OT_SHAPE_COMPLEX_SYLLABIC_HH */ +#endif /* HB_OT_SHAPER_SYLLABIC_HH */ diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-thai.cc b/thirdparty/harfbuzz/src/hb-ot-shaper-thai.cc index a1e27a83be..1280e7ed17 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-thai.cc +++ b/thirdparty/harfbuzz/src/hb-ot-shaper-thai.cc @@ -28,7 +28,7 @@ #ifndef HB_NO_OT_SHAPE -#include "hb-ot-shape-complex.hh" +#include "hb-ot-shaper.hh" /* Thai / Lao shaper */ @@ -222,7 +222,7 @@ do_thai_pua_shaping (const hb_ot_shape_plan_t *plan HB_UNUSED, hb_buffer_t *buffer, hb_font_t *font) { -#ifdef HB_NO_OT_SHAPE_COMPLEX_THAI_FALLBACK +#ifdef HB_NO_OT_SHAPER_THAI_FALLBACK return; #endif @@ -279,7 +279,7 @@ preprocess_text_thai (const hb_ot_shape_plan_t *plan, * to be what Uniscribe and other engines implement. According to Eric Muller: * * When you have a SARA AM, decompose it in NIKHAHIT + SARA AA, *and* move the - * NIKHAHIT backwards over any tone mark (0E48-0E4B). + * NIKHAHIT backwards over any above-base marks. * * <0E14, 0E4B, 0E33> -> <0E14, 0E4D, 0E4B, 0E32> * @@ -308,8 +308,8 @@ preprocess_text_thai (const hb_ot_shape_plan_t *plan, * Nikhahit: U+0E4D U+0ECD * * Testing shows that Uniscribe reorder the following marks: - * Thai: <0E31,0E34..0E37,0E47..0E4E> - * Lao: <0EB1,0EB4..0EB7,0EC7..0ECE> + * Thai: <0E31,0E34..0E37, 0E47..0E4E> + * Lao: <0EB1,0EB4..0EB7,0EBB,0EC8..0ECD> * * Note how the Lao versions are the same as Thai + 0x80. */ @@ -319,7 +319,7 @@ preprocess_text_thai (const hb_ot_shape_plan_t *plan, #define IS_SARA_AM(x) (((x) & ~0x0080u) == 0x0E33u) #define NIKHAHIT_FROM_SARA_AM(x) ((x) - 0x0E33u + 0x0E4Du) #define SARA_AA_FROM_SARA_AM(x) ((x) - 1) -#define IS_TONE_MARK(x) (hb_in_ranges<hb_codepoint_t> ((x) & ~0x0080u, 0x0E34u, 0x0E37u, 0x0E47u, 0x0E4Eu, 0x0E31u, 0x0E31u)) +#define IS_ABOVE_BASE_MARK(x) (hb_in_ranges<hb_codepoint_t> ((x) & ~0x0080u, 0x0E34u, 0x0E37u, 0x0E47u, 0x0E4Eu, 0x0E31u, 0x0E31u, 0x0E3Bu, 0x0E3Bu)) buffer->clear_output (); unsigned int count = buffer->len; @@ -343,7 +343,7 @@ preprocess_text_thai (const hb_ot_shape_plan_t *plan, /* Ok, let's see... */ unsigned int start = end - 2; - while (start > 0 && IS_TONE_MARK (buffer->out_info[start - 1].codepoint)) + while (start > 0 && IS_ABOVE_BASE_MARK (buffer->out_info[start - 1].codepoint)) start--; if (start + 2 < end) @@ -371,7 +371,7 @@ preprocess_text_thai (const hb_ot_shape_plan_t *plan, do_thai_pua_shaping (plan, buffer, font); } -const hb_ot_complex_shaper_t _hb_ot_complex_shaper_thai = +const hb_ot_shaper_t _hb_ot_shaper_thai = { nullptr, /* collect_features */ nullptr, /* override_features */ diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-use-machine.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-use-machine.hh new file mode 100644 index 0000000000..65e65ff39d --- /dev/null +++ b/thirdparty/harfbuzz/src/hb-ot-shaper-use-machine.hh @@ -0,0 +1,931 @@ + +#line 1 "hb-ot-shaper-use-machine.rl" +/* + * Copyright © 2015 Mozilla Foundation. + * Copyright © 2015 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Mozilla Author(s): Jonathan Kew + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_OT_SHAPER_USE_MACHINE_HH +#define HB_OT_SHAPER_USE_MACHINE_HH + +#include "hb.hh" + +#include "hb-ot-shaper-syllabic.hh" + +/* buffer var allocations */ +#define use_category() ot_shaper_var_u8_category() + +#define USE(Cat) use_syllable_machine_ex_##Cat + +enum use_syllable_type_t { + use_virama_terminated_cluster, + use_sakot_terminated_cluster, + use_standard_cluster, + use_number_joiner_terminated_cluster, + use_numeral_cluster, + use_symbol_cluster, + use_hieroglyph_cluster, + use_broken_cluster, + use_non_cluster, +}; + + +#line 57 "hb-ot-shaper-use-machine.hh" +#define use_syllable_machine_ex_B 1u +#define use_syllable_machine_ex_CGJ 6u +#define use_syllable_machine_ex_CMAbv 31u +#define use_syllable_machine_ex_CMBlw 32u +#define use_syllable_machine_ex_CS 43u +#define use_syllable_machine_ex_FAbv 24u +#define use_syllable_machine_ex_FBlw 25u +#define use_syllable_machine_ex_FMAbv 45u +#define use_syllable_machine_ex_FMBlw 46u +#define use_syllable_machine_ex_FMPst 47u +#define use_syllable_machine_ex_FPst 26u +#define use_syllable_machine_ex_G 49u +#define use_syllable_machine_ex_GB 5u +#define use_syllable_machine_ex_H 12u +#define use_syllable_machine_ex_HN 13u +#define use_syllable_machine_ex_HVM 53u +#define use_syllable_machine_ex_IS 44u +#define use_syllable_machine_ex_J 50u +#define use_syllable_machine_ex_MAbv 27u +#define use_syllable_machine_ex_MBlw 28u +#define use_syllable_machine_ex_MPre 30u +#define use_syllable_machine_ex_MPst 29u +#define use_syllable_machine_ex_N 4u +#define use_syllable_machine_ex_O 0u +#define use_syllable_machine_ex_R 18u +#define use_syllable_machine_ex_SB 51u +#define use_syllable_machine_ex_SE 52u +#define use_syllable_machine_ex_SMAbv 41u +#define use_syllable_machine_ex_SMBlw 42u +#define use_syllable_machine_ex_SUB 11u +#define use_syllable_machine_ex_Sk 48u +#define use_syllable_machine_ex_VAbv 33u +#define use_syllable_machine_ex_VBlw 34u +#define use_syllable_machine_ex_VMAbv 37u +#define use_syllable_machine_ex_VMBlw 38u +#define use_syllable_machine_ex_VMPre 23u +#define use_syllable_machine_ex_VMPst 39u +#define use_syllable_machine_ex_VPre 22u +#define use_syllable_machine_ex_VPst 35u +#define use_syllable_machine_ex_WJ 16u +#define use_syllable_machine_ex_ZWNJ 14u + + +#line 101 "hb-ot-shaper-use-machine.hh" +static const unsigned char _use_syllable_machine_trans_keys[] = { + 0u, 53u, 11u, 53u, 11u, 53u, 1u, 53u, 23u, 48u, 24u, 47u, 25u, 47u, 26u, 47u, + 45u, 46u, 46u, 46u, 24u, 48u, 24u, 48u, 24u, 48u, 1u, 1u, 24u, 48u, 22u, 53u, + 23u, 53u, 23u, 53u, 23u, 53u, 12u, 53u, 23u, 53u, 12u, 53u, 12u, 53u, 12u, 53u, + 11u, 53u, 1u, 1u, 1u, 48u, 11u, 53u, 41u, 42u, 42u, 42u, 11u, 53u, 11u, 53u, + 1u, 53u, 23u, 48u, 24u, 47u, 25u, 47u, 26u, 47u, 45u, 46u, 46u, 46u, 24u, 48u, + 24u, 48u, 24u, 48u, 1u, 1u, 24u, 48u, 22u, 53u, 23u, 53u, 23u, 53u, 23u, 53u, + 12u, 53u, 23u, 53u, 12u, 53u, 12u, 53u, 12u, 53u, 11u, 53u, 1u, 1u, 1u, 48u, + 13u, 13u, 4u, 4u, 11u, 53u, 11u, 53u, 1u, 53u, 23u, 48u, 24u, 47u, 25u, 47u, + 26u, 47u, 45u, 46u, 46u, 46u, 24u, 48u, 24u, 48u, 24u, 48u, 1u, 1u, 24u, 48u, + 22u, 53u, 23u, 53u, 23u, 53u, 23u, 53u, 12u, 53u, 23u, 53u, 12u, 53u, 12u, 53u, + 12u, 53u, 11u, 53u, 1u, 1u, 1u, 48u, 11u, 53u, 11u, 53u, 1u, 53u, 23u, 48u, + 24u, 47u, 25u, 47u, 26u, 47u, 45u, 46u, 46u, 46u, 24u, 48u, 24u, 48u, 24u, 48u, + 1u, 1u, 24u, 48u, 22u, 53u, 23u, 53u, 23u, 53u, 23u, 53u, 12u, 53u, 23u, 53u, + 12u, 53u, 12u, 53u, 12u, 53u, 11u, 53u, 1u, 1u, 1u, 48u, 4u, 4u, 13u, 13u, + 1u, 53u, 11u, 53u, 41u, 42u, 42u, 42u, 1u, 5u, 50u, 52u, 49u, 52u, 49u, 51u, + 0 +}; + +static const char _use_syllable_machine_key_spans[] = { + 54, 43, 43, 53, 26, 24, 23, 22, + 2, 1, 25, 25, 25, 1, 25, 32, + 31, 31, 31, 42, 31, 42, 42, 42, + 43, 1, 48, 43, 2, 1, 43, 43, + 53, 26, 24, 23, 22, 2, 1, 25, + 25, 25, 1, 25, 32, 31, 31, 31, + 42, 31, 42, 42, 42, 43, 1, 48, + 1, 1, 43, 43, 53, 26, 24, 23, + 22, 2, 1, 25, 25, 25, 1, 25, + 32, 31, 31, 31, 42, 31, 42, 42, + 42, 43, 1, 48, 43, 43, 53, 26, + 24, 23, 22, 2, 1, 25, 25, 25, + 1, 25, 32, 31, 31, 31, 42, 31, + 42, 42, 42, 43, 1, 48, 1, 1, + 53, 43, 2, 1, 5, 3, 4, 3 +}; + +static const short _use_syllable_machine_index_offsets[] = { + 0, 55, 99, 143, 197, 224, 249, 273, + 296, 299, 301, 327, 353, 379, 381, 407, + 440, 472, 504, 536, 579, 611, 654, 697, + 740, 784, 786, 835, 879, 882, 884, 928, + 972, 1026, 1053, 1078, 1102, 1125, 1128, 1130, + 1156, 1182, 1208, 1210, 1236, 1269, 1301, 1333, + 1365, 1408, 1440, 1483, 1526, 1569, 1613, 1615, + 1664, 1666, 1668, 1712, 1756, 1810, 1837, 1862, + 1886, 1909, 1912, 1914, 1940, 1966, 1992, 1994, + 2020, 2053, 2085, 2117, 2149, 2192, 2224, 2267, + 2310, 2353, 2397, 2399, 2448, 2492, 2536, 2590, + 2617, 2642, 2666, 2689, 2692, 2694, 2720, 2746, + 2772, 2774, 2800, 2833, 2865, 2897, 2929, 2972, + 3004, 3047, 3090, 3133, 3177, 3179, 3228, 3230, + 3232, 3286, 3330, 3333, 3335, 3341, 3345, 3350 +}; + +static const unsigned char _use_syllable_machine_indicies[] = { + 0, 1, 2, 2, 3, 4, 2, 2, + 2, 2, 2, 5, 6, 7, 2, 2, + 2, 2, 8, 2, 2, 2, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 2, 23, 24, 25, + 2, 26, 27, 28, 29, 30, 31, 32, + 29, 33, 2, 34, 2, 35, 2, 37, + 38, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, + 36, 53, 54, 55, 36, 56, 57, 36, + 58, 59, 60, 61, 58, 36, 36, 36, + 36, 62, 36, 37, 38, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 49, + 49, 50, 51, 52, 36, 53, 54, 55, + 36, 36, 36, 36, 58, 59, 60, 61, + 58, 36, 36, 36, 36, 62, 36, 37, + 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 40, 41, 42, + 43, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 53, 54, 55, 36, 36, + 36, 36, 36, 59, 60, 61, 63, 36, + 36, 36, 36, 40, 36, 40, 41, 42, + 43, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 53, 54, 55, 36, 36, + 36, 36, 36, 59, 60, 61, 63, 36, + 41, 42, 43, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 59, 60, 61, + 36, 42, 43, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 59, 60, 61, + 36, 43, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 59, 60, 61, 36, + 59, 60, 36, 60, 36, 41, 42, 43, + 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 53, 54, 55, 36, 36, 36, + 36, 36, 59, 60, 61, 63, 36, 41, + 42, 43, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 54, 55, 36, + 36, 36, 36, 36, 59, 60, 61, 63, + 36, 41, 42, 43, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, + 55, 36, 36, 36, 36, 36, 59, 60, + 61, 63, 36, 64, 36, 41, 42, 43, + 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 59, 60, 61, 63, 36, 39, + 40, 41, 42, 43, 36, 36, 36, 36, + 36, 36, 50, 51, 52, 36, 53, 54, + 55, 36, 36, 36, 36, 36, 59, 60, + 61, 63, 36, 36, 36, 36, 40, 36, + 40, 41, 42, 43, 36, 36, 36, 36, + 36, 36, 50, 51, 52, 36, 53, 54, + 55, 36, 36, 36, 36, 36, 59, 60, + 61, 63, 36, 36, 36, 36, 40, 36, + 40, 41, 42, 43, 36, 36, 36, 36, + 36, 36, 36, 51, 52, 36, 53, 54, + 55, 36, 36, 36, 36, 36, 59, 60, + 61, 63, 36, 36, 36, 36, 40, 36, + 40, 41, 42, 43, 36, 36, 36, 36, + 36, 36, 36, 36, 52, 36, 53, 54, + 55, 36, 36, 36, 36, 36, 59, 60, + 61, 63, 36, 36, 36, 36, 40, 36, + 65, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 39, 40, 41, 42, 43, 36, + 45, 46, 36, 36, 36, 50, 51, 52, + 36, 53, 54, 55, 36, 36, 36, 36, + 36, 59, 60, 61, 63, 36, 36, 36, + 36, 40, 36, 40, 41, 42, 43, 36, + 36, 36, 36, 36, 36, 36, 36, 36, + 36, 53, 54, 55, 36, 36, 36, 36, + 36, 59, 60, 61, 63, 36, 36, 36, + 36, 40, 36, 65, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 39, 40, 41, + 42, 43, 36, 36, 46, 36, 36, 36, + 50, 51, 52, 36, 53, 54, 55, 36, + 36, 36, 36, 36, 59, 60, 61, 63, + 36, 36, 36, 36, 40, 36, 65, 36, + 36, 36, 36, 36, 36, 36, 36, 36, + 39, 40, 41, 42, 43, 36, 36, 36, + 36, 36, 36, 50, 51, 52, 36, 53, + 54, 55, 36, 36, 36, 36, 36, 59, + 60, 61, 63, 36, 36, 36, 36, 40, + 36, 65, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 39, 40, 41, 42, 43, + 44, 45, 46, 36, 36, 36, 50, 51, + 52, 36, 53, 54, 55, 36, 36, 36, + 36, 36, 59, 60, 61, 63, 36, 36, + 36, 36, 40, 36, 37, 38, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 39, + 40, 41, 42, 43, 44, 45, 46, 47, + 36, 49, 50, 51, 52, 36, 53, 54, + 55, 36, 36, 36, 36, 58, 59, 60, + 61, 58, 36, 36, 36, 36, 62, 36, + 37, 36, 37, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, + 40, 41, 42, 43, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 53, 54, + 55, 36, 36, 36, 36, 36, 59, 60, + 61, 63, 36, 37, 38, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 36, 53, 54, 55, + 36, 36, 36, 36, 58, 59, 60, 61, + 58, 36, 36, 36, 36, 62, 36, 56, + 57, 36, 57, 36, 67, 68, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 69, + 70, 71, 72, 73, 74, 75, 76, 77, + 1, 78, 79, 80, 81, 66, 82, 83, + 84, 66, 66, 66, 66, 85, 86, 87, + 88, 89, 66, 66, 66, 66, 90, 66, + 67, 68, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 78, 79, 80, + 81, 66, 82, 83, 84, 66, 66, 66, + 66, 85, 86, 87, 88, 89, 66, 66, + 66, 66, 90, 66, 67, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 70, 71, 72, 73, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, + 82, 83, 84, 66, 66, 66, 66, 66, + 86, 87, 88, 91, 66, 66, 66, 66, + 70, 66, 70, 71, 72, 73, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, + 82, 83, 84, 66, 66, 66, 66, 66, + 86, 87, 88, 91, 66, 71, 72, 73, + 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 86, 87, 88, 66, 72, 73, + 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 86, 87, 88, 66, 73, 66, + 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, + 66, 86, 87, 88, 66, 86, 87, 66, + 87, 66, 71, 72, 73, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 82, + 83, 84, 66, 66, 66, 66, 66, 86, + 87, 88, 91, 66, 71, 72, 73, 66, + 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 83, 84, 66, 66, 66, 66, + 66, 86, 87, 88, 91, 66, 71, 72, + 73, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 84, 66, 66, + 66, 66, 66, 86, 87, 88, 91, 66, + 93, 92, 71, 72, 73, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 86, + 87, 88, 91, 66, 69, 70, 71, 72, + 73, 66, 66, 66, 66, 66, 66, 79, + 80, 81, 66, 82, 83, 84, 66, 66, + 66, 66, 66, 86, 87, 88, 91, 66, + 66, 66, 66, 70, 66, 70, 71, 72, + 73, 66, 66, 66, 66, 66, 66, 79, + 80, 81, 66, 82, 83, 84, 66, 66, + 66, 66, 66, 86, 87, 88, 91, 66, + 66, 66, 66, 70, 66, 70, 71, 72, + 73, 66, 66, 66, 66, 66, 66, 66, + 80, 81, 66, 82, 83, 84, 66, 66, + 66, 66, 66, 86, 87, 88, 91, 66, + 66, 66, 66, 70, 66, 70, 71, 72, + 73, 66, 66, 66, 66, 66, 66, 66, + 66, 81, 66, 82, 83, 84, 66, 66, + 66, 66, 66, 86, 87, 88, 91, 66, + 66, 66, 66, 70, 66, 94, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 69, + 70, 71, 72, 73, 66, 75, 76, 66, + 66, 66, 79, 80, 81, 66, 82, 83, + 84, 66, 66, 66, 66, 66, 86, 87, + 88, 91, 66, 66, 66, 66, 70, 66, + 70, 71, 72, 73, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 82, 83, + 84, 66, 66, 66, 66, 66, 86, 87, + 88, 91, 66, 66, 66, 66, 70, 66, + 94, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 69, 70, 71, 72, 73, 66, + 66, 76, 66, 66, 66, 79, 80, 81, + 66, 82, 83, 84, 66, 66, 66, 66, + 66, 86, 87, 88, 91, 66, 66, 66, + 66, 70, 66, 94, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 69, 70, 71, + 72, 73, 66, 66, 66, 66, 66, 66, + 79, 80, 81, 66, 82, 83, 84, 66, + 66, 66, 66, 66, 86, 87, 88, 91, + 66, 66, 66, 66, 70, 66, 94, 66, + 66, 66, 66, 66, 66, 66, 66, 66, + 69, 70, 71, 72, 73, 74, 75, 76, + 66, 66, 66, 79, 80, 81, 66, 82, + 83, 84, 66, 66, 66, 66, 66, 86, + 87, 88, 91, 66, 66, 66, 66, 70, + 66, 67, 68, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 66, 78, 79, + 80, 81, 66, 82, 83, 84, 66, 66, + 66, 66, 85, 86, 87, 88, 89, 66, + 66, 66, 66, 90, 66, 67, 95, 67, + 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 70, 71, 72, + 73, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 82, 83, 84, 66, 66, + 66, 66, 66, 86, 87, 88, 91, 66, + 97, 96, 3, 98, 99, 100, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 101, + 102, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114, 66, 115, 116, + 117, 66, 56, 57, 66, 118, 119, 120, + 88, 121, 66, 66, 66, 66, 122, 66, + 99, 100, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 101, 102, 103, 104, 105, + 106, 107, 108, 109, 111, 111, 112, 113, + 114, 66, 115, 116, 117, 66, 66, 66, + 66, 118, 119, 120, 88, 121, 66, 66, + 66, 66, 122, 66, 99, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 102, 103, 104, 105, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, + 115, 116, 117, 66, 66, 66, 66, 66, + 119, 120, 88, 123, 66, 66, 66, 66, + 102, 66, 102, 103, 104, 105, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, + 115, 116, 117, 66, 66, 66, 66, 66, + 119, 120, 88, 123, 66, 103, 104, 105, + 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 119, 120, 88, 66, 104, 105, + 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 119, 120, 88, 66, 105, 66, + 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, + 66, 119, 120, 88, 66, 119, 120, 66, + 120, 66, 103, 104, 105, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 115, + 116, 117, 66, 66, 66, 66, 66, 119, + 120, 88, 123, 66, 103, 104, 105, 66, + 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 116, 117, 66, 66, 66, 66, + 66, 119, 120, 88, 123, 66, 103, 104, + 105, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 117, 66, 66, + 66, 66, 66, 119, 120, 88, 123, 66, + 124, 92, 103, 104, 105, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 119, + 120, 88, 123, 66, 101, 102, 103, 104, + 105, 66, 66, 66, 66, 66, 66, 112, + 113, 114, 66, 115, 116, 117, 66, 66, + 66, 66, 66, 119, 120, 88, 123, 66, + 66, 66, 66, 102, 66, 102, 103, 104, + 105, 66, 66, 66, 66, 66, 66, 112, + 113, 114, 66, 115, 116, 117, 66, 66, + 66, 66, 66, 119, 120, 88, 123, 66, + 66, 66, 66, 102, 66, 102, 103, 104, + 105, 66, 66, 66, 66, 66, 66, 66, + 113, 114, 66, 115, 116, 117, 66, 66, + 66, 66, 66, 119, 120, 88, 123, 66, + 66, 66, 66, 102, 66, 102, 103, 104, + 105, 66, 66, 66, 66, 66, 66, 66, + 66, 114, 66, 115, 116, 117, 66, 66, + 66, 66, 66, 119, 120, 88, 123, 66, + 66, 66, 66, 102, 66, 125, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 101, + 102, 103, 104, 105, 66, 107, 108, 66, + 66, 66, 112, 113, 114, 66, 115, 116, + 117, 66, 66, 66, 66, 66, 119, 120, + 88, 123, 66, 66, 66, 66, 102, 66, + 102, 103, 104, 105, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 115, 116, + 117, 66, 66, 66, 66, 66, 119, 120, + 88, 123, 66, 66, 66, 66, 102, 66, + 125, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 101, 102, 103, 104, 105, 66, + 66, 108, 66, 66, 66, 112, 113, 114, + 66, 115, 116, 117, 66, 66, 66, 66, + 66, 119, 120, 88, 123, 66, 66, 66, + 66, 102, 66, 125, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 101, 102, 103, + 104, 105, 66, 66, 66, 66, 66, 66, + 112, 113, 114, 66, 115, 116, 117, 66, + 66, 66, 66, 66, 119, 120, 88, 123, + 66, 66, 66, 66, 102, 66, 125, 66, + 66, 66, 66, 66, 66, 66, 66, 66, + 101, 102, 103, 104, 105, 106, 107, 108, + 66, 66, 66, 112, 113, 114, 66, 115, + 116, 117, 66, 66, 66, 66, 66, 119, + 120, 88, 123, 66, 66, 66, 66, 102, + 66, 99, 100, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 66, 111, 112, + 113, 114, 66, 115, 116, 117, 66, 66, + 66, 66, 118, 119, 120, 88, 121, 66, + 66, 66, 66, 122, 66, 99, 95, 99, + 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 102, 103, 104, + 105, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 115, 116, 117, 66, 66, + 66, 66, 66, 119, 120, 88, 123, 66, + 99, 100, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 101, 102, 103, 104, 105, + 106, 107, 108, 109, 110, 111, 112, 113, + 114, 66, 115, 116, 117, 66, 66, 66, + 66, 118, 119, 120, 88, 121, 66, 66, + 66, 66, 122, 66, 5, 6, 126, 126, + 126, 126, 126, 126, 126, 126, 126, 9, + 10, 11, 12, 13, 14, 15, 16, 17, + 19, 19, 20, 21, 22, 126, 23, 24, + 25, 126, 126, 126, 126, 29, 30, 31, + 32, 29, 126, 126, 126, 126, 35, 126, + 5, 126, 126, 126, 126, 126, 126, 126, + 126, 126, 126, 126, 126, 126, 126, 126, + 126, 126, 126, 126, 126, 126, 10, 11, + 12, 13, 126, 126, 126, 126, 126, 126, + 126, 126, 126, 126, 23, 24, 25, 126, + 126, 126, 126, 126, 30, 31, 32, 127, + 126, 126, 126, 126, 10, 126, 10, 11, + 12, 13, 126, 126, 126, 126, 126, 126, + 126, 126, 126, 126, 23, 24, 25, 126, + 126, 126, 126, 126, 30, 31, 32, 127, + 126, 11, 12, 13, 126, 126, 126, 126, + 126, 126, 126, 126, 126, 126, 126, 126, + 126, 126, 126, 126, 126, 126, 30, 31, + 32, 126, 12, 13, 126, 126, 126, 126, + 126, 126, 126, 126, 126, 126, 126, 126, + 126, 126, 126, 126, 126, 126, 30, 31, + 32, 126, 13, 126, 126, 126, 126, 126, + 126, 126, 126, 126, 126, 126, 126, 126, + 126, 126, 126, 126, 126, 30, 31, 32, + 126, 30, 31, 126, 31, 126, 11, 12, + 13, 126, 126, 126, 126, 126, 126, 126, + 126, 126, 126, 23, 24, 25, 126, 126, + 126, 126, 126, 30, 31, 32, 127, 126, + 11, 12, 13, 126, 126, 126, 126, 126, + 126, 126, 126, 126, 126, 126, 24, 25, + 126, 126, 126, 126, 126, 30, 31, 32, + 127, 126, 11, 12, 13, 126, 126, 126, + 126, 126, 126, 126, 126, 126, 126, 126, + 126, 25, 126, 126, 126, 126, 126, 30, + 31, 32, 127, 126, 128, 126, 11, 12, + 13, 126, 126, 126, 126, 126, 126, 126, + 126, 126, 126, 126, 126, 126, 126, 126, + 126, 126, 126, 30, 31, 32, 127, 126, + 9, 10, 11, 12, 13, 126, 126, 126, + 126, 126, 126, 20, 21, 22, 126, 23, + 24, 25, 126, 126, 126, 126, 126, 30, + 31, 32, 127, 126, 126, 126, 126, 10, + 126, 10, 11, 12, 13, 126, 126, 126, + 126, 126, 126, 20, 21, 22, 126, 23, + 24, 25, 126, 126, 126, 126, 126, 30, + 31, 32, 127, 126, 126, 126, 126, 10, + 126, 10, 11, 12, 13, 126, 126, 126, + 126, 126, 126, 126, 21, 22, 126, 23, + 24, 25, 126, 126, 126, 126, 126, 30, + 31, 32, 127, 126, 126, 126, 126, 10, + 126, 10, 11, 12, 13, 126, 126, 126, + 126, 126, 126, 126, 126, 22, 126, 23, + 24, 25, 126, 126, 126, 126, 126, 30, + 31, 32, 127, 126, 126, 126, 126, 10, + 126, 129, 126, 126, 126, 126, 126, 126, + 126, 126, 126, 9, 10, 11, 12, 13, + 126, 15, 16, 126, 126, 126, 20, 21, + 22, 126, 23, 24, 25, 126, 126, 126, + 126, 126, 30, 31, 32, 127, 126, 126, + 126, 126, 10, 126, 10, 11, 12, 13, + 126, 126, 126, 126, 126, 126, 126, 126, + 126, 126, 23, 24, 25, 126, 126, 126, + 126, 126, 30, 31, 32, 127, 126, 126, + 126, 126, 10, 126, 129, 126, 126, 126, + 126, 126, 126, 126, 126, 126, 9, 10, + 11, 12, 13, 126, 126, 16, 126, 126, + 126, 20, 21, 22, 126, 23, 24, 25, + 126, 126, 126, 126, 126, 30, 31, 32, + 127, 126, 126, 126, 126, 10, 126, 129, + 126, 126, 126, 126, 126, 126, 126, 126, + 126, 9, 10, 11, 12, 13, 126, 126, + 126, 126, 126, 126, 20, 21, 22, 126, + 23, 24, 25, 126, 126, 126, 126, 126, + 30, 31, 32, 127, 126, 126, 126, 126, + 10, 126, 129, 126, 126, 126, 126, 126, + 126, 126, 126, 126, 9, 10, 11, 12, + 13, 14, 15, 16, 126, 126, 126, 20, + 21, 22, 126, 23, 24, 25, 126, 126, + 126, 126, 126, 30, 31, 32, 127, 126, + 126, 126, 126, 10, 126, 5, 6, 126, + 126, 126, 126, 126, 126, 126, 126, 126, + 9, 10, 11, 12, 13, 14, 15, 16, + 17, 126, 19, 20, 21, 22, 126, 23, + 24, 25, 126, 126, 126, 126, 29, 30, + 31, 32, 29, 126, 126, 126, 126, 35, + 126, 5, 126, 5, 126, 126, 126, 126, + 126, 126, 126, 126, 126, 126, 126, 126, + 126, 126, 126, 126, 126, 126, 126, 126, + 126, 10, 11, 12, 13, 126, 126, 126, + 126, 126, 126, 126, 126, 126, 126, 23, + 24, 25, 126, 126, 126, 126, 126, 30, + 31, 32, 127, 126, 130, 126, 7, 126, + 1, 126, 126, 126, 1, 126, 126, 126, + 126, 126, 5, 6, 7, 126, 126, 126, + 126, 126, 126, 126, 126, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 126, 23, 24, 25, 126, + 26, 27, 126, 29, 30, 31, 32, 29, + 126, 126, 126, 126, 35, 126, 5, 6, + 126, 126, 126, 126, 126, 126, 126, 126, + 126, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 126, + 23, 24, 25, 126, 126, 126, 126, 29, + 30, 31, 32, 29, 126, 126, 126, 126, + 35, 126, 26, 27, 126, 27, 126, 1, + 131, 131, 131, 1, 131, 133, 132, 33, + 132, 33, 133, 132, 133, 132, 33, 132, + 34, 132, 0 +}; + +static const char _use_syllable_machine_trans_targs[] = { + 1, 30, 0, 56, 58, 85, 86, 110, + 112, 98, 87, 88, 89, 90, 102, 104, + 105, 106, 113, 107, 99, 100, 101, 93, + 94, 95, 114, 115, 116, 108, 91, 92, + 0, 117, 119, 109, 0, 2, 3, 15, + 4, 5, 6, 7, 19, 21, 22, 23, + 27, 24, 16, 17, 18, 10, 11, 12, + 28, 29, 25, 8, 9, 0, 26, 13, + 14, 20, 0, 31, 32, 44, 33, 34, + 35, 36, 48, 50, 51, 52, 53, 45, + 46, 47, 39, 40, 41, 54, 37, 38, + 0, 54, 55, 42, 0, 43, 49, 0, + 0, 57, 0, 59, 60, 72, 61, 62, + 63, 64, 76, 78, 79, 80, 84, 81, + 73, 74, 75, 67, 68, 69, 82, 65, + 66, 82, 83, 70, 71, 77, 0, 96, + 97, 103, 111, 0, 0, 118 +}; + +static const char _use_syllable_machine_trans_actions[] = { + 0, 0, 3, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 4, 0, 0, 0, 5, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 6, 0, 0, + 0, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 8, 0, 0, + 9, 10, 0, 0, 11, 0, 0, 12, + 13, 0, 14, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 8, 0, + 0, 10, 0, 0, 0, 0, 15, 0, + 0, 0, 0, 16, 17, 0 +}; + +static const char _use_syllable_machine_to_state_actions[] = { + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static const char _use_syllable_machine_from_state_actions[] = { + 2, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static const short _use_syllable_machine_eof_trans[] = { + 0, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 93, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 96, 67, + 97, 99, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 93, 67, + 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 96, 67, 67, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 132, 133, 133, 133 +}; + +static const int use_syllable_machine_start = 0; +static const int use_syllable_machine_first_final = 0; +static const int use_syllable_machine_error = -1; + +static const int use_syllable_machine_en_main = 0; + + +#line 58 "hb-ot-shaper-use-machine.rl" + + + +#line 182 "hb-ot-shaper-use-machine.rl" + + +#define found_syllable(syllable_type) \ + HB_STMT_START { \ + if (0) fprintf (stderr, "syllable %d..%d %s\n", (*ts).second.first, (*te).second.first, #syllable_type); \ + for (unsigned i = (*ts).second.first; i < (*te).second.first; ++i) \ + info[i].syllable() = (syllable_serial << 4) | syllable_type; \ + syllable_serial++; \ + if (unlikely (syllable_serial == 16)) syllable_serial = 1; \ + } HB_STMT_END + + +template <typename Iter> +struct machine_index_t : + hb_iter_with_fallback_t<machine_index_t<Iter>, + typename Iter::item_t> +{ + machine_index_t (const Iter& it) : it (it) {} + machine_index_t (const machine_index_t& o) : hb_iter_with_fallback_t<machine_index_t<Iter>, + typename Iter::item_t> (), + it (o.it), is_null (o.is_null) {} + + static constexpr bool is_random_access_iterator = Iter::is_random_access_iterator; + static constexpr bool is_sorted_iterator = Iter::is_sorted_iterator; + + typename Iter::item_t __item__ () const { return *it; } + typename Iter::item_t __item_at__ (unsigned i) const { return it[i]; } + unsigned __len__ () const { return it.len (); } + void __next__ () { ++it; } + void __forward__ (unsigned n) { it += n; } + void __prev__ () { --it; } + void __rewind__ (unsigned n) { it -= n; } + + void operator = (unsigned n) + { + assert (n == 0); + is_null = true; + } + explicit operator bool () { return !is_null; } + + void operator = (const machine_index_t& o) + { + is_null = o.is_null; + unsigned index = (*it).first; + unsigned n = (*o.it).first; + if (index < n) it += n - index; else if (index > n) it -= index - n; + } + bool operator == (const machine_index_t& o) const + { return is_null ? o.is_null : !o.is_null && (*it).first == (*o.it).first; } + bool operator != (const machine_index_t& o) const { return !(*this == o); } + + private: + Iter it; + bool is_null = false; +}; +struct +{ + template <typename Iter, + hb_requires (hb_is_iterable (Iter))> + machine_index_t<hb_iter_type<Iter>> + operator () (Iter&& it) const + { return machine_index_t<hb_iter_type<Iter>> (hb_iter (it)); } +} +HB_FUNCOBJ (machine_index); + + + +static bool +not_ccs_default_ignorable (const hb_glyph_info_t &i) +{ return i.use_category() != USE(CGJ); } + +static inline void +find_syllables_use (hb_buffer_t *buffer) +{ + hb_glyph_info_t *info = buffer->info; + auto p = + + hb_iter (info, buffer->len) + | hb_enumerate + | hb_filter ([] (const hb_glyph_info_t &i) { return not_ccs_default_ignorable (i); }, + hb_second) + | hb_filter ([&] (const hb_pair_t<unsigned, const hb_glyph_info_t &> p) + { + if (p.second.use_category() == USE(ZWNJ)) + for (unsigned i = p.first + 1; i < buffer->len; ++i) + if (not_ccs_default_ignorable (info[i])) + return !_hb_glyph_info_is_unicode_mark (&info[i]); + return true; + }) + | hb_enumerate + | machine_index + ; + auto pe = p + p.len (); + auto eof = +pe; + auto ts = +p; + auto te = +p; + unsigned int act HB_UNUSED; + int cs; + +#line 784 "hb-ot-shaper-use-machine.hh" + { + cs = use_syllable_machine_start; + ts = 0; + te = 0; + act = 0; + } + +#line 282 "hb-ot-shaper-use-machine.rl" + + + unsigned int syllable_serial = 1; + +#line 797 "hb-ot-shaper-use-machine.hh" + { + int _slen; + int _trans; + const unsigned char *_keys; + const unsigned char *_inds; + if ( p == pe ) + goto _test_eof; +_resume: + switch ( _use_syllable_machine_from_state_actions[cs] ) { + case 2: +#line 1 "NONE" + {ts = p;} + break; +#line 811 "hb-ot-shaper-use-machine.hh" + } + + _keys = _use_syllable_machine_trans_keys + (cs<<1); + _inds = _use_syllable_machine_indicies + _use_syllable_machine_index_offsets[cs]; + + _slen = _use_syllable_machine_key_spans[cs]; + _trans = _inds[ _slen > 0 && _keys[0] <=( (*p).second.second.use_category()) && + ( (*p).second.second.use_category()) <= _keys[1] ? + ( (*p).second.second.use_category()) - _keys[0] : _slen ]; + +_eof_trans: + cs = _use_syllable_machine_trans_targs[_trans]; + + if ( _use_syllable_machine_trans_actions[_trans] == 0 ) + goto _again; + + switch ( _use_syllable_machine_trans_actions[_trans] ) { + case 9: +#line 172 "hb-ot-shaper-use-machine.rl" + {te = p+1;{ found_syllable (use_standard_cluster); }} + break; + case 6: +#line 175 "hb-ot-shaper-use-machine.rl" + {te = p+1;{ found_syllable (use_symbol_cluster); }} + break; + case 4: +#line 177 "hb-ot-shaper-use-machine.rl" + {te = p+1;{ found_syllable (use_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; }} + break; + case 3: +#line 178 "hb-ot-shaper-use-machine.rl" + {te = p+1;{ found_syllable (use_non_cluster); }} + break; + case 11: +#line 171 "hb-ot-shaper-use-machine.rl" + {te = p;p--;{ found_syllable (use_sakot_terminated_cluster); }} + break; + case 7: +#line 172 "hb-ot-shaper-use-machine.rl" + {te = p;p--;{ found_syllable (use_standard_cluster); }} + break; + case 14: +#line 173 "hb-ot-shaper-use-machine.rl" + {te = p;p--;{ found_syllable (use_number_joiner_terminated_cluster); }} + break; + case 13: +#line 174 "hb-ot-shaper-use-machine.rl" + {te = p;p--;{ found_syllable (use_numeral_cluster); }} + break; + case 5: +#line 175 "hb-ot-shaper-use-machine.rl" + {te = p;p--;{ found_syllable (use_symbol_cluster); }} + break; + case 17: +#line 176 "hb-ot-shaper-use-machine.rl" + {te = p;p--;{ found_syllable (use_hieroglyph_cluster); }} + break; + case 15: +#line 177 "hb-ot-shaper-use-machine.rl" + {te = p;p--;{ found_syllable (use_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; }} + break; + case 16: +#line 178 "hb-ot-shaper-use-machine.rl" + {te = p;p--;{ found_syllable (use_non_cluster); }} + break; + case 12: +#line 1 "NONE" + { switch( act ) { + case 1: + {{p = ((te))-1;} found_syllable (use_virama_terminated_cluster); } + break; + case 2: + {{p = ((te))-1;} found_syllable (use_sakot_terminated_cluster); } + break; + } + } + break; + case 8: +#line 1 "NONE" + {te = p+1;} +#line 170 "hb-ot-shaper-use-machine.rl" + {act = 1;} + break; + case 10: +#line 1 "NONE" + {te = p+1;} +#line 171 "hb-ot-shaper-use-machine.rl" + {act = 2;} + break; +#line 901 "hb-ot-shaper-use-machine.hh" + } + +_again: + switch ( _use_syllable_machine_to_state_actions[cs] ) { + case 1: +#line 1 "NONE" + {ts = 0;} + break; +#line 910 "hb-ot-shaper-use-machine.hh" + } + + if ( ++p != pe ) + goto _resume; + _test_eof: {} + if ( p == eof ) + { + if ( _use_syllable_machine_eof_trans[cs] > 0 ) { + _trans = _use_syllable_machine_eof_trans[cs] - 1; + goto _eof_trans; + } + } + + } + +#line 287 "hb-ot-shaper-use-machine.rl" + +} + +#undef found_syllable + +#endif /* HB_OT_SHAPER_USE_MACHINE_HH */ diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-use-table.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-use-table.hh index ea627cd27e..5aa025fb4c 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-use-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-shaper-use-table.hh @@ -37,12 +37,12 @@ * UnicodeData.txt does not have a header. */ -#ifndef HB_OT_SHAPE_COMPLEX_USE_TABLE_HH -#define HB_OT_SHAPE_COMPLEX_USE_TABLE_HH +#ifndef HB_OT_SHAPER_USE_TABLE_HH +#define HB_OT_SHAPER_USE_TABLE_HH #include "hb.hh" -#include "hb-ot-shape-complex-use-machine.hh" +#include "hb-ot-shaper-use-machine.hh" #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-macros" @@ -53,6 +53,7 @@ #define GB USE(GB) /* BASE_OTHER */ #define H USE(H) /* HALANT */ #define HN USE(HN) /* HALANT_NUM */ +#define HVM USE(HVM) /* HALANT_OR_VOWEL_MODIFIER */ #define IS USE(IS) /* INVISIBLE_STACKER */ #define J USE(J) /* HIEROGLYPH_JOINER */ #define N USE(N) /* BASE_NUM */ @@ -246,7 +247,7 @@ static const uint8_t use_table[] = { /* 0D90 */ B, B, B, B, B, B, B, WJ, WJ, WJ, B, B, B, B, B, B, /* 0DA0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 0DB0 */ B, B, WJ, B, B, B, B, B, B, B, B, B, WJ, B, WJ, WJ, - /* 0DC0 */ B, B, B, B, B, B, B, WJ, WJ, WJ, H, WJ, WJ, WJ, WJ, VPst, + /* 0DC0 */ B, B, B, B, B, B, B, WJ, WJ, WJ, HVM, WJ, WJ, WJ, WJ, VPst, /* 0DD0 */ VPst, VPst, VAbv, VAbv, VBlw, WJ, VBlw, WJ, VPst, VPre, VPre, VPre, VPre, VPre, VPre, VPst, /* 0DE0 */ WJ, WJ, WJ, WJ, WJ, WJ, B, B, B, B, B, B, B, B, B, B, /* 0DF0 */ WJ, WJ, VPst, VPst, O, WJ, WJ, WJ, @@ -606,7 +607,7 @@ static const uint8_t use_table[] = { /* 10A00 */ B, VBlw, VBlw, VBlw, WJ, VAbv, VBlw, WJ, WJ, WJ, WJ, WJ, VPst, VMBlw, VMBlw, VMAbv, /* 10A10 */ B, B, B, B, WJ, B, B, B, WJ, B, B, B, B, B, B, B, /* 10A20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 10A30 */ B, B, B, B, B, B, WJ, WJ, CMAbv, CMBlw, CMBlw, WJ, WJ, WJ, WJ, IS, + /* 10A30 */ B, B, B, B, B, B, WJ, WJ, CMBlw, CMBlw, CMBlw, WJ, WJ, WJ, WJ, IS, /* 10A40 */ B, B, B, B, B, B, B, B, B, WJ, WJ, WJ, WJ, WJ, WJ, WJ, #define use_offset_0x10ac0u 4304 @@ -1531,6 +1532,7 @@ hb_use_get_category (hb_glyph_info_t info) #undef GB #undef H #undef HN +#undef HVM #undef IS #undef J #undef N @@ -1566,5 +1568,5 @@ hb_use_get_category (hb_glyph_info_t info) #undef VMPre -#endif /* HB_OT_SHAPE_COMPLEX_USE_TABLE_HH */ +#endif /* HB_OT_SHAPER_USE_TABLE_HH */ /* == End of generated table == */ diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-use.cc b/thirdparty/harfbuzz/src/hb-ot-shaper-use.cc index 1d13c8a126..60394ed4d8 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-use.cc +++ b/thirdparty/harfbuzz/src/hb-ot-shaper-use.cc @@ -30,11 +30,11 @@ #ifndef HB_NO_OT_SHAPE -#include "hb-ot-shape-complex-use-machine.hh" -#include "hb-ot-shape-complex-use-table.hh" -#include "hb-ot-shape-complex-arabic.hh" -#include "hb-ot-shape-complex-arabic-joining-list.hh" -#include "hb-ot-shape-complex-vowel-constraints.hh" +#include "hb-ot-shaper-use-machine.hh" +#include "hb-ot-shaper-use-table.hh" +#include "hb-ot-shaper-arabic.hh" +#include "hb-ot-shaper-arabic-joining-list.hh" +#include "hb-ot-shaper-vowel-constraints.hh" /* @@ -133,6 +133,7 @@ collect_features_use (hb_ot_shape_planner_t *plan) map->enable_feature (use_basic_features[i], F_MANUAL_ZWJ | F_PER_SYLLABLE); map->add_gsub_pause (reorder_use); + map->add_gsub_pause (hb_syllabic_clear_var); // Don't need syllables anymore, use stop to free buffer var /* "Topographical features" */ for (unsigned int i = 0; i < ARRAY_LENGTH (use_topographical_features); i++) @@ -297,6 +298,7 @@ setup_syllables_use (const hb_ot_shape_plan_t *plan, hb_font_t *font HB_UNUSED, hb_buffer_t *buffer) { + HB_BUFFER_ALLOCATE_VAR (buffer, syllable); find_syllables_use (buffer); foreach_syllable (buffer, start, end) buffer->unsafe_to_break (start, end); @@ -349,7 +351,7 @@ record_pref_use (const hb_ot_shape_plan_t *plan HB_UNUSED, static inline bool is_halant_use (const hb_glyph_info_t &info) { - return (info.use_category() == USE(H) || info.use_category() == USE(IS)) && + return (info.use_category() == USE(H) || info.use_category() == USE(HVM) || info.use_category() == USE(IS)) && !_hb_glyph_info_ligated (&info); } @@ -480,7 +482,7 @@ compose_use (const hb_ot_shape_normalize_context_t *c, } -const hb_ot_complex_shaper_t _hb_ot_complex_shaper_use = +const hb_ot_shaper_t _hb_ot_shaper_use = { collect_features_use, nullptr, /* override_features */ diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-vowel-constraints.cc b/thirdparty/harfbuzz/src/hb-ot-shaper-vowel-constraints.cc index d2cca105a4..be4ac813b1 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-vowel-constraints.cc +++ b/thirdparty/harfbuzz/src/hb-ot-shaper-vowel-constraints.cc @@ -18,7 +18,7 @@ #ifndef HB_NO_OT_SHAPE -#include "hb-ot-shape-complex-vowel-constraints.hh" +#include "hb-ot-shaper-vowel-constraints.hh" static void _output_dotted_circle (hb_buffer_t *buffer) @@ -39,7 +39,7 @@ _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED, hb_buffer_t *buffer, hb_font_t *font HB_UNUSED) { -#ifdef HB_NO_OT_SHAPE_COMPLEX_VOWEL_CONSTRAINTS +#ifdef HB_NO_OT_SHAPER_VOWEL_CONSTRAINTS return; #endif if (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE) diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-vowel-constraints.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-vowel-constraints.hh index d9082d4ead..5a7ee1b0f2 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-vowel-constraints.hh +++ b/thirdparty/harfbuzz/src/hb-ot-shaper-vowel-constraints.hh @@ -24,16 +24,16 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_OT_SHAPE_COMPLEX_VOWEL_CONSTRAINTS_HH -#define HB_OT_SHAPE_COMPLEX_VOWEL_CONSTRAINTS_HH +#ifndef HB_OT_SHAPER_VOWEL_CONSTRAINTS_HH +#define HB_OT_SHAPER_VOWEL_CONSTRAINTS_HH #include "hb.hh" -#include "hb-ot-shape-complex.hh" +#include "hb-ot-shaper.hh" HB_INTERNAL void _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer, hb_font_t *font); -#endif /* HB_OT_SHAPE_COMPLEX_VOWEL_CONSTRAINTS_HH */ +#endif /* HB_OT_SHAPER_VOWEL_CONSTRAINTS_HH */ diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex.hh b/thirdparty/harfbuzz/src/hb-ot-shaper.hh index 8012a9ae94..b823bf003c 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex.hh +++ b/thirdparty/harfbuzz/src/hb-ot-shaper.hh @@ -24,8 +24,8 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_OT_SHAPE_COMPLEX_HH -#define HB_OT_SHAPE_COMPLEX_HH +#ifndef HB_OT_SHAPER_HH +#define HB_OT_SHAPER_HH #include "hb.hh" @@ -34,12 +34,12 @@ #include "hb-ot-shape-normalize.hh" -/* buffer var allocations, used by complex shapers */ -#define complex_var_u8_category() var2.u8[2] -#define complex_var_u8_auxiliary() var2.u8[3] +/* buffer var allocations, used by all OT shapers */ +#define ot_shaper_var_u8_category() var2.u8[2] +#define ot_shaper_var_u8_auxiliary() var2.u8[3] -#define HB_OT_SHAPE_COMPLEX_MAX_COMBINING_MARKS 32 +#define HB_OT_SHAPE_MAX_COMBINING_MARKS 32 enum hb_ot_shape_zero_width_marks_type_t { HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE, @@ -49,22 +49,22 @@ enum hb_ot_shape_zero_width_marks_type_t { /* Master OT shaper list */ -#define HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS \ - HB_COMPLEX_SHAPER_IMPLEMENT (arabic) \ - HB_COMPLEX_SHAPER_IMPLEMENT (default) \ - HB_COMPLEX_SHAPER_IMPLEMENT (dumber) \ - HB_COMPLEX_SHAPER_IMPLEMENT (hangul) \ - HB_COMPLEX_SHAPER_IMPLEMENT (hebrew) \ - HB_COMPLEX_SHAPER_IMPLEMENT (indic) \ - HB_COMPLEX_SHAPER_IMPLEMENT (khmer) \ - HB_COMPLEX_SHAPER_IMPLEMENT (myanmar) \ - HB_COMPLEX_SHAPER_IMPLEMENT (myanmar_zawgyi) \ - HB_COMPLEX_SHAPER_IMPLEMENT (thai) \ - HB_COMPLEX_SHAPER_IMPLEMENT (use) \ +#define HB_OT_SHAPERS_IMPLEMENT_SHAPERS \ + HB_OT_SHAPER_IMPLEMENT (arabic) \ + HB_OT_SHAPER_IMPLEMENT (default) \ + HB_OT_SHAPER_IMPLEMENT (dumber) \ + HB_OT_SHAPER_IMPLEMENT (hangul) \ + HB_OT_SHAPER_IMPLEMENT (hebrew) \ + HB_OT_SHAPER_IMPLEMENT (indic) \ + HB_OT_SHAPER_IMPLEMENT (khmer) \ + HB_OT_SHAPER_IMPLEMENT (myanmar) \ + HB_OT_SHAPER_IMPLEMENT (myanmar_zawgyi) \ + HB_OT_SHAPER_IMPLEMENT (thai) \ + HB_OT_SHAPER_IMPLEMENT (use) \ /* ^--- Add new shapers here; keep sorted. */ -struct hb_ot_complex_shaper_t +struct hb_ot_shaper_t { /* collect_features() * Called during shape_plan(). @@ -168,18 +168,18 @@ struct hb_ot_complex_shaper_t bool fallback_position; }; -#define HB_COMPLEX_SHAPER_IMPLEMENT(name) extern HB_INTERNAL const hb_ot_complex_shaper_t _hb_ot_complex_shaper_##name; -HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS -#undef HB_COMPLEX_SHAPER_IMPLEMENT +#define HB_OT_SHAPER_IMPLEMENT(name) extern HB_INTERNAL const hb_ot_shaper_t _hb_ot_shaper_##name; +HB_OT_SHAPERS_IMPLEMENT_SHAPERS +#undef HB_OT_SHAPER_IMPLEMENT -static inline const hb_ot_complex_shaper_t * -hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner) +static inline const hb_ot_shaper_t * +hb_ot_shaper_categorize (const hb_ot_shape_planner_t *planner) { switch ((hb_tag_t) planner->props.script) { default: - return &_hb_ot_complex_shaper_default; + return &_hb_ot_shaper_default; /* Unicode-1.1 additions */ @@ -195,28 +195,28 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner) if ((planner->map.chosen_script[0] != HB_OT_TAG_DEFAULT_SCRIPT || planner->props.script == HB_SCRIPT_ARABIC) && HB_DIRECTION_IS_HORIZONTAL(planner->props.direction)) - return &_hb_ot_complex_shaper_arabic; + return &_hb_ot_shaper_arabic; else - return &_hb_ot_complex_shaper_default; + return &_hb_ot_shaper_default; /* Unicode-1.1 additions */ case HB_SCRIPT_THAI: case HB_SCRIPT_LAO: - return &_hb_ot_complex_shaper_thai; + return &_hb_ot_shaper_thai; /* Unicode-1.1 additions */ case HB_SCRIPT_HANGUL: - return &_hb_ot_complex_shaper_hangul; + return &_hb_ot_shaper_hangul; /* Unicode-1.1 additions */ case HB_SCRIPT_HEBREW: - return &_hb_ot_complex_shaper_hebrew; + return &_hb_ot_shaper_hebrew; /* Unicode-1.1 additions */ @@ -230,9 +230,6 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner) case HB_SCRIPT_TAMIL: case HB_SCRIPT_TELUGU: - /* Unicode-3.0 additions */ - case HB_SCRIPT_SINHALA: - /* If the designer designed the font for the 'DFLT' script, * (or we ended up arbitrarily pick 'latn'), use the default shaper. * Otherwise, use the specific shaper. @@ -240,14 +237,14 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner) * If it's indy3 tag, send to USE. */ if (planner->map.chosen_script[0] == HB_TAG ('D','F','L','T') || planner->map.chosen_script[0] == HB_TAG ('l','a','t','n')) - return &_hb_ot_complex_shaper_default; + return &_hb_ot_shaper_default; else if ((planner->map.chosen_script[0] & 0x000000FF) == '3') - return &_hb_ot_complex_shaper_use; + return &_hb_ot_shaper_use; else - return &_hb_ot_complex_shaper_indic; + return &_hb_ot_shaper_indic; case HB_SCRIPT_KHMER: - return &_hb_ot_complex_shaper_khmer; + return &_hb_ot_shaper_khmer; case HB_SCRIPT_MYANMAR: /* If the designer designed the font for the 'DFLT' script, @@ -260,16 +257,16 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner) if (planner->map.chosen_script[0] == HB_TAG ('D','F','L','T') || planner->map.chosen_script[0] == HB_TAG ('l','a','t','n') || planner->map.chosen_script[0] == HB_TAG ('m','y','m','r')) - return &_hb_ot_complex_shaper_default; + return &_hb_ot_shaper_default; else - return &_hb_ot_complex_shaper_myanmar; + return &_hb_ot_shaper_myanmar; #define HB_SCRIPT_MYANMAR_ZAWGYI ((hb_script_t) HB_TAG ('Q','a','a','g')) case HB_SCRIPT_MYANMAR_ZAWGYI: /* https://github.com/harfbuzz/harfbuzz/issues/1162 */ - return &_hb_ot_complex_shaper_myanmar_zawgyi; + return &_hb_ot_shaper_myanmar_zawgyi; /* Unicode-2.0 additions */ @@ -277,7 +274,7 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner) /* Unicode-3.0 additions */ case HB_SCRIPT_MONGOLIAN: - //case HB_SCRIPT_SINHALA: + case HB_SCRIPT_SINHALA: /* Unicode-3.2 additions */ case HB_SCRIPT_BUHID: @@ -390,11 +387,11 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner) * GSUB/GPOS needed, so there may be no scripts found! */ if (planner->map.chosen_script[0] == HB_TAG ('D','F','L','T') || planner->map.chosen_script[0] == HB_TAG ('l','a','t','n')) - return &_hb_ot_complex_shaper_default; + return &_hb_ot_shaper_default; else - return &_hb_ot_complex_shaper_use; + return &_hb_ot_shaper_use; } } -#endif /* HB_OT_SHAPE_COMPLEX_HH */ +#endif /* HB_OT_SHAPER_HH */ diff --git a/thirdparty/harfbuzz/src/hb-ot-tag-table.hh b/thirdparty/harfbuzz/src/hb-ot-tag-table.hh index 5261783277..9394b90ee6 100644 --- a/thirdparty/harfbuzz/src/hb-ot-tag-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-tag-table.hh @@ -13,1612 +13,1617 @@ #ifndef HB_OT_TAG_TABLE_HH #define HB_OT_TAG_TABLE_HH -static const LangTag ot_languages[] = { - {"aa", HB_TAG('A','F','R',' ')}, /* Afar */ - {"aae", HB_TAG('S','Q','I',' ')}, /* Arbëreshë Albanian -> Albanian */ - {"aao", HB_TAG('A','R','A',' ')}, /* Algerian Saharan Arabic -> Arabic */ - {"aat", HB_TAG('S','Q','I',' ')}, /* Arvanitika Albanian -> Albanian */ - {"ab", HB_TAG('A','B','K',' ')}, /* Abkhazian */ - {"aba", HB_TAG_NONE }, /* Abé != Abaza */ - {"abh", HB_TAG('A','R','A',' ')}, /* Tajiki Arabic -> Arabic */ - {"abq", HB_TAG('A','B','A',' ')}, /* Abaza */ - {"abs", HB_TAG('C','P','P',' ')}, /* Ambonese Malay -> Creoles */ - {"abv", HB_TAG('A','R','A',' ')}, /* Baharna Arabic -> Arabic */ - {"acf", HB_TAG('F','A','N',' ')}, /* Saint Lucian Creole French -> French Antillean */ - {"acf", HB_TAG('C','P','P',' ')}, /* Saint Lucian Creole French -> Creoles */ -/*{"ach", HB_TAG('A','C','H',' ')},*/ /* Acoli -> Acholi */ - {"acm", HB_TAG('A','R','A',' ')}, /* Mesopotamian Arabic -> Arabic */ - {"acq", HB_TAG('A','R','A',' ')}, /* Ta'izzi-Adeni Arabic -> Arabic */ - {"acr", HB_TAG('A','C','R',' ')}, /* Achi */ - {"acr", HB_TAG('M','Y','N',' ')}, /* Achi -> Mayan */ - {"acw", HB_TAG('A','R','A',' ')}, /* Hijazi Arabic -> Arabic */ - {"acx", HB_TAG('A','R','A',' ')}, /* Omani Arabic -> Arabic */ - {"acy", HB_TAG('A','R','A',' ')}, /* Cypriot Arabic -> Arabic */ - {"ada", HB_TAG('D','N','G',' ')}, /* Adangme -> Dangme */ - {"adf", HB_TAG('A','R','A',' ')}, /* Dhofari Arabic -> Arabic */ - {"adp", HB_TAG('D','Z','N',' ')}, /* Adap (retired code) -> Dzongkha */ -/*{"ady", HB_TAG('A','D','Y',' ')},*/ /* Adyghe */ - {"aeb", HB_TAG('A','R','A',' ')}, /* Tunisian Arabic -> Arabic */ - {"aec", HB_TAG('A','R','A',' ')}, /* Saidi Arabic -> Arabic */ - {"af", HB_TAG('A','F','K',' ')}, /* Afrikaans */ - {"afb", HB_TAG('A','R','A',' ')}, /* Gulf Arabic -> Arabic */ - {"afk", HB_TAG_NONE }, /* Nanubae != Afrikaans */ - {"afs", HB_TAG('C','P','P',' ')}, /* Afro-Seminole Creole -> Creoles */ - {"agu", HB_TAG('M','Y','N',' ')}, /* Aguacateco -> Mayan */ - {"agw", HB_TAG_NONE }, /* Kahua != Agaw */ - {"ahg", HB_TAG('A','G','W',' ')}, /* Qimant -> Agaw */ - {"aht", HB_TAG('A','T','H',' ')}, /* Ahtena -> Athapaskan */ - {"aig", HB_TAG('C','P','P',' ')}, /* Antigua and Barbuda Creole English -> Creoles */ - {"aii", HB_TAG('S','W','A',' ')}, /* Assyrian Neo-Aramaic -> Swadaya Aramaic */ - {"aii", HB_TAG('S','Y','R',' ')}, /* Assyrian Neo-Aramaic -> Syriac */ -/*{"aio", HB_TAG('A','I','O',' ')},*/ /* Aiton */ - {"aiw", HB_TAG('A','R','I',' ')}, /* Aari */ - {"ajp", HB_TAG('A','R','A',' ')}, /* South Levantine Arabic -> Arabic */ - {"ajt", HB_TAG('A','R','A',' ')}, /* Judeo-Tunisian Arabic (retired code) -> Arabic */ - {"ak", HB_TAG('A','K','A',' ')}, /* Akan [macrolanguage] */ - {"akb", HB_TAG('A','K','B',' ')}, /* Batak Angkola */ - {"akb", HB_TAG('B','T','K',' ')}, /* Batak Angkola -> Batak */ - {"aln", HB_TAG('S','Q','I',' ')}, /* Gheg Albanian -> Albanian */ - {"als", HB_TAG('S','Q','I',' ')}, /* Tosk Albanian -> Albanian */ -/*{"alt", HB_TAG('A','L','T',' ')},*/ /* Southern Altai -> Altai */ - {"am", HB_TAG('A','M','H',' ')}, /* Amharic */ - {"amf", HB_TAG('H','B','N',' ')}, /* Hamer-Banna -> Hammer-Banna */ - {"amw", HB_TAG('S','Y','R',' ')}, /* Western Neo-Aramaic -> Syriac */ - {"an", HB_TAG('A','R','G',' ')}, /* Aragonese */ -/*{"ang", HB_TAG('A','N','G',' ')},*/ /* Old English (ca. 450-1100) -> Anglo-Saxon */ - {"aoa", HB_TAG('C','P','P',' ')}, /* Angolar -> Creoles */ - {"apa", HB_TAG('A','T','H',' ')}, /* Apache [collection] -> Athapaskan */ - {"apc", HB_TAG('A','R','A',' ')}, /* North Levantine Arabic -> Arabic */ - {"apd", HB_TAG('A','R','A',' ')}, /* Sudanese Arabic -> Arabic */ - {"apj", HB_TAG('A','T','H',' ')}, /* Jicarilla Apache -> Athapaskan */ - {"apk", HB_TAG('A','T','H',' ')}, /* Kiowa Apache -> Athapaskan */ - {"apl", HB_TAG('A','T','H',' ')}, /* Lipan Apache -> Athapaskan */ - {"apm", HB_TAG('A','T','H',' ')}, /* Mescalero-Chiricahua Apache -> Athapaskan */ - {"apw", HB_TAG('A','T','H',' ')}, /* Western Apache -> Athapaskan */ - {"ar", HB_TAG('A','R','A',' ')}, /* Arabic [macrolanguage] */ - {"arb", HB_TAG('A','R','A',' ')}, /* Standard Arabic -> Arabic */ - {"ari", HB_TAG_NONE }, /* Arikara != Aari */ - {"ark", HB_TAG_NONE }, /* Arikapú != Rakhine */ - {"arn", HB_TAG('M','A','P',' ')}, /* Mapudungun */ - {"arq", HB_TAG('A','R','A',' ')}, /* Algerian Arabic -> Arabic */ - {"ars", HB_TAG('A','R','A',' ')}, /* Najdi Arabic -> Arabic */ - {"ary", HB_TAG('M','O','R',' ')}, /* Moroccan Arabic -> Moroccan */ - {"ary", HB_TAG('A','R','A',' ')}, /* Moroccan Arabic -> Arabic */ - {"arz", HB_TAG('A','R','A',' ')}, /* Egyptian Arabic -> Arabic */ - {"as", HB_TAG('A','S','M',' ')}, /* Assamese */ -/*{"ast", HB_TAG('A','S','T',' ')},*/ /* Asturian */ -/*{"ath", HB_TAG('A','T','H',' ')},*/ /* Athapascan [collection] -> Athapaskan */ - {"atj", HB_TAG('R','C','R',' ')}, /* Atikamekw -> R-Cree */ - {"atv", HB_TAG('A','L','T',' ')}, /* Northern Altai -> Altai */ - {"auj", HB_TAG('B','B','R',' ')}, /* Awjilah -> Berber */ - {"auz", HB_TAG('A','R','A',' ')}, /* Uzbeki Arabic -> Arabic */ - {"av", HB_TAG('A','V','R',' ')}, /* Avaric -> Avar */ - {"avl", HB_TAG('A','R','A',' ')}, /* Eastern Egyptian Bedawi Arabic -> Arabic */ -/*{"avn", HB_TAG('A','V','N',' ')},*/ /* Avatime */ -/*{"awa", HB_TAG('A','W','A',' ')},*/ /* Awadhi */ - {"ay", HB_TAG('A','Y','M',' ')}, /* Aymara [macrolanguage] */ - {"ayc", HB_TAG('A','Y','M',' ')}, /* Southern Aymara -> Aymara */ - {"ayh", HB_TAG('A','R','A',' ')}, /* Hadrami Arabic -> Arabic */ - {"ayl", HB_TAG('A','R','A',' ')}, /* Libyan Arabic -> Arabic */ - {"ayn", HB_TAG('A','R','A',' ')}, /* Sanaani Arabic -> Arabic */ - {"ayp", HB_TAG('A','R','A',' ')}, /* North Mesopotamian Arabic -> Arabic */ - {"ayr", HB_TAG('A','Y','M',' ')}, /* Central Aymara -> Aymara */ - {"az", HB_TAG('A','Z','E',' ')}, /* Azerbaijani [macrolanguage] */ - {"azb", HB_TAG('A','Z','B',' ')}, /* South Azerbaijani -> Torki */ - {"azb", HB_TAG('A','Z','E',' ')}, /* South Azerbaijani -> Azerbaijani */ - {"azd", HB_TAG('N','A','H',' ')}, /* Eastern Durango Nahuatl -> Nahuatl */ - {"azj", HB_TAG('A','Z','E',' ')}, /* North Azerbaijani -> Azerbaijani */ - {"azn", HB_TAG('N','A','H',' ')}, /* Western Durango Nahuatl -> Nahuatl */ - {"azz", HB_TAG('N','A','H',' ')}, /* Highland Puebla Nahuatl -> Nahuatl */ - {"ba", HB_TAG('B','S','H',' ')}, /* Bashkir */ - {"bad", HB_TAG('B','A','D','0')}, /* Banda [collection] */ - {"bag", HB_TAG_NONE }, /* Tuki != Baghelkhandi */ - {"bah", HB_TAG('C','P','P',' ')}, /* Bahamas Creole English -> Creoles */ - {"bai", HB_TAG('B','M','L',' ')}, /* Bamileke [collection] */ - {"bal", HB_TAG('B','L','I',' ')}, /* Baluchi [macrolanguage] */ -/*{"ban", HB_TAG('B','A','N',' ')},*/ /* Balinese */ -/*{"bar", HB_TAG('B','A','R',' ')},*/ /* Bavarian */ - {"bau", HB_TAG_NONE }, /* Bada (Nigeria) != Baulé */ - {"bbc", HB_TAG('B','B','C',' ')}, /* Batak Toba */ - {"bbc", HB_TAG('B','T','K',' ')}, /* Batak Toba -> Batak */ - {"bbj", HB_TAG('B','M','L',' ')}, /* Ghomálá' -> Bamileke */ - {"bbp", HB_TAG('B','A','D','0')}, /* West Central Banda -> Banda */ - {"bbr", HB_TAG_NONE }, /* Girawa != Berber */ - {"bbz", HB_TAG('A','R','A',' ')}, /* Babalia Creole Arabic (retired code) -> Arabic */ - {"bcc", HB_TAG('B','L','I',' ')}, /* Southern Balochi -> Baluchi */ - {"bch", HB_TAG_NONE }, /* Bariai != Bench */ - {"bci", HB_TAG('B','A','U',' ')}, /* Baoulé -> Baulé */ - {"bcl", HB_TAG('B','I','K',' ')}, /* Central Bikol -> Bikol */ - {"bcq", HB_TAG('B','C','H',' ')}, /* Bench */ - {"bcr", HB_TAG('A','T','H',' ')}, /* Babine -> Athapaskan */ -/*{"bdy", HB_TAG('B','D','Y',' ')},*/ /* Bandjalang */ - {"be", HB_TAG('B','E','L',' ')}, /* Belarusian -> Belarussian */ - {"bea", HB_TAG('A','T','H',' ')}, /* Beaver -> Athapaskan */ - {"beb", HB_TAG('B','T','I',' ')}, /* Bebele -> Beti */ -/*{"bem", HB_TAG('B','E','M',' ')},*/ /* Bemba (Zambia) */ - {"ber", HB_TAG('B','B','R',' ')}, /* Berber [collection] */ - {"bew", HB_TAG('C','P','P',' ')}, /* Betawi -> Creoles */ - {"bfl", HB_TAG('B','A','D','0')}, /* Banda-Ndélé -> Banda */ - {"bfq", HB_TAG('B','A','D',' ')}, /* Badaga */ - {"bft", HB_TAG('B','L','T',' ')}, /* Balti */ - {"bfu", HB_TAG('L','A','H',' ')}, /* Gahri -> Lahuli */ - {"bfy", HB_TAG('B','A','G',' ')}, /* Bagheli -> Baghelkhandi */ - {"bg", HB_TAG('B','G','R',' ')}, /* Bulgarian */ -/*{"bgc", HB_TAG('B','G','C',' ')},*/ /* Haryanvi */ - {"bgn", HB_TAG('B','L','I',' ')}, /* Western Balochi -> Baluchi */ - {"bgp", HB_TAG('B','L','I',' ')}, /* Eastern Balochi -> Baluchi */ - {"bgq", HB_TAG('B','G','Q',' ')}, /* Bagri */ - {"bgq", HB_TAG('R','A','J',' ')}, /* Bagri -> Rajasthani */ - {"bgr", HB_TAG('Q','I','N',' ')}, /* Bawm Chin -> Chin */ - {"bhb", HB_TAG('B','H','I',' ')}, /* Bhili */ -/*{"bhi", HB_TAG('B','H','I',' ')},*/ /* Bhilali -> Bhili */ - {"bhk", HB_TAG('B','I','K',' ')}, /* Albay Bicolano (retired code) -> Bikol */ -/*{"bho", HB_TAG('B','H','O',' ')},*/ /* Bhojpuri */ - {"bhr", HB_TAG('M','L','G',' ')}, /* Bara Malagasy -> Malagasy */ - {"bi", HB_TAG('B','I','S',' ')}, /* Bislama */ - {"bi", HB_TAG('C','P','P',' ')}, /* Bislama -> Creoles */ -/*{"bik", HB_TAG('B','I','K',' ')},*/ /* Bikol [macrolanguage] */ - {"bil", HB_TAG_NONE }, /* Bile != Bilen */ - {"bin", HB_TAG('E','D','O',' ')}, /* Edo */ - {"biu", HB_TAG('Q','I','N',' ')}, /* Biete -> Chin */ -/*{"bjj", HB_TAG('B','J','J',' ')},*/ /* Kanauji */ - {"bjn", HB_TAG('M','L','Y',' ')}, /* Banjar -> Malay */ - {"bjo", HB_TAG('B','A','D','0')}, /* Mid-Southern Banda -> Banda */ - {"bjq", HB_TAG('M','L','G',' ')}, /* Southern Betsimisaraka Malagasy (retired code) -> Malagasy */ - {"bjs", HB_TAG('C','P','P',' ')}, /* Bajan -> Creoles */ - {"bjt", HB_TAG('B','L','N',' ')}, /* Balanta-Ganja -> Balante */ - {"bkf", HB_TAG_NONE }, /* Beeke != Blackfoot */ - {"bko", HB_TAG('B','M','L',' ')}, /* Kwa' -> Bamileke */ - {"bla", HB_TAG('B','K','F',' ')}, /* Siksika -> Blackfoot */ - {"ble", HB_TAG('B','L','N',' ')}, /* Balanta-Kentohe -> Balante */ - {"blg", HB_TAG('I','B','A',' ')}, /* Balau (retired code) -> Iban */ - {"bli", HB_TAG_NONE }, /* Bolia != Baluchi */ - {"blk", HB_TAG('B','L','K',' ')}, /* Pa’o Karen */ - {"blk", HB_TAG('K','R','N',' ')}, /* Pa'o Karen -> Karen */ - {"bln", HB_TAG('B','I','K',' ')}, /* Southern Catanduanes Bikol -> Bikol */ - {"blt", HB_TAG_NONE }, /* Tai Dam != Balti */ - {"bm", HB_TAG('B','M','B',' ')}, /* Bambara (Bamanankan) */ - {"bmb", HB_TAG_NONE }, /* Bembe != Bambara (Bamanankan) */ - {"bml", HB_TAG_NONE }, /* Bomboli != Bamileke */ - {"bmm", HB_TAG('M','L','G',' ')}, /* Northern Betsimisaraka Malagasy -> Malagasy */ - {"bn", HB_TAG('B','E','N',' ')}, /* Bengali */ - {"bo", HB_TAG('T','I','B',' ')}, /* Tibetan */ - {"bpd", HB_TAG('B','A','D','0')}, /* Banda-Banda -> Banda */ - {"bpl", HB_TAG('C','P','P',' ')}, /* Broome Pearling Lugger Pidgin -> Creoles */ - {"bpq", HB_TAG('C','P','P',' ')}, /* Banda Malay -> Creoles */ -/*{"bpy", HB_TAG('B','P','Y',' ')},*/ /* Bishnupriya -> Bishnupriya Manipuri */ - {"bqi", HB_TAG('L','R','C',' ')}, /* Bakhtiari -> Luri */ - {"bqk", HB_TAG('B','A','D','0')}, /* Banda-Mbrès -> Banda */ - {"br", HB_TAG('B','R','E',' ')}, /* Breton */ - {"bra", HB_TAG('B','R','I',' ')}, /* Braj -> Braj Bhasha */ - {"brc", HB_TAG('C','P','P',' ')}, /* Berbice Creole Dutch -> Creoles */ -/*{"brh", HB_TAG('B','R','H',' ')},*/ /* Brahui */ - {"bri", HB_TAG_NONE }, /* Mokpwe != Braj Bhasha */ - {"brm", HB_TAG_NONE }, /* Barambu != Burmese */ -/*{"brx", HB_TAG('B','R','X',' ')},*/ /* Bodo (India) */ - {"bs", HB_TAG('B','O','S',' ')}, /* Bosnian */ - {"bsh", HB_TAG_NONE }, /* Kati != Bashkir */ -/*{"bsk", HB_TAG('B','S','K',' ')},*/ /* Burushaski */ - {"btb", HB_TAG('B','T','I',' ')}, /* Beti (Cameroon) (retired code) */ - {"btd", HB_TAG('B','T','D',' ')}, /* Batak Dairi (Pakpak) */ - {"btd", HB_TAG('B','T','K',' ')}, /* Batak Dairi -> Batak */ - {"bti", HB_TAG_NONE }, /* Burate != Beti */ - {"btj", HB_TAG('M','L','Y',' ')}, /* Bacanese Malay -> Malay */ -/*{"btk", HB_TAG('B','T','K',' ')},*/ /* Batak [collection] */ - {"btm", HB_TAG('B','T','M',' ')}, /* Batak Mandailing */ - {"btm", HB_TAG('B','T','K',' ')}, /* Batak Mandailing -> Batak */ - {"bto", HB_TAG('B','I','K',' ')}, /* Rinconada Bikol -> Bikol */ - {"bts", HB_TAG('B','T','S',' ')}, /* Batak Simalungun */ - {"bts", HB_TAG('B','T','K',' ')}, /* Batak Simalungun -> Batak */ - {"btx", HB_TAG('B','T','X',' ')}, /* Batak Karo */ - {"btx", HB_TAG('B','T','K',' ')}, /* Batak Karo -> Batak */ - {"btz", HB_TAG('B','T','Z',' ')}, /* Batak Alas-Kluet */ - {"btz", HB_TAG('B','T','K',' ')}, /* Batak Alas-Kluet -> Batak */ -/*{"bug", HB_TAG('B','U','G',' ')},*/ /* Buginese -> Bugis */ - {"bum", HB_TAG('B','T','I',' ')}, /* Bulu (Cameroon) -> Beti */ - {"bve", HB_TAG('M','L','Y',' ')}, /* Berau Malay -> Malay */ - {"bvu", HB_TAG('M','L','Y',' ')}, /* Bukit Malay -> Malay */ - {"bwe", HB_TAG('K','R','N',' ')}, /* Bwe Karen -> Karen */ - {"bxk", HB_TAG('L','U','H',' ')}, /* Bukusu -> Luyia */ - {"bxo", HB_TAG('C','P','P',' ')}, /* Barikanchi -> Creoles */ - {"bxp", HB_TAG('B','T','I',' ')}, /* Bebil -> Beti */ - {"bxr", HB_TAG('R','B','U',' ')}, /* Russia Buriat -> Russian Buriat */ - {"byn", HB_TAG('B','I','L',' ')}, /* Bilin -> Bilen */ - {"byv", HB_TAG('B','Y','V',' ')}, /* Medumba */ - {"byv", HB_TAG('B','M','L',' ')}, /* Medumba -> Bamileke */ - {"bzc", HB_TAG('M','L','G',' ')}, /* Southern Betsimisaraka Malagasy -> Malagasy */ - {"bzj", HB_TAG('C','P','P',' ')}, /* Belize Kriol English -> Creoles */ - {"bzk", HB_TAG('C','P','P',' ')}, /* Nicaragua Creole English -> Creoles */ - {"ca", HB_TAG('C','A','T',' ')}, /* Catalan */ - {"caa", HB_TAG('M','Y','N',' ')}, /* Chortà -> Mayan */ - {"cac", HB_TAG('M','Y','N',' ')}, /* Chuj -> Mayan */ - {"caf", HB_TAG('C','R','R',' ')}, /* Southern Carrier -> Carrier */ - {"caf", HB_TAG('A','T','H',' ')}, /* Southern Carrier -> Athapaskan */ - {"cak", HB_TAG('C','A','K',' ')}, /* Kaqchikel */ - {"cak", HB_TAG('M','Y','N',' ')}, /* Kaqchikel -> Mayan */ - {"cbk", HB_TAG('C','B','K',' ')}, /* Chavacano -> Zamboanga Chavacano */ - {"cbk", HB_TAG('C','P','P',' ')}, /* Chavacano -> Creoles */ - {"cbl", HB_TAG('Q','I','N',' ')}, /* Bualkhaw Chin -> Chin */ - {"ccl", HB_TAG('C','P','P',' ')}, /* Cutchi-Swahili -> Creoles */ - {"ccm", HB_TAG('C','P','P',' ')}, /* Malaccan Creole Malay -> Creoles */ - {"cco", HB_TAG('C','C','H','N')}, /* Comaltepec Chinantec -> Chinantec */ - {"ccq", HB_TAG('A','R','K',' ')}, /* Chaungtha (retired code) -> Rakhine */ - {"cdo", HB_TAG('Z','H','S',' ')}, /* Min Dong Chinese -> Chinese, Simplified */ - {"ce", HB_TAG('C','H','E',' ')}, /* Chechen */ -/*{"ceb", HB_TAG('C','E','B',' ')},*/ /* Cebuano */ - {"cek", HB_TAG('Q','I','N',' ')}, /* Eastern Khumi Chin -> Chin */ - {"cey", HB_TAG('Q','I','N',' ')}, /* Ekai Chin -> Chin */ - {"cfm", HB_TAG('H','A','L',' ')}, /* Halam (Falam Chin) */ - {"cfm", HB_TAG('Q','I','N',' ')}, /* Falam Chin -> Chin */ -/*{"cgg", HB_TAG('C','G','G',' ')},*/ /* Chiga */ - {"ch", HB_TAG('C','H','A',' ')}, /* Chamorro */ - {"chf", HB_TAG('M','Y','N',' ')}, /* Tabasco Chontal -> Mayan */ - {"chg", HB_TAG_NONE }, /* Chagatai != Chaha Gurage */ - {"chh", HB_TAG_NONE }, /* Chinook != Chattisgarhi */ - {"chj", HB_TAG('C','C','H','N')}, /* Ojitlán Chinantec -> Chinantec */ - {"chk", HB_TAG('C','H','K','0')}, /* Chuukese */ - {"chm", HB_TAG('H','M','A',' ')}, /* Mari (Russia) [macrolanguage] -> High Mari */ - {"chm", HB_TAG('L','M','A',' ')}, /* Mari (Russia) [macrolanguage] -> Low Mari */ - {"chn", HB_TAG('C','P','P',' ')}, /* Chinook jargon -> Creoles */ -/*{"cho", HB_TAG('C','H','O',' ')},*/ /* Choctaw */ - {"chp", HB_TAG('C','H','P',' ')}, /* Chipewyan */ - {"chp", HB_TAG('S','A','Y',' ')}, /* Chipewyan -> Sayisi */ - {"chp", HB_TAG('A','T','H',' ')}, /* Chipewyan -> Athapaskan */ - {"chq", HB_TAG('C','C','H','N')}, /* Quiotepec Chinantec -> Chinantec */ -/*{"chr", HB_TAG('C','H','R',' ')},*/ /* Cherokee */ -/*{"chy", HB_TAG('C','H','Y',' ')},*/ /* Cheyenne */ - {"chz", HB_TAG('C','C','H','N')}, /* OzumacÃn Chinantec -> Chinantec */ - {"ciw", HB_TAG('O','J','B',' ')}, /* Chippewa -> Ojibway */ -/*{"cja", HB_TAG('C','J','A',' ')},*/ /* Western Cham */ -/*{"cjm", HB_TAG('C','J','M',' ')},*/ /* Eastern Cham */ - {"cjy", HB_TAG('Z','H','S',' ')}, /* Jinyu Chinese -> Chinese, Simplified */ - {"cka", HB_TAG('Q','I','N',' ')}, /* Khumi Awa Chin (retired code) -> Chin */ - {"ckb", HB_TAG('K','U','R',' ')}, /* Central Kurdish -> Kurdish */ - {"ckn", HB_TAG('Q','I','N',' ')}, /* Kaang Chin -> Chin */ - {"cks", HB_TAG('C','P','P',' ')}, /* Tayo -> Creoles */ - {"ckt", HB_TAG('C','H','K',' ')}, /* Chukot -> Chukchi */ - {"ckz", HB_TAG('M','Y','N',' ')}, /* Cakchiquel-Quiché Mixed Language -> Mayan */ - {"clc", HB_TAG('A','T','H',' ')}, /* Chilcotin -> Athapaskan */ - {"cld", HB_TAG('S','Y','R',' ')}, /* Chaldean Neo-Aramaic -> Syriac */ - {"cle", HB_TAG('C','C','H','N')}, /* Lealao Chinantec -> Chinantec */ - {"clj", HB_TAG('Q','I','N',' ')}, /* Laitu Chin -> Chin */ - {"clt", HB_TAG('Q','I','N',' ')}, /* Lautu Chin -> Chin */ - {"cmn", HB_TAG('Z','H','S',' ')}, /* Mandarin Chinese -> Chinese, Simplified */ - {"cmr", HB_TAG('Q','I','N',' ')}, /* Mro-Khimi Chin -> Chin */ - {"cnb", HB_TAG('Q','I','N',' ')}, /* Chinbon Chin -> Chin */ - {"cnh", HB_TAG('Q','I','N',' ')}, /* Hakha Chin -> Chin */ - {"cnk", HB_TAG('Q','I','N',' ')}, /* Khumi Chin -> Chin */ - {"cnl", HB_TAG('C','C','H','N')}, /* Lalana Chinantec -> Chinantec */ - {"cnp", HB_TAG('Z','H','S',' ')}, /* Northern Ping Chinese -> Chinese, Simplified */ - {"cnr", HB_TAG('S','R','B',' ')}, /* Montenegrin -> Serbian */ - {"cnt", HB_TAG('C','C','H','N')}, /* Tepetotutla Chinantec -> Chinantec */ - {"cnu", HB_TAG('B','B','R',' ')}, /* Chenoua -> Berber */ - {"cnw", HB_TAG('Q','I','N',' ')}, /* Ngawn Chin -> Chin */ - {"co", HB_TAG('C','O','S',' ')}, /* Corsican */ - {"coa", HB_TAG('M','L','Y',' ')}, /* Cocos Islands Malay -> Malay */ - {"cob", HB_TAG('M','Y','N',' ')}, /* Chicomuceltec -> Mayan */ -/*{"cop", HB_TAG('C','O','P',' ')},*/ /* Coptic */ - {"coq", HB_TAG('A','T','H',' ')}, /* Coquille -> Athapaskan */ - {"cpa", HB_TAG('C','C','H','N')}, /* Palantla Chinantec -> Chinantec */ - {"cpe", HB_TAG('C','P','P',' ')}, /* English-based creoles and pidgins [collection] -> Creoles */ - {"cpf", HB_TAG('C','P','P',' ')}, /* French-based creoles and pidgins [collection] -> Creoles */ - {"cpi", HB_TAG('C','P','P',' ')}, /* Chinese Pidgin English -> Creoles */ -/*{"cpp", HB_TAG('C','P','P',' ')},*/ /* Portuguese-based creoles and pidgins [collection] -> Creoles */ - {"cpx", HB_TAG('Z','H','S',' ')}, /* Pu-Xian Chinese -> Chinese, Simplified */ - {"cqd", HB_TAG('H','M','N',' ')}, /* Chuanqiandian Cluster Miao -> Hmong */ - {"cqu", HB_TAG('Q','U','H',' ')}, /* Chilean Quechua (retired code) -> Quechua (Bolivia) */ - {"cqu", HB_TAG('Q','U','Z',' ')}, /* Chilean Quechua (retired code) -> Quechua */ - {"cr", HB_TAG('C','R','E',' ')}, /* Cree [macrolanguage] */ - {"crh", HB_TAG('C','R','T',' ')}, /* Crimean Tatar */ - {"cri", HB_TAG('C','P','P',' ')}, /* Sãotomense -> Creoles */ - {"crj", HB_TAG('E','C','R',' ')}, /* Southern East Cree -> Eastern Cree */ - {"crj", HB_TAG('Y','C','R',' ')}, /* Southern East Cree -> Y-Cree */ - {"crj", HB_TAG('C','R','E',' ')}, /* Southern East Cree -> Cree */ - {"crk", HB_TAG('W','C','R',' ')}, /* Plains Cree -> West-Cree */ - {"crk", HB_TAG('Y','C','R',' ')}, /* Plains Cree -> Y-Cree */ - {"crk", HB_TAG('C','R','E',' ')}, /* Plains Cree -> Cree */ - {"crl", HB_TAG('E','C','R',' ')}, /* Northern East Cree -> Eastern Cree */ - {"crl", HB_TAG('Y','C','R',' ')}, /* Northern East Cree -> Y-Cree */ - {"crl", HB_TAG('C','R','E',' ')}, /* Northern East Cree -> Cree */ - {"crm", HB_TAG('M','C','R',' ')}, /* Moose Cree */ - {"crm", HB_TAG('L','C','R',' ')}, /* Moose Cree -> L-Cree */ - {"crm", HB_TAG('C','R','E',' ')}, /* Moose Cree -> Cree */ - {"crp", HB_TAG('C','P','P',' ')}, /* Creoles and pidgins [collection] -> Creoles */ - {"crr", HB_TAG_NONE }, /* Carolina Algonquian != Carrier */ - {"crs", HB_TAG('C','P','P',' ')}, /* Seselwa Creole French -> Creoles */ - {"crt", HB_TAG_NONE }, /* Iyojwa'ja Chorote != Crimean Tatar */ - {"crx", HB_TAG('C','R','R',' ')}, /* Carrier */ - {"crx", HB_TAG('A','T','H',' ')}, /* Carrier -> Athapaskan */ - {"cs", HB_TAG('C','S','Y',' ')}, /* Czech */ - {"csa", HB_TAG('C','C','H','N')}, /* Chiltepec Chinantec -> Chinantec */ -/*{"csb", HB_TAG('C','S','B',' ')},*/ /* Kashubian */ - {"csh", HB_TAG('Q','I','N',' ')}, /* Asho Chin -> Chin */ - {"csj", HB_TAG('Q','I','N',' ')}, /* Songlai Chin -> Chin */ - {"csl", HB_TAG_NONE }, /* Chinese Sign Language != Church Slavonic */ - {"cso", HB_TAG('C','C','H','N')}, /* Sochiapam Chinantec -> Chinantec */ - {"csp", HB_TAG('Z','H','S',' ')}, /* Southern Ping Chinese -> Chinese, Simplified */ - {"csv", HB_TAG('Q','I','N',' ')}, /* Sumtu Chin -> Chin */ - {"csw", HB_TAG('N','C','R',' ')}, /* Swampy Cree -> N-Cree */ - {"csw", HB_TAG('N','H','C',' ')}, /* Swampy Cree -> Norway House Cree */ - {"csw", HB_TAG('C','R','E',' ')}, /* Swampy Cree -> Cree */ - {"csy", HB_TAG('Q','I','N',' ')}, /* Siyin Chin -> Chin */ - {"ctc", HB_TAG('A','T','H',' ')}, /* Chetco -> Athapaskan */ - {"ctd", HB_TAG('Q','I','N',' ')}, /* Tedim Chin -> Chin */ - {"cte", HB_TAG('C','C','H','N')}, /* Tepinapa Chinantec -> Chinantec */ -/*{"ctg", HB_TAG('C','T','G',' ')},*/ /* Chittagonian */ - {"cth", HB_TAG('Q','I','N',' ')}, /* Thaiphum Chin -> Chin */ - {"ctl", HB_TAG('C','C','H','N')}, /* Tlacoatzintepec Chinantec -> Chinantec */ - {"cts", HB_TAG('B','I','K',' ')}, /* Northern Catanduanes Bikol -> Bikol */ -/*{"ctt", HB_TAG('C','T','T',' ')},*/ /* Wayanad Chetti */ - {"ctu", HB_TAG('M','Y','N',' ')}, /* Chol -> Mayan */ - {"cu", HB_TAG('C','S','L',' ')}, /* Church Slavonic */ - {"cuc", HB_TAG('C','C','H','N')}, /* Usila Chinantec -> Chinantec */ -/*{"cuk", HB_TAG('C','U','K',' ')},*/ /* San Blas Kuna */ - {"cv", HB_TAG('C','H','U',' ')}, /* Chuvash */ - {"cvn", HB_TAG('C','C','H','N')}, /* Valle Nacional Chinantec -> Chinantec */ - {"cwd", HB_TAG('D','C','R',' ')}, /* Woods Cree */ - {"cwd", HB_TAG('T','C','R',' ')}, /* Woods Cree -> TH-Cree */ - {"cwd", HB_TAG('C','R','E',' ')}, /* Woods Cree -> Cree */ - {"cy", HB_TAG('W','E','L',' ')}, /* Welsh */ - {"czh", HB_TAG('Z','H','S',' ')}, /* Huizhou Chinese -> Chinese, Simplified */ - {"czo", HB_TAG('Z','H','S',' ')}, /* Min Zhong Chinese -> Chinese, Simplified */ - {"czt", HB_TAG('Q','I','N',' ')}, /* Zotung Chin -> Chin */ - {"da", HB_TAG('D','A','N',' ')}, /* Danish */ -/*{"dag", HB_TAG('D','A','G',' ')},*/ /* Dagbani */ - {"dao", HB_TAG('Q','I','N',' ')}, /* Daai Chin -> Chin */ - {"dap", HB_TAG('N','I','S',' ')}, /* Nisi (India) (retired code) */ -/*{"dar", HB_TAG('D','A','R',' ')},*/ /* Dargwa */ -/*{"dax", HB_TAG('D','A','X',' ')},*/ /* Dayi */ - {"dcr", HB_TAG('C','P','P',' ')}, /* Negerhollands -> Creoles */ - {"de", HB_TAG('D','E','U',' ')}, /* German */ - {"den", HB_TAG('S','L','A',' ')}, /* Slave (Athapascan) [macrolanguage] -> Slavey */ - {"den", HB_TAG('A','T','H',' ')}, /* Slave (Athapascan) [macrolanguage] -> Athapaskan */ - {"dep", HB_TAG('C','P','P',' ')}, /* Pidgin Delaware -> Creoles */ - {"dgo", HB_TAG('D','G','O',' ')}, /* Dogri (individual language) */ - {"dgo", HB_TAG('D','G','R',' ')}, /* Dogri (macrolanguage) */ - {"dgr", HB_TAG('A','T','H',' ')}, /* Dogrib -> Athapaskan */ - {"dhd", HB_TAG('M','A','W',' ')}, /* Dhundari -> Marwari */ -/*{"dhg", HB_TAG('D','H','G',' ')},*/ /* Dhangu */ - {"dhv", HB_TAG_NONE }, /* Dehu != Divehi (Dhivehi, Maldivian) (deprecated) */ - {"dib", HB_TAG('D','N','K',' ')}, /* South Central Dinka -> Dinka */ - {"dik", HB_TAG('D','N','K',' ')}, /* Southwestern Dinka -> Dinka */ - {"din", HB_TAG('D','N','K',' ')}, /* Dinka [macrolanguage] */ - {"dip", HB_TAG('D','N','K',' ')}, /* Northeastern Dinka -> Dinka */ - {"diq", HB_TAG('D','I','Q',' ')}, /* Dimli */ - {"diq", HB_TAG('Z','Z','A',' ')}, /* Dimli -> Zazaki */ - {"diw", HB_TAG('D','N','K',' ')}, /* Northwestern Dinka -> Dinka */ - {"dje", HB_TAG('D','J','R',' ')}, /* Zarma */ - {"djk", HB_TAG('C','P','P',' ')}, /* Eastern Maroon Creole -> Creoles */ - {"djr", HB_TAG('D','J','R','0')}, /* Djambarrpuyngu */ - {"dks", HB_TAG('D','N','K',' ')}, /* Southeastern Dinka -> Dinka */ - {"dng", HB_TAG('D','U','N',' ')}, /* Dungan */ -/*{"dnj", HB_TAG('D','N','J',' ')},*/ /* Dan */ - {"dnk", HB_TAG_NONE }, /* Dengka != Dinka */ - {"doi", HB_TAG('D','G','R',' ')}, /* Dogri (macrolanguage) [macrolanguage] */ - {"drh", HB_TAG('M','N','G',' ')}, /* Darkhat (retired code) -> Mongolian */ - {"dri", HB_TAG_NONE }, /* C'Lela != Dari */ - {"drw", HB_TAG('D','R','I',' ')}, /* Darwazi (retired code) -> Dari */ - {"drw", HB_TAG('F','A','R',' ')}, /* Darwazi (retired code) -> Persian */ - {"dsb", HB_TAG('L','S','B',' ')}, /* Lower Sorbian */ - {"dty", HB_TAG('N','E','P',' ')}, /* Dotyali -> Nepali */ -/*{"duj", HB_TAG('D','U','J',' ')},*/ /* Dhuwal (retired code) */ - {"dun", HB_TAG_NONE }, /* Dusun Deyah != Dungan */ - {"dup", HB_TAG('M','L','Y',' ')}, /* Duano -> Malay */ - {"dv", HB_TAG('D','I','V',' ')}, /* Divehi (Dhivehi, Maldivian) */ - {"dv", HB_TAG('D','H','V',' ')}, /* Divehi (Dhivehi, Maldivian) (deprecated) */ - {"dwk", HB_TAG('K','U','I',' ')}, /* Dawik Kui -> Kui */ - {"dwu", HB_TAG('D','U','J',' ')}, /* Dhuwal */ - {"dwy", HB_TAG('D','U','J',' ')}, /* Dhuwaya -> Dhuwal */ - {"dyu", HB_TAG('J','U','L',' ')}, /* Dyula -> Jula */ - {"dz", HB_TAG('D','Z','N',' ')}, /* Dzongkha */ - {"dzn", HB_TAG_NONE }, /* Dzando != Dzongkha */ - {"ecr", HB_TAG_NONE }, /* Eteocretan != Eastern Cree */ - {"ee", HB_TAG('E','W','E',' ')}, /* Ewe */ -/*{"efi", HB_TAG('E','F','I',' ')},*/ /* Efik */ - {"ekk", HB_TAG('E','T','I',' ')}, /* Standard Estonian -> Estonian */ - {"eky", HB_TAG('K','R','N',' ')}, /* Eastern Kayah -> Karen */ - {"el", HB_TAG('E','L','L',' ')}, /* Modern Greek (1453-) -> Greek */ - {"emk", HB_TAG('E','M','K',' ')}, /* Eastern Maninkakan */ - {"emk", HB_TAG('M','N','K',' ')}, /* Eastern Maninkakan -> Maninka */ - {"emy", HB_TAG('M','Y','N',' ')}, /* Epigraphic Mayan -> Mayan */ - {"en", HB_TAG('E','N','G',' ')}, /* English */ - {"enb", HB_TAG('K','A','L',' ')}, /* Markweeta -> Kalenjin */ - {"enf", HB_TAG('F','N','E',' ')}, /* Forest Enets */ - {"enh", HB_TAG('T','N','E',' ')}, /* Tundra Enets */ - {"eo", HB_TAG('N','T','O',' ')}, /* Esperanto */ - {"es", HB_TAG('E','S','P',' ')}, /* Spanish */ - {"esg", HB_TAG('G','O','N',' ')}, /* Aheri Gondi -> Gondi */ - {"esi", HB_TAG('I','P','K',' ')}, /* North Alaskan Inupiatun -> Inupiat */ - {"esk", HB_TAG('I','P','K',' ')}, /* Northwest Alaska Inupiatun -> Inupiat */ -/*{"esu", HB_TAG('E','S','U',' ')},*/ /* Central Yupik */ - {"et", HB_TAG('E','T','I',' ')}, /* Estonian [macrolanguage] */ - {"eto", HB_TAG('B','T','I',' ')}, /* Eton (Cameroon) -> Beti */ - {"eu", HB_TAG('E','U','Q',' ')}, /* Basque */ - {"euq", HB_TAG_NONE }, /* Basque [collection] != Basque */ - {"eve", HB_TAG('E','V','N',' ')}, /* Even */ - {"evn", HB_TAG('E','V','K',' ')}, /* Evenki */ - {"ewo", HB_TAG('B','T','I',' ')}, /* Ewondo -> Beti */ - {"eyo", HB_TAG('K','A','L',' ')}, /* Keiyo -> Kalenjin */ - {"fa", HB_TAG('F','A','R',' ')}, /* Persian [macrolanguage] */ - {"fab", HB_TAG('C','P','P',' ')}, /* Fa d'Ambu -> Creoles */ - {"fan", HB_TAG('F','A','N','0')}, /* Fang (Equatorial Guinea) */ - {"fan", HB_TAG('B','T','I',' ')}, /* Fang (Equatorial Guinea) -> Beti */ - {"far", HB_TAG_NONE }, /* Fataleka != Persian */ - {"fat", HB_TAG('F','A','T',' ')}, /* Fanti */ - {"fat", HB_TAG('A','K','A',' ')}, /* Fanti -> Akan */ - {"fbl", HB_TAG('B','I','K',' ')}, /* West Albay Bikol -> Bikol */ - {"ff", HB_TAG('F','U','L',' ')}, /* Fulah [macrolanguage] */ - {"ffm", HB_TAG('F','U','L',' ')}, /* Maasina Fulfulde -> Fulah */ - {"fi", HB_TAG('F','I','N',' ')}, /* Finnish */ - {"fil", HB_TAG('P','I','L',' ')}, /* Filipino */ - {"fj", HB_TAG('F','J','I',' ')}, /* Fijian */ - {"flm", HB_TAG('H','A','L',' ')}, /* Halam (Falam Chin) (retired code) */ - {"flm", HB_TAG('Q','I','N',' ')}, /* Falam Chin (retired code) -> Chin */ - {"fmp", HB_TAG('F','M','P',' ')}, /* Fe’fe’ */ - {"fmp", HB_TAG('B','M','L',' ')}, /* Fe'fe' -> Bamileke */ - {"fng", HB_TAG('C','P','P',' ')}, /* Fanagalo -> Creoles */ - {"fo", HB_TAG('F','O','S',' ')}, /* Faroese */ -/*{"fon", HB_TAG('F','O','N',' ')},*/ /* Fon */ - {"fos", HB_TAG_NONE }, /* Siraya != Faroese */ - {"fpe", HB_TAG('C','P','P',' ')}, /* Fernando Po Creole English -> Creoles */ - {"fr", HB_TAG('F','R','A',' ')}, /* French */ -/*{"frc", HB_TAG('F','R','C',' ')},*/ /* Cajun French */ -/*{"frp", HB_TAG('F','R','P',' ')},*/ /* Arpitan */ - {"fub", HB_TAG('F','U','L',' ')}, /* Adamawa Fulfulde -> Fulah */ - {"fuc", HB_TAG('F','U','L',' ')}, /* Pulaar -> Fulah */ - {"fue", HB_TAG('F','U','L',' ')}, /* Borgu Fulfulde -> Fulah */ - {"fuf", HB_TAG('F','T','A',' ')}, /* Pular -> Futa */ - {"fuf", HB_TAG('F','U','L',' ')}, /* Pular -> Fulah */ - {"fuh", HB_TAG('F','U','L',' ')}, /* Western Niger Fulfulde -> Fulah */ - {"fui", HB_TAG('F','U','L',' ')}, /* Bagirmi Fulfulde -> Fulah */ - {"fuq", HB_TAG('F','U','L',' ')}, /* Central-Eastern Niger Fulfulde -> Fulah */ - {"fur", HB_TAG('F','R','L',' ')}, /* Friulian */ - {"fuv", HB_TAG('F','U','V',' ')}, /* Nigerian Fulfulde */ - {"fuv", HB_TAG('F','U','L',' ')}, /* Nigerian Fulfulde -> Fulah */ - {"fy", HB_TAG('F','R','I',' ')}, /* Western Frisian -> Frisian */ - {"ga", HB_TAG('I','R','I',' ')}, /* Irish */ - {"gaa", HB_TAG('G','A','D',' ')}, /* Ga */ - {"gac", HB_TAG('C','P','P',' ')}, /* Mixed Great Andamanese -> Creoles */ - {"gad", HB_TAG_NONE }, /* Gaddang != Ga */ - {"gae", HB_TAG_NONE }, /* Guarequena != Scottish Gaelic (Gaelic) */ -/*{"gag", HB_TAG('G','A','G',' ')},*/ /* Gagauz */ - {"gal", HB_TAG_NONE }, /* Galolen != Galician */ - {"gan", HB_TAG('Z','H','S',' ')}, /* Gan Chinese -> Chinese, Simplified */ - {"gar", HB_TAG_NONE }, /* Galeya != Garshuni */ - {"gaw", HB_TAG_NONE }, /* Nobonob != Garhwali */ - {"gax", HB_TAG('O','R','O',' ')}, /* Borana-Arsi-Guji Oromo -> Oromo */ - {"gaz", HB_TAG('O','R','O',' ')}, /* West Central Oromo -> Oromo */ - {"gbm", HB_TAG('G','A','W',' ')}, /* Garhwali */ - {"gce", HB_TAG('A','T','H',' ')}, /* Galice -> Athapaskan */ - {"gcf", HB_TAG('C','P','P',' ')}, /* Guadeloupean Creole French -> Creoles */ - {"gcl", HB_TAG('C','P','P',' ')}, /* Grenadian Creole English -> Creoles */ - {"gcr", HB_TAG('C','P','P',' ')}, /* Guianese Creole French -> Creoles */ - {"gd", HB_TAG('G','A','E',' ')}, /* Scottish Gaelic (Gaelic) */ - {"gda", HB_TAG('R','A','J',' ')}, /* Gade Lohar -> Rajasthani */ -/*{"gez", HB_TAG('G','E','Z',' ')},*/ /* Geez */ - {"ggo", HB_TAG('G','O','N',' ')}, /* Southern Gondi (retired code) -> Gondi */ - {"gha", HB_TAG('B','B','R',' ')}, /* Ghadamès -> Berber */ - {"ghk", HB_TAG('K','R','N',' ')}, /* Geko Karen -> Karen */ - {"gho", HB_TAG('B','B','R',' ')}, /* Ghomara -> Berber */ - {"gib", HB_TAG('C','P','P',' ')}, /* Gibanawa -> Creoles */ -/*{"gih", HB_TAG('G','I','H',' ')},*/ /* Githabul */ - {"gil", HB_TAG('G','I','L','0')}, /* Kiribati (Gilbertese) */ - {"gju", HB_TAG('R','A','J',' ')}, /* Gujari -> Rajasthani */ - {"gkp", HB_TAG('G','K','P',' ')}, /* Guinea Kpelle -> Kpelle (Guinea) */ - {"gkp", HB_TAG('K','P','L',' ')}, /* Guinea Kpelle -> Kpelle */ - {"gl", HB_TAG('G','A','L',' ')}, /* Galician */ - {"gld", HB_TAG('N','A','N',' ')}, /* Nanai */ -/*{"glk", HB_TAG('G','L','K',' ')},*/ /* Gilaki */ - {"gmz", HB_TAG_NONE }, /* Mgbolizhia != Gumuz */ - {"gn", HB_TAG('G','U','A',' ')}, /* Guarani [macrolanguage] */ - {"gnb", HB_TAG('Q','I','N',' ')}, /* Gangte -> Chin */ -/*{"gnn", HB_TAG('G','N','N',' ')},*/ /* Gumatj */ - {"gno", HB_TAG('G','O','N',' ')}, /* Northern Gondi -> Gondi */ - {"gnw", HB_TAG('G','U','A',' ')}, /* Western Bolivian Guaranà -> Guarani */ -/*{"gog", HB_TAG('G','O','G',' ')},*/ /* Gogo */ - {"gom", HB_TAG('K','O','K',' ')}, /* Goan Konkani -> Konkani */ -/*{"gon", HB_TAG('G','O','N',' ')},*/ /* Gondi [macrolanguage] */ - {"goq", HB_TAG('C','P','P',' ')}, /* Gorap -> Creoles */ - {"gox", HB_TAG('B','A','D','0')}, /* Gobu -> Banda */ - {"gpe", HB_TAG('C','P','P',' ')}, /* Ghanaian Pidgin English -> Creoles */ - {"gro", HB_TAG_NONE }, /* Groma != Garo */ - {"grr", HB_TAG('B','B','R',' ')}, /* Taznatit -> Berber */ - {"grt", HB_TAG('G','R','O',' ')}, /* Garo */ - {"gru", HB_TAG('S','O','G',' ')}, /* Kistane -> Sodo Gurage */ - {"gsw", HB_TAG('A','L','S',' ')}, /* Alsatian */ - {"gu", HB_TAG('G','U','J',' ')}, /* Gujarati */ - {"gua", HB_TAG_NONE }, /* Shiki != Guarani */ -/*{"guc", HB_TAG('G','U','C',' ')},*/ /* Wayuu */ -/*{"guf", HB_TAG('G','U','F',' ')},*/ /* Gupapuyngu */ - {"gug", HB_TAG('G','U','A',' ')}, /* Paraguayan Guaranà -> Guarani */ - {"gui", HB_TAG('G','U','A',' ')}, /* Eastern Bolivian Guaranà -> Guarani */ - {"guk", HB_TAG('G','M','Z',' ')}, /* Gumuz */ - {"gul", HB_TAG('C','P','P',' ')}, /* Sea Island Creole English -> Creoles */ - {"gun", HB_TAG('G','U','A',' ')}, /* Mbyá Guaranà -> Guarani */ -/*{"guz", HB_TAG('G','U','Z',' ')},*/ /* Gusii */ - {"gv", HB_TAG('M','N','X',' ')}, /* Manx */ - {"gwi", HB_TAG('A','T','H',' ')}, /* Gwichʼin -> Athapaskan */ - {"gyn", HB_TAG('C','P','P',' ')}, /* Guyanese Creole English -> Creoles */ - {"ha", HB_TAG('H','A','U',' ')}, /* Hausa */ - {"haa", HB_TAG('A','T','H',' ')}, /* Han -> Athapaskan */ - {"hae", HB_TAG('O','R','O',' ')}, /* Eastern Oromo -> Oromo */ - {"hai", HB_TAG('H','A','I','0')}, /* Haida [macrolanguage] */ - {"hak", HB_TAG('Z','H','S',' ')}, /* Hakka Chinese -> Chinese, Simplified */ - {"hal", HB_TAG_NONE }, /* Halang != Halam (Falam Chin) */ - {"har", HB_TAG('H','R','I',' ')}, /* Harari */ -/*{"haw", HB_TAG('H','A','W',' ')},*/ /* Hawaiian */ - {"hax", HB_TAG('H','A','I','0')}, /* Southern Haida -> Haida */ -/*{"hay", HB_TAG('H','A','Y',' ')},*/ /* Haya */ -/*{"haz", HB_TAG('H','A','Z',' ')},*/ /* Hazaragi */ - {"hbn", HB_TAG_NONE }, /* Heiban != Hammer-Banna */ - {"hca", HB_TAG('C','P','P',' ')}, /* Andaman Creole Hindi -> Creoles */ - {"hdn", HB_TAG('H','A','I','0')}, /* Northern Haida -> Haida */ - {"he", HB_TAG('I','W','R',' ')}, /* Hebrew */ - {"hea", HB_TAG('H','M','N',' ')}, /* Northern Qiandong Miao -> Hmong */ -/*{"hei", HB_TAG('H','E','I',' ')},*/ /* Heiltsuk */ - {"hi", HB_TAG('H','I','N',' ')}, /* Hindi */ -/*{"hil", HB_TAG('H','I','L',' ')},*/ /* Hiligaynon */ - {"hji", HB_TAG('M','L','Y',' ')}, /* Haji -> Malay */ - {"hlt", HB_TAG('Q','I','N',' ')}, /* Matu Chin -> Chin */ - {"hma", HB_TAG('H','M','N',' ')}, /* Southern Mashan Hmong -> Hmong */ - {"hmc", HB_TAG('H','M','N',' ')}, /* Central Huishui Hmong -> Hmong */ - {"hmd", HB_TAG('H','M','D',' ')}, /* Large Flowery Miao -> A-Hmao */ - {"hmd", HB_TAG('H','M','N',' ')}, /* Large Flowery Miao -> Hmong */ - {"hme", HB_TAG('H','M','N',' ')}, /* Eastern Huishui Hmong -> Hmong */ - {"hmg", HB_TAG('H','M','N',' ')}, /* Southwestern Guiyang Hmong -> Hmong */ - {"hmh", HB_TAG('H','M','N',' ')}, /* Southwestern Huishui Hmong -> Hmong */ - {"hmi", HB_TAG('H','M','N',' ')}, /* Northern Huishui Hmong -> Hmong */ - {"hmj", HB_TAG('H','M','N',' ')}, /* Ge -> Hmong */ - {"hml", HB_TAG('H','M','N',' ')}, /* Luopohe Hmong -> Hmong */ - {"hmm", HB_TAG('H','M','N',' ')}, /* Central Mashan Hmong -> Hmong */ -/*{"hmn", HB_TAG('H','M','N',' ')},*/ /* Hmong [macrolanguage] */ - {"hmp", HB_TAG('H','M','N',' ')}, /* Northern Mashan Hmong -> Hmong */ - {"hmq", HB_TAG('H','M','N',' ')}, /* Eastern Qiandong Miao -> Hmong */ - {"hmr", HB_TAG('Q','I','N',' ')}, /* Hmar -> Chin */ - {"hms", HB_TAG('H','M','N',' ')}, /* Southern Qiandong Miao -> Hmong */ - {"hmw", HB_TAG('H','M','N',' ')}, /* Western Mashan Hmong -> Hmong */ - {"hmy", HB_TAG('H','M','N',' ')}, /* Southern Guiyang Hmong -> Hmong */ - {"hmz", HB_TAG('H','M','Z',' ')}, /* Hmong Shua -> Hmong Shuat */ - {"hmz", HB_TAG('H','M','N',' ')}, /* Hmong Shua -> Hmong */ -/*{"hnd", HB_TAG('H','N','D',' ')},*/ /* Southern Hindko -> Hindko */ - {"hne", HB_TAG('C','H','H',' ')}, /* Chhattisgarhi -> Chattisgarhi */ - {"hnj", HB_TAG('H','M','N',' ')}, /* Hmong Njua -> Hmong */ - {"hno", HB_TAG('H','N','D',' ')}, /* Northern Hindko -> Hindko */ - {"ho", HB_TAG('H','M','O',' ')}, /* Hiri Motu */ - {"ho", HB_TAG('C','P','P',' ')}, /* Hiri Motu -> Creoles */ - {"hoc", HB_TAG('H','O',' ',' ')}, /* Ho */ - {"hoi", HB_TAG('A','T','H',' ')}, /* Holikachuk -> Athapaskan */ - {"hoj", HB_TAG('H','A','R',' ')}, /* Hadothi -> Harauti */ - {"hoj", HB_TAG('R','A','J',' ')}, /* Hadothi -> Rajasthani */ - {"hr", HB_TAG('H','R','V',' ')}, /* Croatian */ - {"hra", HB_TAG('Q','I','N',' ')}, /* Hrangkhol -> Chin */ - {"hrm", HB_TAG('H','M','N',' ')}, /* Horned Miao -> Hmong */ - {"hsb", HB_TAG('U','S','B',' ')}, /* Upper Sorbian */ - {"hsn", HB_TAG('Z','H','S',' ')}, /* Xiang Chinese -> Chinese, Simplified */ - {"ht", HB_TAG('H','A','I',' ')}, /* Haitian (Haitian Creole) */ - {"ht", HB_TAG('C','P','P',' ')}, /* Haitian -> Creoles */ - {"hu", HB_TAG('H','U','N',' ')}, /* Hungarian */ - {"huj", HB_TAG('H','M','N',' ')}, /* Northern Guiyang Hmong -> Hmong */ - {"hup", HB_TAG('A','T','H',' ')}, /* Hupa -> Athapaskan */ - {"hus", HB_TAG('M','Y','N',' ')}, /* Huastec -> Mayan */ - {"hwc", HB_TAG('C','P','P',' ')}, /* Hawai'i Creole English -> Creoles */ - {"hy", HB_TAG('H','Y','E','0')}, /* Armenian -> Armenian East */ - {"hy", HB_TAG('H','Y','E',' ')}, /* Armenian */ - {"hyw", HB_TAG('H','Y','E',' ')}, /* Western Armenian -> Armenian */ - {"hz", HB_TAG('H','E','R',' ')}, /* Herero */ - {"ia", HB_TAG('I','N','A',' ')}, /* Interlingua (International Auxiliary Language Association) */ -/*{"iba", HB_TAG('I','B','A',' ')},*/ /* Iban */ -/*{"ibb", HB_TAG('I','B','B',' ')},*/ /* Ibibio */ - {"iby", HB_TAG('I','J','O',' ')}, /* Ibani -> Ijo */ - {"icr", HB_TAG('C','P','P',' ')}, /* Islander Creole English -> Creoles */ - {"id", HB_TAG('I','N','D',' ')}, /* Indonesian */ - {"id", HB_TAG('M','L','Y',' ')}, /* Indonesian -> Malay */ - {"ida", HB_TAG('L','U','H',' ')}, /* Idakho-Isukha-Tiriki -> Luyia */ - {"idb", HB_TAG('C','P','P',' ')}, /* Indo-Portuguese -> Creoles */ - {"ie", HB_TAG('I','L','E',' ')}, /* Interlingue */ - {"ig", HB_TAG('I','B','O',' ')}, /* Igbo */ - {"igb", HB_TAG('E','B','I',' ')}, /* Ebira */ - {"ihb", HB_TAG('C','P','P',' ')}, /* Iha Based Pidgin -> Creoles */ - {"ii", HB_TAG('Y','I','M',' ')}, /* Sichuan Yi -> Yi Modern */ - {"ijc", HB_TAG('I','J','O',' ')}, /* Izon -> Ijo */ - {"ije", HB_TAG('I','J','O',' ')}, /* Biseni -> Ijo */ - {"ijn", HB_TAG('I','J','O',' ')}, /* Kalabari -> Ijo */ -/*{"ijo", HB_TAG('I','J','O',' ')},*/ /* Ijo [collection] */ - {"ijs", HB_TAG('I','J','O',' ')}, /* Southeast Ijo -> Ijo */ - {"ik", HB_TAG('I','P','K',' ')}, /* Inupiaq [macrolanguage] -> Inupiat */ - {"ike", HB_TAG('I','N','U',' ')}, /* Eastern Canadian Inuktitut -> Inuktitut */ - {"ike", HB_TAG('I','N','U','K')}, /* Eastern Canadian Inuktitut -> Nunavik Inuktitut */ - {"ikt", HB_TAG('I','N','U',' ')}, /* Inuinnaqtun -> Inuktitut */ -/*{"ilo", HB_TAG('I','L','O',' ')},*/ /* Iloko -> Ilokano */ - {"in", HB_TAG('I','N','D',' ')}, /* Indonesian (retired code) */ - {"in", HB_TAG('M','L','Y',' ')}, /* Indonesian (retired code) -> Malay */ - {"ing", HB_TAG('A','T','H',' ')}, /* Degexit'an -> Athapaskan */ - {"inh", HB_TAG('I','N','G',' ')}, /* Ingush */ - {"io", HB_TAG('I','D','O',' ')}, /* Ido */ - {"iri", HB_TAG_NONE }, /* Rigwe != Irish */ -/*{"iru", HB_TAG('I','R','U',' ')},*/ /* Irula */ - {"is", HB_TAG('I','S','L',' ')}, /* Icelandic */ - {"ism", HB_TAG_NONE }, /* Masimasi != Inari Sami */ - {"it", HB_TAG('I','T','A',' ')}, /* Italian */ - {"itz", HB_TAG('M','Y','N',' ')}, /* Itzá -> Mayan */ - {"iu", HB_TAG('I','N','U',' ')}, /* Inuktitut [macrolanguage] */ - {"iu", HB_TAG('I','N','U','K')}, /* Inuktitut [macrolanguage] -> Nunavik Inuktitut */ - {"iw", HB_TAG('I','W','R',' ')}, /* Hebrew (retired code) */ - {"ixl", HB_TAG('M','Y','N',' ')}, /* Ixil -> Mayan */ - {"ja", HB_TAG('J','A','N',' ')}, /* Japanese */ - {"jac", HB_TAG('M','Y','N',' ')}, /* Popti' -> Mayan */ - {"jak", HB_TAG('M','L','Y',' ')}, /* Jakun -> Malay */ - {"jam", HB_TAG('J','A','M',' ')}, /* Jamaican Creole English -> Jamaican Creole */ - {"jam", HB_TAG('C','P','P',' ')}, /* Jamaican Creole English -> Creoles */ - {"jan", HB_TAG_NONE }, /* Jandai != Japanese */ - {"jax", HB_TAG('M','L','Y',' ')}, /* Jambi Malay -> Malay */ - {"jbe", HB_TAG('B','B','R',' ')}, /* Judeo-Berber -> Berber */ - {"jbn", HB_TAG('B','B','R',' ')}, /* Nafusi -> Berber */ -/*{"jbo", HB_TAG('J','B','O',' ')},*/ /* Lojban */ -/*{"jct", HB_TAG('J','C','T',' ')},*/ /* Krymchak */ - {"jgo", HB_TAG('B','M','L',' ')}, /* Ngomba -> Bamileke */ - {"ji", HB_TAG('J','I','I',' ')}, /* Yiddish (retired code) */ - {"jii", HB_TAG_NONE }, /* Jiiddu != Yiddish */ - {"jkm", HB_TAG('K','R','N',' ')}, /* Mobwa Karen -> Karen */ - {"jkp", HB_TAG('K','R','N',' ')}, /* Paku Karen -> Karen */ - {"jud", HB_TAG_NONE }, /* Worodougou != Ladino */ - {"jul", HB_TAG_NONE }, /* Jirel != Jula */ - {"jv", HB_TAG('J','A','V',' ')}, /* Javanese */ - {"jvd", HB_TAG('C','P','P',' ')}, /* Javindo -> Creoles */ - {"jw", HB_TAG('J','A','V',' ')}, /* Javanese (retired code) */ - {"ka", HB_TAG('K','A','T',' ')}, /* Georgian */ - {"kaa", HB_TAG('K','R','K',' ')}, /* Karakalpak */ - {"kab", HB_TAG('K','A','B','0')}, /* Kabyle */ - {"kab", HB_TAG('B','B','R',' ')}, /* Kabyle -> Berber */ - {"kac", HB_TAG_NONE }, /* Kachin != Kachchi */ - {"kam", HB_TAG('K','M','B',' ')}, /* Kamba (Kenya) */ - {"kar", HB_TAG('K','R','N',' ')}, /* Karen [collection] */ -/*{"kaw", HB_TAG('K','A','W',' ')},*/ /* Kawi (Old Javanese) */ - {"kbd", HB_TAG('K','A','B',' ')}, /* Kabardian */ - {"kby", HB_TAG('K','N','R',' ')}, /* Manga Kanuri -> Kanuri */ - {"kca", HB_TAG('K','H','K',' ')}, /* Khanty -> Khanty-Kazim */ - {"kca", HB_TAG('K','H','S',' ')}, /* Khanty -> Khanty-Shurishkar */ - {"kca", HB_TAG('K','H','V',' ')}, /* Khanty -> Khanty-Vakhi */ - {"kcn", HB_TAG('C','P','P',' ')}, /* Nubi -> Creoles */ -/*{"kde", HB_TAG('K','D','E',' ')},*/ /* Makonde */ - {"kdr", HB_TAG('K','R','M',' ')}, /* Karaim */ - {"kdt", HB_TAG('K','U','Y',' ')}, /* Kuy */ - {"kea", HB_TAG('K','E','A',' ')}, /* Kabuverdianu (Crioulo) */ - {"kea", HB_TAG('C','P','P',' ')}, /* Kabuverdianu -> Creoles */ - {"keb", HB_TAG_NONE }, /* Kélé != Kebena */ - {"kek", HB_TAG('K','E','K',' ')}, /* Kekchi */ - {"kek", HB_TAG('M','Y','N',' ')}, /* Kekchà -> Mayan */ - {"kex", HB_TAG('K','K','N',' ')}, /* Kukna -> Kokni */ - {"kfa", HB_TAG('K','O','D',' ')}, /* Kodava -> Kodagu */ - {"kfr", HB_TAG('K','A','C',' ')}, /* Kachhi -> Kachchi */ - {"kfx", HB_TAG('K','U','L',' ')}, /* Kullu Pahari -> Kulvi */ - {"kfy", HB_TAG('K','M','N',' ')}, /* Kumaoni */ - {"kg", HB_TAG('K','O','N','0')}, /* Kongo [macrolanguage] */ - {"kge", HB_TAG_NONE }, /* Komering != Khutsuri Georgian */ - {"kha", HB_TAG('K','S','I',' ')}, /* Khasi */ - {"khb", HB_TAG('X','B','D',' ')}, /* Lü */ - {"khk", HB_TAG('M','N','G',' ')}, /* Halh Mongolian -> Mongolian */ - {"khn", HB_TAG_NONE }, /* Khandesi != Khamti Shan (Microsoft fonts) */ - {"khs", HB_TAG_NONE }, /* Kasua != Khanty-Shurishkar */ - {"kht", HB_TAG('K','H','T',' ')}, /* Khamti -> Khamti Shan */ - {"kht", HB_TAG('K','H','N',' ')}, /* Khamti -> Khamti Shan (Microsoft fonts) */ - {"khv", HB_TAG_NONE }, /* Khvarshi != Khanty-Vakhi */ -/*{"khw", HB_TAG('K','H','W',' ')},*/ /* Khowar */ - {"ki", HB_TAG('K','I','K',' ')}, /* Kikuyu (Gikuyu) */ - {"kis", HB_TAG_NONE }, /* Kis != Kisii */ - {"kiu", HB_TAG('K','I','U',' ')}, /* Kirmanjki */ - {"kiu", HB_TAG('Z','Z','A',' ')}, /* Kirmanjki -> Zazaki */ - {"kj", HB_TAG('K','U','A',' ')}, /* Kuanyama */ - {"kjb", HB_TAG('M','Y','N',' ')}, /* Q'anjob'al -> Mayan */ -/*{"kjd", HB_TAG('K','J','D',' ')},*/ /* Southern Kiwai */ - {"kjh", HB_TAG('K','H','A',' ')}, /* Khakas -> Khakass */ - {"kjp", HB_TAG('K','J','P',' ')}, /* Pwo Eastern Karen -> Eastern Pwo Karen */ - {"kjp", HB_TAG('K','R','N',' ')}, /* Pwo Eastern Karen -> Karen */ - {"kjt", HB_TAG('K','R','N',' ')}, /* Phrae Pwo Karen -> Karen */ -/*{"kjz", HB_TAG('K','J','Z',' ')},*/ /* Bumthangkha */ - {"kk", HB_TAG('K','A','Z',' ')}, /* Kazakh */ - {"kkn", HB_TAG_NONE }, /* Kon Keu != Kokni */ - {"kkz", HB_TAG('A','T','H',' ')}, /* Kaska -> Athapaskan */ - {"kl", HB_TAG('G','R','N',' ')}, /* Greenlandic */ - {"klm", HB_TAG_NONE }, /* Migum != Kalmyk */ - {"kln", HB_TAG('K','A','L',' ')}, /* Kalenjin [macrolanguage] */ - {"km", HB_TAG('K','H','M',' ')}, /* Khmer */ - {"kmb", HB_TAG('M','B','N',' ')}, /* Kimbundu -> Mbundu */ - {"kmn", HB_TAG_NONE }, /* Awtuw != Kumaoni */ - {"kmo", HB_TAG_NONE }, /* Kwoma != Komo */ - {"kmr", HB_TAG('K','U','R',' ')}, /* Northern Kurdish -> Kurdish */ - {"kms", HB_TAG_NONE }, /* Kamasau != Komso */ - {"kmv", HB_TAG('C','P','P',' ')}, /* Karipúna Creole French -> Creoles */ - {"kmw", HB_TAG('K','M','O',' ')}, /* Komo (Democratic Republic of Congo) */ -/*{"kmz", HB_TAG('K','M','Z',' ')},*/ /* Khorasani Turkish -> Khorasani Turkic */ - {"kn", HB_TAG('K','A','N',' ')}, /* Kannada */ - {"knc", HB_TAG('K','N','R',' ')}, /* Central Kanuri -> Kanuri */ - {"kng", HB_TAG('K','O','N','0')}, /* Koongo -> Kongo */ - {"knj", HB_TAG('M','Y','N',' ')}, /* Western Kanjobal -> Mayan */ - {"knn", HB_TAG('K','O','K',' ')}, /* Konkani */ - {"knr", HB_TAG_NONE }, /* Kaningra != Kanuri */ - {"ko", HB_TAG('K','O','R',' ')}, /* Korean */ - {"ko", HB_TAG('K','O','H',' ')}, /* Korean -> Korean Old Hangul */ - {"kod", HB_TAG_NONE }, /* Kodi != Kodagu */ - {"koh", HB_TAG_NONE }, /* Koyo != Korean Old Hangul */ - {"koi", HB_TAG('K','O','P',' ')}, /* Komi-Permyak */ - {"koi", HB_TAG('K','O','M',' ')}, /* Komi-Permyak -> Komi */ -/*{"kok", HB_TAG('K','O','K',' ')},*/ /* Konkani [macrolanguage] */ - {"kop", HB_TAG_NONE }, /* Waube != Komi-Permyak */ -/*{"kos", HB_TAG('K','O','S',' ')},*/ /* Kosraean */ - {"koy", HB_TAG('A','T','H',' ')}, /* Koyukon -> Athapaskan */ - {"koz", HB_TAG_NONE }, /* Korak != Komi-Zyrian */ - {"kpe", HB_TAG('K','P','L',' ')}, /* Kpelle [macrolanguage] */ - {"kpl", HB_TAG_NONE }, /* Kpala != Kpelle */ - {"kpp", HB_TAG('K','R','N',' ')}, /* Paku Karen (retired code) -> Karen */ - {"kpv", HB_TAG('K','O','Z',' ')}, /* Komi-Zyrian */ - {"kpv", HB_TAG('K','O','M',' ')}, /* Komi-Zyrian -> Komi */ - {"kpy", HB_TAG('K','Y','K',' ')}, /* Koryak */ - {"kqs", HB_TAG('K','I','S',' ')}, /* Northern Kissi -> Kisii */ - {"kqy", HB_TAG('K','R','T',' ')}, /* Koorete */ - {"kr", HB_TAG('K','N','R',' ')}, /* Kanuri [macrolanguage] */ - {"krc", HB_TAG('K','A','R',' ')}, /* Karachay-Balkar -> Karachay */ - {"krc", HB_TAG('B','A','L',' ')}, /* Karachay-Balkar -> Balkar */ - {"kri", HB_TAG('K','R','I',' ')}, /* Krio */ - {"kri", HB_TAG('C','P','P',' ')}, /* Krio -> Creoles */ - {"krk", HB_TAG_NONE }, /* Kerek != Karakalpak */ -/*{"krl", HB_TAG('K','R','L',' ')},*/ /* Karelian */ - {"krm", HB_TAG_NONE }, /* Krim (retired code) != Karaim */ - {"krn", HB_TAG_NONE }, /* Sapo != Karen */ - {"krt", HB_TAG('K','N','R',' ')}, /* Tumari Kanuri -> Kanuri */ - {"kru", HB_TAG('K','U','U',' ')}, /* Kurukh */ - {"ks", HB_TAG('K','S','H',' ')}, /* Kashmiri */ - {"ksh", HB_TAG('K','S','H','0')}, /* Kölsch -> Ripuarian */ - {"ksi", HB_TAG_NONE }, /* Krisa != Khasi */ - {"ksm", HB_TAG_NONE }, /* Kumba != Kildin Sami */ - {"kss", HB_TAG('K','I','S',' ')}, /* Southern Kisi -> Kisii */ - {"ksw", HB_TAG('K','S','W',' ')}, /* S’gaw Karen */ - {"ksw", HB_TAG('K','R','N',' ')}, /* S'gaw Karen -> Karen */ - {"ktb", HB_TAG('K','E','B',' ')}, /* Kambaata -> Kebena */ - {"ktu", HB_TAG('K','O','N',' ')}, /* Kituba (Democratic Republic of Congo) -> Kikongo */ - {"ktw", HB_TAG('A','T','H',' ')}, /* Kato -> Athapaskan */ - {"ku", HB_TAG('K','U','R',' ')}, /* Kurdish [macrolanguage] */ - {"kui", HB_TAG_NONE }, /* Kuikúro-Kalapálo != Kui */ - {"kul", HB_TAG_NONE }, /* Kulere != Kulvi */ -/*{"kum", HB_TAG('K','U','M',' ')},*/ /* Kumyk */ - {"kuu", HB_TAG('A','T','H',' ')}, /* Upper Kuskokwim -> Athapaskan */ - {"kuw", HB_TAG('B','A','D','0')}, /* Kpagua -> Banda */ - {"kuy", HB_TAG_NONE }, /* Kuuku-Ya'u != Kuy */ - {"kv", HB_TAG('K','O','M',' ')}, /* Komi [macrolanguage] */ - {"kvb", HB_TAG('M','L','Y',' ')}, /* Kubu -> Malay */ - {"kvl", HB_TAG('K','R','N',' ')}, /* Kayaw -> Karen */ - {"kvq", HB_TAG('K','R','N',' ')}, /* Geba Karen -> Karen */ - {"kvr", HB_TAG('M','L','Y',' ')}, /* Kerinci -> Malay */ - {"kvt", HB_TAG('K','R','N',' ')}, /* Lahta Karen -> Karen */ - {"kvu", HB_TAG('K','R','N',' ')}, /* Yinbaw Karen -> Karen */ - {"kvy", HB_TAG('K','R','N',' ')}, /* Yintale Karen -> Karen */ - {"kw", HB_TAG('C','O','R',' ')}, /* Cornish */ -/*{"kwk", HB_TAG('K','W','K',' ')},*/ /* Kwakiutl -> Kwakʼwala */ - {"kww", HB_TAG('C','P','P',' ')}, /* Kwinti -> Creoles */ - {"kwy", HB_TAG('K','O','N','0')}, /* San Salvador Kongo -> Kongo */ - {"kxc", HB_TAG('K','M','S',' ')}, /* Konso -> Komso */ - {"kxd", HB_TAG('M','L','Y',' ')}, /* Brunei -> Malay */ - {"kxf", HB_TAG('K','R','N',' ')}, /* Manumanaw Karen -> Karen */ - {"kxk", HB_TAG('K','R','N',' ')}, /* Zayein Karen -> Karen */ - {"kxl", HB_TAG('K','U','U',' ')}, /* Nepali Kurux (retired code) -> Kurukh */ - {"kxu", HB_TAG('K','U','I',' ')}, /* Kui (India) (retired code) */ - {"ky", HB_TAG('K','I','R',' ')}, /* Kirghiz (Kyrgyz) */ - {"kyk", HB_TAG_NONE }, /* Kamayo != Koryak */ - {"kyu", HB_TAG('K','Y','U',' ')}, /* Western Kayah */ - {"kyu", HB_TAG('K','R','N',' ')}, /* Western Kayah -> Karen */ - {"la", HB_TAG('L','A','T',' ')}, /* Latin */ - {"lac", HB_TAG('M','Y','N',' ')}, /* Lacandon -> Mayan */ - {"lad", HB_TAG('J','U','D',' ')}, /* Ladino */ - {"lah", HB_TAG_NONE }, /* Lahnda [macrolanguage] != Lahuli */ - {"lak", HB_TAG_NONE }, /* Laka (Nigeria) (retired code) != Lak */ - {"lam", HB_TAG_NONE }, /* Lamba != Lambani */ - {"laz", HB_TAG_NONE }, /* Aribwatsa != Laz */ - {"lb", HB_TAG('L','T','Z',' ')}, /* Luxembourgish */ - {"lbe", HB_TAG('L','A','K',' ')}, /* Lak */ - {"lbj", HB_TAG('L','D','K',' ')}, /* Ladakhi */ - {"lbl", HB_TAG('B','I','K',' ')}, /* Libon Bikol -> Bikol */ - {"lce", HB_TAG('M','L','Y',' ')}, /* Loncong -> Malay */ - {"lcf", HB_TAG('M','L','Y',' ')}, /* Lubu -> Malay */ - {"ldi", HB_TAG('K','O','N','0')}, /* Laari -> Kongo */ - {"ldk", HB_TAG_NONE }, /* Leelau != Ladakhi */ -/*{"lef", HB_TAG('L','E','F',' ')},*/ /* Lelemi */ -/*{"lez", HB_TAG('L','E','Z',' ')},*/ /* Lezghian -> Lezgi */ - {"lg", HB_TAG('L','U','G',' ')}, /* Ganda */ - {"li", HB_TAG('L','I','M',' ')}, /* Limburgish */ - {"lif", HB_TAG('L','M','B',' ')}, /* Limbu */ -/*{"lij", HB_TAG('L','I','J',' ')},*/ /* Ligurian */ - {"lir", HB_TAG('C','P','P',' ')}, /* Liberian English -> Creoles */ -/*{"lis", HB_TAG('L','I','S',' ')},*/ /* Lisu */ - {"liw", HB_TAG('M','L','Y',' ')}, /* Col -> Malay */ - {"liy", HB_TAG('B','A','D','0')}, /* Banda-Bambari -> Banda */ -/*{"ljp", HB_TAG('L','J','P',' ')},*/ /* Lampung Api -> Lampung */ - {"lkb", HB_TAG('L','U','H',' ')}, /* Kabras -> Luyia */ -/*{"lki", HB_TAG('L','K','I',' ')},*/ /* Laki */ - {"lko", HB_TAG('L','U','H',' ')}, /* Khayo -> Luyia */ - {"lks", HB_TAG('L','U','H',' ')}, /* Kisa -> Luyia */ - {"lld", HB_TAG('L','A','D',' ')}, /* Ladin */ - {"lma", HB_TAG_NONE }, /* East Limba != Low Mari */ - {"lmb", HB_TAG_NONE }, /* Merei != Limbu */ - {"lmn", HB_TAG('L','A','M',' ')}, /* Lambadi -> Lambani */ -/*{"lmo", HB_TAG('L','M','O',' ')},*/ /* Lombard */ - {"lmw", HB_TAG_NONE }, /* Lake Miwok != Lomwe */ - {"ln", HB_TAG('L','I','N',' ')}, /* Lingala */ - {"lna", HB_TAG('B','A','D','0')}, /* Langbashe -> Banda */ - {"lnl", HB_TAG('B','A','D','0')}, /* South Central Banda -> Banda */ - {"lo", HB_TAG('L','A','O',' ')}, /* Lao */ -/*{"lom", HB_TAG('L','O','M',' ')},*/ /* Loma (Liberia) */ - {"lou", HB_TAG('C','P','P',' ')}, /* Louisiana Creole -> Creoles */ -/*{"lpo", HB_TAG('L','P','O',' ')},*/ /* Lipo */ -/*{"lrc", HB_TAG('L','R','C',' ')},*/ /* Northern Luri -> Luri */ - {"lri", HB_TAG('L','U','H',' ')}, /* Marachi -> Luyia */ - {"lrm", HB_TAG('L','U','H',' ')}, /* Marama -> Luyia */ - {"lrt", HB_TAG('C','P','P',' ')}, /* Larantuka Malay -> Creoles */ - {"lsb", HB_TAG_NONE }, /* Burundian Sign Language != Lower Sorbian */ - {"lsm", HB_TAG('L','U','H',' ')}, /* Saamia -> Luyia */ - {"lt", HB_TAG('L','T','H',' ')}, /* Lithuanian */ - {"ltg", HB_TAG('L','V','I',' ')}, /* Latgalian -> Latvian */ - {"lth", HB_TAG_NONE }, /* Thur != Lithuanian */ - {"lto", HB_TAG('L','U','H',' ')}, /* Tsotso -> Luyia */ - {"lts", HB_TAG('L','U','H',' ')}, /* Tachoni -> Luyia */ - {"lu", HB_TAG('L','U','B',' ')}, /* Luba-Katanga */ -/*{"lua", HB_TAG('L','U','A',' ')},*/ /* Luba-Lulua */ -/*{"luo", HB_TAG('L','U','O',' ')},*/ /* Luo (Kenya and Tanzania) */ - {"lus", HB_TAG('M','I','Z',' ')}, /* Lushai -> Mizo */ - {"lus", HB_TAG('Q','I','N',' ')}, /* Lushai -> Chin */ - {"luy", HB_TAG('L','U','H',' ')}, /* Luyia [macrolanguage] */ - {"luz", HB_TAG('L','R','C',' ')}, /* Southern Luri -> Luri */ - {"lv", HB_TAG('L','V','I',' ')}, /* Latvian [macrolanguage] */ - {"lvi", HB_TAG_NONE }, /* Lavi != Latvian */ - {"lvs", HB_TAG('L','V','I',' ')}, /* Standard Latvian -> Latvian */ - {"lwg", HB_TAG('L','U','H',' ')}, /* Wanga -> Luyia */ - {"lzh", HB_TAG('Z','H','T',' ')}, /* Literary Chinese -> Chinese, Traditional */ - {"lzz", HB_TAG('L','A','Z',' ')}, /* Laz */ -/*{"mad", HB_TAG('M','A','D',' ')},*/ /* Madurese -> Madura */ -/*{"mag", HB_TAG('M','A','G',' ')},*/ /* Magahi */ - {"mai", HB_TAG('M','T','H',' ')}, /* Maithili */ - {"maj", HB_TAG_NONE }, /* Jalapa De DÃaz Mazatec != Majang */ - {"mak", HB_TAG('M','K','R',' ')}, /* Makasar */ - {"mam", HB_TAG('M','A','M',' ')}, /* Mam */ - {"mam", HB_TAG('M','Y','N',' ')}, /* Mam -> Mayan */ - {"man", HB_TAG('M','N','K',' ')}, /* Mandingo [macrolanguage] -> Maninka */ - {"map", HB_TAG_NONE }, /* Austronesian [collection] != Mapudungun */ - {"maw", HB_TAG_NONE }, /* Mampruli != Marwari */ - {"max", HB_TAG('M','L','Y',' ')}, /* North Moluccan Malay -> Malay */ - {"max", HB_TAG('C','P','P',' ')}, /* North Moluccan Malay -> Creoles */ - {"mbf", HB_TAG('C','P','P',' ')}, /* Baba Malay -> Creoles */ - {"mbn", HB_TAG_NONE }, /* Macaguán != Mbundu */ -/*{"mbo", HB_TAG('M','B','O',' ')},*/ /* Mbo (Cameroon) */ - {"mch", HB_TAG_NONE }, /* Maquiritari != Manchu */ - {"mcm", HB_TAG('C','P','P',' ')}, /* Malaccan Creole Portuguese -> Creoles */ - {"mcr", HB_TAG_NONE }, /* Menya != Moose Cree */ - {"mct", HB_TAG('B','T','I',' ')}, /* Mengisa -> Beti */ - {"mde", HB_TAG_NONE }, /* Maba (Chad) != Mende */ - {"mdf", HB_TAG('M','O','K',' ')}, /* Moksha */ -/*{"mdr", HB_TAG('M','D','R',' ')},*/ /* Mandar */ - {"mdy", HB_TAG('M','L','E',' ')}, /* Male (Ethiopia) */ - {"men", HB_TAG('M','D','E',' ')}, /* Mende (Sierra Leone) */ - {"meo", HB_TAG('M','L','Y',' ')}, /* Kedah Malay -> Malay */ -/*{"mer", HB_TAG('M','E','R',' ')},*/ /* Meru */ - {"mfa", HB_TAG('M','F','A',' ')}, /* Pattani Malay */ - {"mfa", HB_TAG('M','L','Y',' ')}, /* Pattani Malay -> Malay */ - {"mfb", HB_TAG('M','L','Y',' ')}, /* Bangka -> Malay */ - {"mfe", HB_TAG('M','F','E',' ')}, /* Morisyen */ - {"mfe", HB_TAG('C','P','P',' ')}, /* Morisyen -> Creoles */ - {"mfp", HB_TAG('C','P','P',' ')}, /* Makassar Malay -> Creoles */ - {"mg", HB_TAG('M','L','G',' ')}, /* Malagasy [macrolanguage] */ - {"mh", HB_TAG('M','A','H',' ')}, /* Marshallese */ - {"mhc", HB_TAG('M','Y','N',' ')}, /* Mocho -> Mayan */ - {"mhr", HB_TAG('L','M','A',' ')}, /* Eastern Mari -> Low Mari */ - {"mhv", HB_TAG('A','R','K',' ')}, /* Arakanese (retired code) -> Rakhine */ - {"mi", HB_TAG('M','R','I',' ')}, /* Maori */ - {"min", HB_TAG('M','I','N',' ')}, /* Minangkabau */ - {"min", HB_TAG('M','L','Y',' ')}, /* Minangkabau -> Malay */ - {"miz", HB_TAG_NONE }, /* Coatzospan Mixtec != Mizo */ - {"mk", HB_TAG('M','K','D',' ')}, /* Macedonian */ - {"mkn", HB_TAG('C','P','P',' ')}, /* Kupang Malay -> Creoles */ - {"mkr", HB_TAG_NONE }, /* Malas != Makasar */ - {"mku", HB_TAG('M','N','K',' ')}, /* Konyanka Maninka -> Maninka */ -/*{"mkw", HB_TAG('M','K','W',' ')},*/ /* Kituba (Congo) */ - {"ml", HB_TAG('M','A','L',' ')}, /* Malayalam -> Malayalam Traditional */ - {"ml", HB_TAG('M','L','R',' ')}, /* Malayalam -> Malayalam Reformed */ - {"mle", HB_TAG_NONE }, /* Manambu != Male */ - {"mln", HB_TAG_NONE }, /* Malango != Malinke */ - {"mlq", HB_TAG('M','L','N',' ')}, /* Western Maninkakan -> Malinke */ - {"mlq", HB_TAG('M','N','K',' ')}, /* Western Maninkakan -> Maninka */ - {"mlr", HB_TAG_NONE }, /* Vame != Malayalam Reformed */ - {"mmr", HB_TAG('H','M','N',' ')}, /* Western Xiangxi Miao -> Hmong */ - {"mn", HB_TAG('M','N','G',' ')}, /* Mongolian [macrolanguage] */ - {"mnc", HB_TAG('M','C','H',' ')}, /* Manchu */ - {"mnd", HB_TAG_NONE }, /* Mondé != Mandinka */ - {"mng", HB_TAG_NONE }, /* Eastern Mnong != Mongolian */ - {"mnh", HB_TAG('B','A','D','0')}, /* Mono (Democratic Republic of Congo) -> Banda */ -/*{"mni", HB_TAG('M','N','I',' ')},*/ /* Manipuri */ - {"mnk", HB_TAG('M','N','D',' ')}, /* Mandinka */ - {"mnk", HB_TAG('M','N','K',' ')}, /* Mandinka -> Maninka */ - {"mnp", HB_TAG('Z','H','S',' ')}, /* Min Bei Chinese -> Chinese, Simplified */ - {"mns", HB_TAG('M','A','N',' ')}, /* Mansi */ - {"mnw", HB_TAG('M','O','N',' ')}, /* Mon */ - {"mnw", HB_TAG('M','O','N','T')}, /* Mon -> Thailand Mon */ - {"mnx", HB_TAG_NONE }, /* Manikion != Manx */ - {"mo", HB_TAG('M','O','L',' ')}, /* Moldavian (retired code) */ - {"mo", HB_TAG('R','O','M',' ')}, /* Moldavian (retired code) -> Romanian */ - {"mod", HB_TAG('C','P','P',' ')}, /* Mobilian -> Creoles */ -/*{"moh", HB_TAG('M','O','H',' ')},*/ /* Mohawk */ - {"mok", HB_TAG_NONE }, /* Morori != Moksha */ - {"mop", HB_TAG('M','Y','N',' ')}, /* Mopán Maya -> Mayan */ - {"mor", HB_TAG_NONE }, /* Moro != Moroccan */ -/*{"mos", HB_TAG('M','O','S',' ')},*/ /* Mossi */ - {"mpe", HB_TAG('M','A','J',' ')}, /* Majang */ - {"mqg", HB_TAG('M','L','Y',' ')}, /* Kota Bangun Kutai Malay -> Malay */ - {"mr", HB_TAG('M','A','R',' ')}, /* Marathi */ - {"mrh", HB_TAG('Q','I','N',' ')}, /* Mara Chin -> Chin */ - {"mrj", HB_TAG('H','M','A',' ')}, /* Western Mari -> High Mari */ - {"ms", HB_TAG('M','L','Y',' ')}, /* Malay [macrolanguage] */ - {"msc", HB_TAG('M','N','K',' ')}, /* Sankaran Maninka -> Maninka */ - {"msh", HB_TAG('M','L','G',' ')}, /* Masikoro Malagasy -> Malagasy */ - {"msi", HB_TAG('M','L','Y',' ')}, /* Sabah Malay -> Malay */ - {"msi", HB_TAG('C','P','P',' ')}, /* Sabah Malay -> Creoles */ - {"mt", HB_TAG('M','T','S',' ')}, /* Maltese */ - {"mth", HB_TAG_NONE }, /* Munggui != Maithili */ - {"mtr", HB_TAG('M','A','W',' ')}, /* Mewari -> Marwari */ - {"mts", HB_TAG_NONE }, /* Yora != Maltese */ - {"mud", HB_TAG('C','P','P',' ')}, /* Mednyj Aleut -> Creoles */ - {"mui", HB_TAG('M','L','Y',' ')}, /* Musi -> Malay */ - {"mun", HB_TAG_NONE }, /* Munda [collection] != Mundari */ - {"mup", HB_TAG('R','A','J',' ')}, /* Malvi -> Rajasthani */ - {"muq", HB_TAG('H','M','N',' ')}, /* Eastern Xiangxi Miao -> Hmong */ -/*{"mus", HB_TAG('M','U','S',' ')},*/ /* Creek -> Muscogee */ - {"mvb", HB_TAG('A','T','H',' ')}, /* Mattole -> Athapaskan */ - {"mve", HB_TAG('M','A','W',' ')}, /* Marwari (Pakistan) */ - {"mvf", HB_TAG('M','N','G',' ')}, /* Peripheral Mongolian -> Mongolian */ - {"mwk", HB_TAG('M','N','K',' ')}, /* Kita Maninkakan -> Maninka */ -/*{"mwl", HB_TAG('M','W','L',' ')},*/ /* Mirandese */ - {"mwq", HB_TAG('Q','I','N',' ')}, /* Mün Chin -> Chin */ - {"mwr", HB_TAG('M','A','W',' ')}, /* Marwari [macrolanguage] */ - {"mww", HB_TAG('M','W','W',' ')}, /* Hmong Daw */ - {"mww", HB_TAG('H','M','N',' ')}, /* Hmong Daw -> Hmong */ - {"my", HB_TAG('B','R','M',' ')}, /* Burmese */ - {"mym", HB_TAG('M','E','N',' ')}, /* Me’en */ -/*{"myn", HB_TAG('M','Y','N',' ')},*/ /* Mayan [collection] */ - {"myq", HB_TAG('M','N','K',' ')}, /* Forest Maninka (retired code) -> Maninka */ - {"myv", HB_TAG('E','R','Z',' ')}, /* Erzya */ - {"mzb", HB_TAG('B','B','R',' ')}, /* Tumzabt -> Berber */ -/*{"mzn", HB_TAG('M','Z','N',' ')},*/ /* Mazanderani */ - {"mzs", HB_TAG('C','P','P',' ')}, /* Macanese -> Creoles */ - {"na", HB_TAG('N','A','U',' ')}, /* Nauru -> Nauruan */ - {"nag", HB_TAG('N','A','G',' ')}, /* Naga Pidgin -> Naga-Assamese */ - {"nag", HB_TAG('C','P','P',' ')}, /* Naga Pidgin -> Creoles */ -/*{"nah", HB_TAG('N','A','H',' ')},*/ /* Nahuatl [collection] */ - {"nan", HB_TAG('Z','H','S',' ')}, /* Min Nan Chinese -> Chinese, Simplified */ -/*{"nap", HB_TAG('N','A','P',' ')},*/ /* Neapolitan */ - {"nas", HB_TAG_NONE }, /* Naasioi != Naskapi */ - {"naz", HB_TAG('N','A','H',' ')}, /* Coatepec Nahuatl -> Nahuatl */ - {"nb", HB_TAG('N','O','R',' ')}, /* Norwegian BokmÃ¥l -> Norwegian */ - {"nch", HB_TAG('N','A','H',' ')}, /* Central Huasteca Nahuatl -> Nahuatl */ - {"nci", HB_TAG('N','A','H',' ')}, /* Classical Nahuatl -> Nahuatl */ - {"ncj", HB_TAG('N','A','H',' ')}, /* Northern Puebla Nahuatl -> Nahuatl */ - {"ncl", HB_TAG('N','A','H',' ')}, /* Michoacán Nahuatl -> Nahuatl */ - {"ncr", HB_TAG_NONE }, /* Ncane != N-Cree */ - {"ncx", HB_TAG('N','A','H',' ')}, /* Central Puebla Nahuatl -> Nahuatl */ - {"nd", HB_TAG('N','D','B',' ')}, /* North Ndebele -> Ndebele */ - {"ndb", HB_TAG_NONE }, /* Kenswei Nsei != Ndebele */ -/*{"ndc", HB_TAG('N','D','C',' ')},*/ /* Ndau */ - {"ndg", HB_TAG_NONE }, /* Ndengereko != Ndonga */ -/*{"nds", HB_TAG('N','D','S',' ')},*/ /* Low Saxon */ - {"ne", HB_TAG('N','E','P',' ')}, /* Nepali [macrolanguage] */ - {"nef", HB_TAG('C','P','P',' ')}, /* Nefamese -> Creoles */ -/*{"new", HB_TAG('N','E','W',' ')},*/ /* Newari */ - {"ng", HB_TAG('N','D','G',' ')}, /* Ndonga */ -/*{"nga", HB_TAG('N','G','A',' ')},*/ /* Ngbaka */ - {"ngl", HB_TAG('L','M','W',' ')}, /* Lomwe */ - {"ngm", HB_TAG('C','P','P',' ')}, /* Ngatik Men's Creole -> Creoles */ - {"ngo", HB_TAG('S','X','T',' ')}, /* Ngoni (retired code) -> Sutu */ - {"ngr", HB_TAG_NONE }, /* Engdewu != Nagari */ - {"ngu", HB_TAG('N','A','H',' ')}, /* Guerrero Nahuatl -> Nahuatl */ - {"nhc", HB_TAG('N','A','H',' ')}, /* Tabasco Nahuatl -> Nahuatl */ - {"nhd", HB_TAG('G','U','A',' ')}, /* Chiripá -> Guarani */ - {"nhe", HB_TAG('N','A','H',' ')}, /* Eastern Huasteca Nahuatl -> Nahuatl */ - {"nhg", HB_TAG('N','A','H',' ')}, /* Tetelcingo Nahuatl -> Nahuatl */ - {"nhi", HB_TAG('N','A','H',' ')}, /* Zacatlán-Ahuacatlán-Tepetzintla Nahuatl -> Nahuatl */ - {"nhk", HB_TAG('N','A','H',' ')}, /* Isthmus-Cosoleacaque Nahuatl -> Nahuatl */ - {"nhm", HB_TAG('N','A','H',' ')}, /* Morelos Nahuatl -> Nahuatl */ - {"nhn", HB_TAG('N','A','H',' ')}, /* Central Nahuatl -> Nahuatl */ - {"nhp", HB_TAG('N','A','H',' ')}, /* Isthmus-Pajapan Nahuatl -> Nahuatl */ - {"nhq", HB_TAG('N','A','H',' ')}, /* Huaxcaleca Nahuatl -> Nahuatl */ - {"nht", HB_TAG('N','A','H',' ')}, /* Ometepec Nahuatl -> Nahuatl */ - {"nhv", HB_TAG('N','A','H',' ')}, /* Temascaltepec Nahuatl -> Nahuatl */ - {"nhw", HB_TAG('N','A','H',' ')}, /* Western Huasteca Nahuatl -> Nahuatl */ - {"nhx", HB_TAG('N','A','H',' ')}, /* Isthmus-Mecayapan Nahuatl -> Nahuatl */ - {"nhy", HB_TAG('N','A','H',' ')}, /* Northern Oaxaca Nahuatl -> Nahuatl */ - {"nhz", HB_TAG('N','A','H',' ')}, /* Santa MarÃa La Alta Nahuatl -> Nahuatl */ - {"niq", HB_TAG('K','A','L',' ')}, /* Nandi -> Kalenjin */ - {"nis", HB_TAG_NONE }, /* Nimi != Nisi */ -/*{"niu", HB_TAG('N','I','U',' ')},*/ /* Niuean */ - {"niv", HB_TAG('G','I','L',' ')}, /* Gilyak */ - {"njt", HB_TAG('C','P','P',' ')}, /* Ndyuka-Trio Pidgin -> Creoles */ - {"njz", HB_TAG('N','I','S',' ')}, /* Nyishi -> Nisi */ - {"nko", HB_TAG_NONE }, /* Nkonya != N’Ko */ - {"nkx", HB_TAG('I','J','O',' ')}, /* Nkoroo -> Ijo */ - {"nl", HB_TAG('N','L','D',' ')}, /* Dutch */ - {"nla", HB_TAG('B','M','L',' ')}, /* Ngombale -> Bamileke */ - {"nle", HB_TAG('L','U','H',' ')}, /* East Nyala -> Luyia */ - {"nln", HB_TAG('N','A','H',' ')}, /* Durango Nahuatl (retired code) -> Nahuatl */ - {"nlv", HB_TAG('N','A','H',' ')}, /* Orizaba Nahuatl -> Nahuatl */ - {"nn", HB_TAG('N','Y','N',' ')}, /* Norwegian Nynorsk (Nynorsk, Norwegian) */ - {"nnh", HB_TAG('B','M','L',' ')}, /* Ngiemboon -> Bamileke */ - {"nnz", HB_TAG('B','M','L',' ')}, /* Nda'nda' -> Bamileke */ - {"no", HB_TAG('N','O','R',' ')}, /* Norwegian [macrolanguage] */ - {"nod", HB_TAG('N','T','A',' ')}, /* Northern Thai -> Northern Tai */ -/*{"noe", HB_TAG('N','O','E',' ')},*/ /* Nimadi */ -/*{"nog", HB_TAG('N','O','G',' ')},*/ /* Nogai */ -/*{"nov", HB_TAG('N','O','V',' ')},*/ /* Novial */ - {"npi", HB_TAG('N','E','P',' ')}, /* Nepali */ - {"npl", HB_TAG('N','A','H',' ')}, /* Southeastern Puebla Nahuatl -> Nahuatl */ - {"nqo", HB_TAG('N','K','O',' ')}, /* N’Ko */ - {"nr", HB_TAG('N','D','B',' ')}, /* South Ndebele -> Ndebele */ - {"nsk", HB_TAG('N','A','S',' ')}, /* Naskapi */ - {"nsm", HB_TAG_NONE }, /* Sumi Naga != Northern Sami */ -/*{"nso", HB_TAG('N','S','O',' ')},*/ /* Northern Sotho */ - {"nsu", HB_TAG('N','A','H',' ')}, /* Sierra Negra Nahuatl -> Nahuatl */ - {"nto", HB_TAG_NONE }, /* Ntomba != Esperanto */ - {"nue", HB_TAG('B','A','D','0')}, /* Ngundu -> Banda */ - {"nuu", HB_TAG('B','A','D','0')}, /* Ngbundu -> Banda */ - {"nuz", HB_TAG('N','A','H',' ')}, /* Tlamacazapa Nahuatl -> Nahuatl */ - {"nv", HB_TAG('N','A','V',' ')}, /* Navajo */ - {"nv", HB_TAG('A','T','H',' ')}, /* Navajo -> Athapaskan */ - {"nwe", HB_TAG('B','M','L',' ')}, /* Ngwe -> Bamileke */ - {"ny", HB_TAG('C','H','I',' ')}, /* Chichewa (Chewa, Nyanja) */ - {"nyd", HB_TAG('L','U','H',' ')}, /* Nyore -> Luyia */ -/*{"nym", HB_TAG('N','Y','M',' ')},*/ /* Nyamwezi */ - {"nyn", HB_TAG('N','K','L',' ')}, /* Nyankole */ -/*{"nza", HB_TAG('N','Z','A',' ')},*/ /* Tigon Mbembe -> Mbembe Tigon */ - {"oc", HB_TAG('O','C','I',' ')}, /* Occitan (post 1500) */ - {"oj", HB_TAG('O','J','B',' ')}, /* Ojibwa [macrolanguage] -> Ojibway */ -/*{"ojb", HB_TAG('O','J','B',' ')},*/ /* Northwestern Ojibwa -> Ojibway */ - {"ojc", HB_TAG('O','J','B',' ')}, /* Central Ojibwa -> Ojibway */ - {"ojg", HB_TAG('O','J','B',' ')}, /* Eastern Ojibwa -> Ojibway */ - {"ojs", HB_TAG('O','C','R',' ')}, /* Severn Ojibwa -> Oji-Cree */ - {"ojs", HB_TAG('O','J','B',' ')}, /* Severn Ojibwa -> Ojibway */ - {"ojw", HB_TAG('O','J','B',' ')}, /* Western Ojibwa -> Ojibway */ - {"okd", HB_TAG('I','J','O',' ')}, /* Okodia -> Ijo */ - {"oki", HB_TAG('K','A','L',' ')}, /* Okiek -> Kalenjin */ - {"okm", HB_TAG('K','O','H',' ')}, /* Middle Korean (10th-16th cent.) -> Korean Old Hangul */ - {"okr", HB_TAG('I','J','O',' ')}, /* Kirike -> Ijo */ - {"om", HB_TAG('O','R','O',' ')}, /* Oromo [macrolanguage] */ - {"onx", HB_TAG('C','P','P',' ')}, /* Onin Based Pidgin -> Creoles */ - {"oor", HB_TAG('C','P','P',' ')}, /* Oorlams -> Creoles */ - {"or", HB_TAG('O','R','I',' ')}, /* Odia (formerly Oriya) [macrolanguage] */ - {"orc", HB_TAG('O','R','O',' ')}, /* Orma -> Oromo */ - {"orn", HB_TAG('M','L','Y',' ')}, /* Orang Kanaq -> Malay */ - {"oro", HB_TAG_NONE }, /* Orokolo != Oromo */ - {"orr", HB_TAG('I','J','O',' ')}, /* Oruma -> Ijo */ - {"ors", HB_TAG('M','L','Y',' ')}, /* Orang Seletar -> Malay */ - {"ory", HB_TAG('O','R','I',' ')}, /* Odia (formerly Oriya) */ - {"os", HB_TAG('O','S','S',' ')}, /* Ossetian */ - {"otw", HB_TAG('O','J','B',' ')}, /* Ottawa -> Ojibway */ - {"oua", HB_TAG('B','B','R',' ')}, /* Tagargrent -> Berber */ - {"pa", HB_TAG('P','A','N',' ')}, /* Punjabi */ - {"paa", HB_TAG_NONE }, /* Papuan [collection] != Palestinian Aramaic */ -/*{"pag", HB_TAG('P','A','G',' ')},*/ /* Pangasinan */ - {"pal", HB_TAG_NONE }, /* Pahlavi != Pali */ -/*{"pam", HB_TAG('P','A','M',' ')},*/ /* Pampanga -> Pampangan */ - {"pap", HB_TAG('P','A','P','0')}, /* Papiamento -> Papiamentu */ - {"pap", HB_TAG('C','P','P',' ')}, /* Papiamento -> Creoles */ - {"pas", HB_TAG_NONE }, /* Papasena != Pashto */ -/*{"pau", HB_TAG('P','A','U',' ')},*/ /* Palauan */ - {"pbt", HB_TAG('P','A','S',' ')}, /* Southern Pashto -> Pashto */ - {"pbu", HB_TAG('P','A','S',' ')}, /* Northern Pashto -> Pashto */ -/*{"pcc", HB_TAG('P','C','C',' ')},*/ /* Bouyei */ -/*{"pcd", HB_TAG('P','C','D',' ')},*/ /* Picard */ - {"pce", HB_TAG('P','L','G',' ')}, /* Ruching Palaung -> Palaung */ - {"pck", HB_TAG('Q','I','N',' ')}, /* Paite Chin -> Chin */ - {"pcm", HB_TAG('C','P','P',' ')}, /* Nigerian Pidgin -> Creoles */ -/*{"pdc", HB_TAG('P','D','C',' ')},*/ /* Pennsylvania German */ - {"pdu", HB_TAG('K','R','N',' ')}, /* Kayan -> Karen */ - {"pea", HB_TAG('C','P','P',' ')}, /* Peranakan Indonesian -> Creoles */ - {"pel", HB_TAG('M','L','Y',' ')}, /* Pekal -> Malay */ - {"pes", HB_TAG('F','A','R',' ')}, /* Iranian Persian -> Persian */ - {"pey", HB_TAG('C','P','P',' ')}, /* Petjo -> Creoles */ - {"pga", HB_TAG('A','R','A',' ')}, /* Sudanese Creole Arabic -> Arabic */ - {"pga", HB_TAG('C','P','P',' ')}, /* Sudanese Creole Arabic -> Creoles */ -/*{"phk", HB_TAG('P','H','K',' ')},*/ /* Phake */ - {"pi", HB_TAG('P','A','L',' ')}, /* Pali */ - {"pih", HB_TAG('P','I','H',' ')}, /* Pitcairn-Norfolk -> Norfolk */ - {"pih", HB_TAG('C','P','P',' ')}, /* Pitcairn-Norfolk -> Creoles */ - {"pil", HB_TAG_NONE }, /* Yom != Filipino */ - {"pis", HB_TAG('C','P','P',' ')}, /* Pijin -> Creoles */ - {"pkh", HB_TAG('Q','I','N',' ')}, /* Pankhu -> Chin */ - {"pko", HB_TAG('K','A','L',' ')}, /* Pökoot -> Kalenjin */ - {"pl", HB_TAG('P','L','K',' ')}, /* Polish */ - {"plg", HB_TAG_NONE }, /* Pilagá != Palaung */ - {"plk", HB_TAG_NONE }, /* Kohistani Shina != Polish */ - {"pll", HB_TAG('P','L','G',' ')}, /* Shwe Palaung -> Palaung */ - {"pln", HB_TAG('C','P','P',' ')}, /* Palenquero -> Creoles */ - {"plp", HB_TAG('P','A','P',' ')}, /* Palpa (retired code) */ - {"plt", HB_TAG('M','L','G',' ')}, /* Plateau Malagasy -> Malagasy */ - {"pml", HB_TAG('C','P','P',' ')}, /* Lingua Franca -> Creoles */ -/*{"pms", HB_TAG('P','M','S',' ')},*/ /* Piemontese */ - {"pmy", HB_TAG('C','P','P',' ')}, /* Papuan Malay -> Creoles */ -/*{"pnb", HB_TAG('P','N','B',' ')},*/ /* Western Panjabi */ - {"poc", HB_TAG('M','Y','N',' ')}, /* Poqomam -> Mayan */ - {"poh", HB_TAG('P','O','H',' ')}, /* Poqomchi' -> Pocomchi */ - {"poh", HB_TAG('M','Y','N',' ')}, /* Poqomchi' -> Mayan */ -/*{"pon", HB_TAG('P','O','N',' ')},*/ /* Pohnpeian */ - {"pov", HB_TAG('C','P','P',' ')}, /* Upper Guinea Crioulo -> Creoles */ - {"ppa", HB_TAG('B','A','G',' ')}, /* Pao (retired code) -> Baghelkhandi */ - {"pre", HB_TAG('C','P','P',' ')}, /* Principense -> Creoles */ -/*{"pro", HB_TAG('P','R','O',' ')},*/ /* Old Provençal (to 1500) -> Provençal / Old Provençal */ - {"prs", HB_TAG('D','R','I',' ')}, /* Dari */ - {"prs", HB_TAG('F','A','R',' ')}, /* Dari -> Persian */ - {"ps", HB_TAG('P','A','S',' ')}, /* Pashto [macrolanguage] */ - {"pse", HB_TAG('M','L','Y',' ')}, /* Central Malay -> Malay */ - {"pst", HB_TAG('P','A','S',' ')}, /* Central Pashto -> Pashto */ - {"pt", HB_TAG('P','T','G',' ')}, /* Portuguese */ - {"pub", HB_TAG('Q','I','N',' ')}, /* Purum -> Chin */ - {"puz", HB_TAG('Q','I','N',' ')}, /* Purum Naga (retired code) -> Chin */ - {"pwo", HB_TAG('P','W','O',' ')}, /* Pwo Western Karen -> Western Pwo Karen */ - {"pwo", HB_TAG('K','R','N',' ')}, /* Pwo Western Karen -> Karen */ - {"pww", HB_TAG('K','R','N',' ')}, /* Pwo Northern Karen -> Karen */ - {"qu", HB_TAG('Q','U','Z',' ')}, /* Quechua [macrolanguage] */ - {"qub", HB_TAG('Q','W','H',' ')}, /* Huallaga Huánuco Quechua -> Quechua (Peru) */ - {"qub", HB_TAG('Q','U','Z',' ')}, /* Huallaga Huánuco Quechua -> Quechua */ - {"quc", HB_TAG('Q','U','C',' ')}, /* K’iche’ */ - {"quc", HB_TAG('M','Y','N',' ')}, /* K'iche' -> Mayan */ - {"qud", HB_TAG('Q','V','I',' ')}, /* Calderón Highland Quichua -> Quechua (Ecuador) */ - {"qud", HB_TAG('Q','U','Z',' ')}, /* Calderón Highland Quichua -> Quechua */ - {"quf", HB_TAG('Q','U','Z',' ')}, /* Lambayeque Quechua -> Quechua */ - {"qug", HB_TAG('Q','V','I',' ')}, /* Chimborazo Highland Quichua -> Quechua (Ecuador) */ - {"qug", HB_TAG('Q','U','Z',' ')}, /* Chimborazo Highland Quichua -> Quechua */ - {"quh", HB_TAG('Q','U','H',' ')}, /* South Bolivian Quechua -> Quechua (Bolivia) */ - {"quh", HB_TAG('Q','U','Z',' ')}, /* South Bolivian Quechua -> Quechua */ - {"quk", HB_TAG('Q','U','Z',' ')}, /* Chachapoyas Quechua -> Quechua */ - {"qul", HB_TAG('Q','U','H',' ')}, /* North Bolivian Quechua -> Quechua (Bolivia) */ - {"qul", HB_TAG('Q','U','Z',' ')}, /* North Bolivian Quechua -> Quechua */ - {"qum", HB_TAG('M','Y','N',' ')}, /* Sipacapense -> Mayan */ - {"qup", HB_TAG('Q','V','I',' ')}, /* Southern Pastaza Quechua -> Quechua (Ecuador) */ - {"qup", HB_TAG('Q','U','Z',' ')}, /* Southern Pastaza Quechua -> Quechua */ - {"qur", HB_TAG('Q','W','H',' ')}, /* Yanahuanca Pasco Quechua -> Quechua (Peru) */ - {"qur", HB_TAG('Q','U','Z',' ')}, /* Yanahuanca Pasco Quechua -> Quechua */ - {"qus", HB_TAG('Q','U','H',' ')}, /* Santiago del Estero Quichua -> Quechua (Bolivia) */ - {"qus", HB_TAG('Q','U','Z',' ')}, /* Santiago del Estero Quichua -> Quechua */ - {"quv", HB_TAG('M','Y','N',' ')}, /* Sacapulteco -> Mayan */ - {"quw", HB_TAG('Q','V','I',' ')}, /* Tena Lowland Quichua -> Quechua (Ecuador) */ - {"quw", HB_TAG('Q','U','Z',' ')}, /* Tena Lowland Quichua -> Quechua */ - {"qux", HB_TAG('Q','W','H',' ')}, /* Yauyos Quechua -> Quechua (Peru) */ - {"qux", HB_TAG('Q','U','Z',' ')}, /* Yauyos Quechua -> Quechua */ - {"quy", HB_TAG('Q','U','Z',' ')}, /* Ayacucho Quechua -> Quechua */ -/*{"quz", HB_TAG('Q','U','Z',' ')},*/ /* Cusco Quechua -> Quechua */ - {"qva", HB_TAG('Q','W','H',' ')}, /* Ambo-Pasco Quechua -> Quechua (Peru) */ - {"qva", HB_TAG('Q','U','Z',' ')}, /* Ambo-Pasco Quechua -> Quechua */ - {"qvc", HB_TAG('Q','U','Z',' ')}, /* Cajamarca Quechua -> Quechua */ - {"qve", HB_TAG('Q','U','Z',' ')}, /* Eastern ApurÃmac Quechua -> Quechua */ - {"qvh", HB_TAG('Q','W','H',' ')}, /* HuamalÃes-Dos de Mayo Huánuco Quechua -> Quechua (Peru) */ - {"qvh", HB_TAG('Q','U','Z',' ')}, /* HuamalÃes-Dos de Mayo Huánuco Quechua -> Quechua */ - {"qvi", HB_TAG('Q','V','I',' ')}, /* Imbabura Highland Quichua -> Quechua (Ecuador) */ - {"qvi", HB_TAG('Q','U','Z',' ')}, /* Imbabura Highland Quichua -> Quechua */ - {"qvj", HB_TAG('Q','V','I',' ')}, /* Loja Highland Quichua -> Quechua (Ecuador) */ - {"qvj", HB_TAG('Q','U','Z',' ')}, /* Loja Highland Quichua -> Quechua */ - {"qvl", HB_TAG('Q','W','H',' ')}, /* Cajatambo North Lima Quechua -> Quechua (Peru) */ - {"qvl", HB_TAG('Q','U','Z',' ')}, /* Cajatambo North Lima Quechua -> Quechua */ - {"qvm", HB_TAG('Q','W','H',' ')}, /* Margos-Yarowilca-Lauricocha Quechua -> Quechua (Peru) */ - {"qvm", HB_TAG('Q','U','Z',' ')}, /* Margos-Yarowilca-Lauricocha Quechua -> Quechua */ - {"qvn", HB_TAG('Q','W','H',' ')}, /* North JunÃn Quechua -> Quechua (Peru) */ - {"qvn", HB_TAG('Q','U','Z',' ')}, /* North JunÃn Quechua -> Quechua */ - {"qvo", HB_TAG('Q','V','I',' ')}, /* Napo Lowland Quechua -> Quechua (Ecuador) */ - {"qvo", HB_TAG('Q','U','Z',' ')}, /* Napo Lowland Quechua -> Quechua */ - {"qvp", HB_TAG('Q','W','H',' ')}, /* Pacaraos Quechua -> Quechua (Peru) */ - {"qvp", HB_TAG('Q','U','Z',' ')}, /* Pacaraos Quechua -> Quechua */ - {"qvs", HB_TAG('Q','U','Z',' ')}, /* San MartÃn Quechua -> Quechua */ - {"qvw", HB_TAG('Q','W','H',' ')}, /* Huaylla Wanca Quechua -> Quechua (Peru) */ - {"qvw", HB_TAG('Q','U','Z',' ')}, /* Huaylla Wanca Quechua -> Quechua */ - {"qvz", HB_TAG('Q','V','I',' ')}, /* Northern Pastaza Quichua -> Quechua (Ecuador) */ - {"qvz", HB_TAG('Q','U','Z',' ')}, /* Northern Pastaza Quichua -> Quechua */ - {"qwa", HB_TAG('Q','W','H',' ')}, /* Corongo Ancash Quechua -> Quechua (Peru) */ - {"qwa", HB_TAG('Q','U','Z',' ')}, /* Corongo Ancash Quechua -> Quechua */ - {"qwc", HB_TAG('Q','U','Z',' ')}, /* Classical Quechua -> Quechua */ - {"qwh", HB_TAG('Q','W','H',' ')}, /* Huaylas Ancash Quechua -> Quechua (Peru) */ - {"qwh", HB_TAG('Q','U','Z',' ')}, /* Huaylas Ancash Quechua -> Quechua */ - {"qws", HB_TAG('Q','W','H',' ')}, /* Sihuas Ancash Quechua -> Quechua (Peru) */ - {"qws", HB_TAG('Q','U','Z',' ')}, /* Sihuas Ancash Quechua -> Quechua */ - {"qwt", HB_TAG('A','T','H',' ')}, /* Kwalhioqua-Tlatskanai -> Athapaskan */ - {"qxa", HB_TAG('Q','W','H',' ')}, /* Chiquián Ancash Quechua -> Quechua (Peru) */ - {"qxa", HB_TAG('Q','U','Z',' ')}, /* Chiquián Ancash Quechua -> Quechua */ - {"qxc", HB_TAG('Q','W','H',' ')}, /* Chincha Quechua -> Quechua (Peru) */ - {"qxc", HB_TAG('Q','U','Z',' ')}, /* Chincha Quechua -> Quechua */ - {"qxh", HB_TAG('Q','W','H',' ')}, /* Panao Huánuco Quechua -> Quechua (Peru) */ - {"qxh", HB_TAG('Q','U','Z',' ')}, /* Panao Huánuco Quechua -> Quechua */ - {"qxl", HB_TAG('Q','V','I',' ')}, /* Salasaca Highland Quichua -> Quechua (Ecuador) */ - {"qxl", HB_TAG('Q','U','Z',' ')}, /* Salasaca Highland Quichua -> Quechua */ - {"qxn", HB_TAG('Q','W','H',' ')}, /* Northern Conchucos Ancash Quechua -> Quechua (Peru) */ - {"qxn", HB_TAG('Q','U','Z',' ')}, /* Northern Conchucos Ancash Quechua -> Quechua */ - {"qxo", HB_TAG('Q','W','H',' ')}, /* Southern Conchucos Ancash Quechua -> Quechua (Peru) */ - {"qxo", HB_TAG('Q','U','Z',' ')}, /* Southern Conchucos Ancash Quechua -> Quechua */ - {"qxp", HB_TAG('Q','U','Z',' ')}, /* Puno Quechua -> Quechua */ - {"qxr", HB_TAG('Q','V','I',' ')}, /* Cañar Highland Quichua -> Quechua (Ecuador) */ - {"qxr", HB_TAG('Q','U','Z',' ')}, /* Cañar Highland Quichua -> Quechua */ - {"qxt", HB_TAG('Q','W','H',' ')}, /* Santa Ana de Tusi Pasco Quechua -> Quechua (Peru) */ - {"qxt", HB_TAG('Q','U','Z',' ')}, /* Santa Ana de Tusi Pasco Quechua -> Quechua */ - {"qxu", HB_TAG('Q','U','Z',' ')}, /* Arequipa-La Unión Quechua -> Quechua */ - {"qxw", HB_TAG('Q','W','H',' ')}, /* Jauja Wanca Quechua -> Quechua (Peru) */ - {"qxw", HB_TAG('Q','U','Z',' ')}, /* Jauja Wanca Quechua -> Quechua */ - {"rag", HB_TAG('L','U','H',' ')}, /* Logooli -> Luyia */ -/*{"raj", HB_TAG('R','A','J',' ')},*/ /* Rajasthani [macrolanguage] */ - {"ral", HB_TAG('Q','I','N',' ')}, /* Ralte -> Chin */ -/*{"rar", HB_TAG('R','A','R',' ')},*/ /* Rarotongan */ - {"rbb", HB_TAG('P','L','G',' ')}, /* Rumai Palaung -> Palaung */ - {"rbl", HB_TAG('B','I','K',' ')}, /* Miraya Bikol -> Bikol */ - {"rcf", HB_TAG('C','P','P',' ')}, /* Réunion Creole French -> Creoles */ -/*{"rej", HB_TAG('R','E','J',' ')},*/ /* Rejang */ -/*{"rhg", HB_TAG('R','H','G',' ')},*/ /* Rohingya */ -/*{"ria", HB_TAG('R','I','A',' ')},*/ /* Riang (India) */ - {"rif", HB_TAG('R','I','F',' ')}, /* Tarifit */ - {"rif", HB_TAG('B','B','R',' ')}, /* Tarifit -> Berber */ -/*{"rit", HB_TAG('R','I','T',' ')},*/ /* Ritharrngu -> Ritarungo */ - {"rki", HB_TAG('A','R','K',' ')}, /* Rakhine */ -/*{"rkw", HB_TAG('R','K','W',' ')},*/ /* Arakwal */ - {"rm", HB_TAG('R','M','S',' ')}, /* Romansh */ - {"rmc", HB_TAG('R','O','Y',' ')}, /* Carpathian Romani -> Romany */ - {"rmf", HB_TAG('R','O','Y',' ')}, /* Kalo Finnish Romani -> Romany */ - {"rml", HB_TAG('R','O','Y',' ')}, /* Baltic Romani -> Romany */ - {"rmn", HB_TAG('R','O','Y',' ')}, /* Balkan Romani -> Romany */ - {"rmo", HB_TAG('R','O','Y',' ')}, /* Sinte Romani -> Romany */ - {"rms", HB_TAG_NONE }, /* Romanian Sign Language != Romansh */ - {"rmw", HB_TAG('R','O','Y',' ')}, /* Welsh Romani -> Romany */ - {"rmy", HB_TAG('R','M','Y',' ')}, /* Vlax Romani */ - {"rmy", HB_TAG('R','O','Y',' ')}, /* Vlax Romani -> Romany */ - {"rmz", HB_TAG('A','R','K',' ')}, /* Marma -> Rakhine */ - {"rn", HB_TAG('R','U','N',' ')}, /* Rundi */ - {"ro", HB_TAG('R','O','M',' ')}, /* Romanian */ - {"rom", HB_TAG('R','O','Y',' ')}, /* Romany [macrolanguage] */ - {"rop", HB_TAG('C','P','P',' ')}, /* Kriol -> Creoles */ - {"rtc", HB_TAG('Q','I','N',' ')}, /* Rungtu Chin -> Chin */ -/*{"rtm", HB_TAG('R','T','M',' ')},*/ /* Rotuman */ - {"ru", HB_TAG('R','U','S',' ')}, /* Russian */ - {"rue", HB_TAG('R','S','Y',' ')}, /* Rusyn */ -/*{"rup", HB_TAG('R','U','P',' ')},*/ /* Aromanian */ - {"rw", HB_TAG('R','U','A',' ')}, /* Kinyarwanda */ - {"rwr", HB_TAG('M','A','W',' ')}, /* Marwari (India) */ - {"sa", HB_TAG('S','A','N',' ')}, /* Sanskrit */ - {"sad", HB_TAG_NONE }, /* Sandawe != Sadri */ - {"sah", HB_TAG('Y','A','K',' ')}, /* Yakut -> Sakha */ - {"sam", HB_TAG('P','A','A',' ')}, /* Samaritan Aramaic -> Palestinian Aramaic */ -/*{"sas", HB_TAG('S','A','S',' ')},*/ /* Sasak */ -/*{"sat", HB_TAG('S','A','T',' ')},*/ /* Santali */ - {"say", HB_TAG_NONE }, /* Saya != Sayisi */ - {"sc", HB_TAG('S','R','D',' ')}, /* Sardinian [macrolanguage] */ - {"scf", HB_TAG('C','P','P',' ')}, /* San Miguel Creole French -> Creoles */ - {"sch", HB_TAG('Q','I','N',' ')}, /* Sakachep -> Chin */ - {"sci", HB_TAG('C','P','P',' ')}, /* Sri Lankan Creole Malay -> Creoles */ - {"sck", HB_TAG('S','A','D',' ')}, /* Sadri */ -/*{"scn", HB_TAG('S','C','N',' ')},*/ /* Sicilian */ -/*{"sco", HB_TAG('S','C','O',' ')},*/ /* Scots */ - {"scs", HB_TAG('S','C','S',' ')}, /* North Slavey */ - {"scs", HB_TAG('S','L','A',' ')}, /* North Slavey -> Slavey */ - {"scs", HB_TAG('A','T','H',' ')}, /* North Slavey -> Athapaskan */ - {"sd", HB_TAG('S','N','D',' ')}, /* Sindhi */ - {"sdc", HB_TAG('S','R','D',' ')}, /* Sassarese Sardinian -> Sardinian */ - {"sdh", HB_TAG('K','U','R',' ')}, /* Southern Kurdish -> Kurdish */ - {"sdn", HB_TAG('S','R','D',' ')}, /* Gallurese Sardinian -> Sardinian */ - {"sds", HB_TAG('B','B','R',' ')}, /* Sened -> Berber */ - {"se", HB_TAG('N','S','M',' ')}, /* Northern Sami */ - {"seh", HB_TAG('S','N','A',' ')}, /* Sena */ - {"sek", HB_TAG('A','T','H',' ')}, /* Sekani -> Athapaskan */ -/*{"sel", HB_TAG('S','E','L',' ')},*/ /* Selkup */ - {"sez", HB_TAG('Q','I','N',' ')}, /* Senthang Chin -> Chin */ - {"sfm", HB_TAG('S','F','M',' ')}, /* Small Flowery Miao */ - {"sfm", HB_TAG('H','M','N',' ')}, /* Small Flowery Miao -> Hmong */ - {"sg", HB_TAG('S','G','O',' ')}, /* Sango */ -/*{"sga", HB_TAG('S','G','A',' ')},*/ /* Old Irish (to 900) */ - {"sgc", HB_TAG('K','A','L',' ')}, /* Kipsigis -> Kalenjin */ - {"sgo", HB_TAG_NONE }, /* Songa (retired code) != Sango */ -/*{"sgs", HB_TAG('S','G','S',' ')},*/ /* Samogitian */ - {"sgw", HB_TAG('C','H','G',' ')}, /* Sebat Bet Gurage -> Chaha Gurage */ - {"sh", HB_TAG('B','O','S',' ')}, /* Serbo-Croatian [macrolanguage] -> Bosnian */ - {"sh", HB_TAG('H','R','V',' ')}, /* Serbo-Croatian [macrolanguage] -> Croatian */ - {"sh", HB_TAG('S','R','B',' ')}, /* Serbo-Croatian [macrolanguage] -> Serbian */ - {"shi", HB_TAG('S','H','I',' ')}, /* Tachelhit */ - {"shi", HB_TAG('B','B','R',' ')}, /* Tachelhit -> Berber */ - {"shl", HB_TAG('Q','I','N',' ')}, /* Shendu -> Chin */ -/*{"shn", HB_TAG('S','H','N',' ')},*/ /* Shan */ - {"shu", HB_TAG('A','R','A',' ')}, /* Chadian Arabic -> Arabic */ - {"shy", HB_TAG('B','B','R',' ')}, /* Tachawit -> Berber */ - {"si", HB_TAG('S','N','H',' ')}, /* Sinhala (Sinhalese) */ - {"sib", HB_TAG_NONE }, /* Sebop != Sibe */ -/*{"sid", HB_TAG('S','I','D',' ')},*/ /* Sidamo */ - {"sig", HB_TAG_NONE }, /* Paasaal != Silte Gurage */ - {"siz", HB_TAG('B','B','R',' ')}, /* Siwi -> Berber */ - {"sjd", HB_TAG('K','S','M',' ')}, /* Kildin Sami */ - {"sjo", HB_TAG('S','I','B',' ')}, /* Xibe -> Sibe */ - {"sjs", HB_TAG('B','B','R',' ')}, /* Senhaja De Srair -> Berber */ - {"sk", HB_TAG('S','K','Y',' ')}, /* Slovak */ - {"skg", HB_TAG('M','L','G',' ')}, /* Sakalava Malagasy -> Malagasy */ - {"skr", HB_TAG('S','R','K',' ')}, /* Saraiki */ - {"sks", HB_TAG_NONE }, /* Maia != Skolt Sami */ - {"skw", HB_TAG('C','P','P',' ')}, /* Skepi Creole Dutch -> Creoles */ - {"sky", HB_TAG_NONE }, /* Sikaiana != Slovak */ - {"sl", HB_TAG('S','L','V',' ')}, /* Slovenian */ - {"sla", HB_TAG_NONE }, /* Slavic [collection] != Slavey */ - {"sm", HB_TAG('S','M','O',' ')}, /* Samoan */ - {"sma", HB_TAG('S','S','M',' ')}, /* Southern Sami */ - {"smd", HB_TAG('M','B','N',' ')}, /* Sama (retired code) -> Mbundu */ - {"smj", HB_TAG('L','S','M',' ')}, /* Lule Sami */ - {"sml", HB_TAG_NONE }, /* Central Sama != Somali */ - {"smn", HB_TAG('I','S','M',' ')}, /* Inari Sami */ - {"sms", HB_TAG('S','K','S',' ')}, /* Skolt Sami */ - {"smt", HB_TAG('Q','I','N',' ')}, /* Simte -> Chin */ - {"sn", HB_TAG('S','N','A','0')}, /* Shona */ - {"snb", HB_TAG('I','B','A',' ')}, /* Sebuyau (retired code) -> Iban */ - {"snh", HB_TAG_NONE }, /* Shinabo (retired code) != Sinhala (Sinhalese) */ -/*{"snk", HB_TAG('S','N','K',' ')},*/ /* Soninke */ - {"so", HB_TAG('S','M','L',' ')}, /* Somali */ - {"sog", HB_TAG_NONE }, /* Sogdian != Sodo Gurage */ -/*{"sop", HB_TAG('S','O','P',' ')},*/ /* Songe */ - {"spv", HB_TAG('O','R','I',' ')}, /* Sambalpuri -> Odia (formerly Oriya) */ - {"spy", HB_TAG('K','A','L',' ')}, /* Sabaot -> Kalenjin */ - {"sq", HB_TAG('S','Q','I',' ')}, /* Albanian [macrolanguage] */ - {"sr", HB_TAG('S','R','B',' ')}, /* Serbian */ - {"srb", HB_TAG_NONE }, /* Sora != Serbian */ - {"src", HB_TAG('S','R','D',' ')}, /* Logudorese Sardinian -> Sardinian */ - {"srk", HB_TAG_NONE }, /* Serudung Murut != Saraiki */ - {"srm", HB_TAG('C','P','P',' ')}, /* Saramaccan -> Creoles */ - {"srn", HB_TAG('C','P','P',' ')}, /* Sranan Tongo -> Creoles */ - {"sro", HB_TAG('S','R','D',' ')}, /* Campidanese Sardinian -> Sardinian */ -/*{"srr", HB_TAG('S','R','R',' ')},*/ /* Serer */ - {"srs", HB_TAG('A','T','H',' ')}, /* Sarsi -> Athapaskan */ - {"ss", HB_TAG('S','W','Z',' ')}, /* Swati */ - {"ssh", HB_TAG('A','R','A',' ')}, /* Shihhi Arabic -> Arabic */ - {"ssl", HB_TAG_NONE }, /* Western Sisaala != South Slavey */ - {"ssm", HB_TAG_NONE }, /* Semnam != Southern Sami */ - {"st", HB_TAG('S','O','T',' ')}, /* Southern Sotho */ - {"sta", HB_TAG('C','P','P',' ')}, /* Settla -> Creoles */ -/*{"stq", HB_TAG('S','T','Q',' ')},*/ /* Saterfriesisch -> Saterland Frisian */ - {"stv", HB_TAG('S','I','G',' ')}, /* Silt'e -> Silte Gurage */ - {"su", HB_TAG('S','U','N',' ')}, /* Sundanese */ -/*{"suk", HB_TAG('S','U','K',' ')},*/ /* Sukuma */ - {"suq", HB_TAG('S','U','R',' ')}, /* Suri */ - {"sur", HB_TAG_NONE }, /* Mwaghavul != Suri */ - {"sv", HB_TAG('S','V','E',' ')}, /* Swedish */ -/*{"sva", HB_TAG('S','V','A',' ')},*/ /* Svan */ - {"svc", HB_TAG('C','P','P',' ')}, /* Vincentian Creole English -> Creoles */ - {"sve", HB_TAG_NONE }, /* Serili != Swedish */ - {"sw", HB_TAG('S','W','K',' ')}, /* Swahili [macrolanguage] */ - {"swb", HB_TAG('C','M','R',' ')}, /* Maore Comorian -> Comorian */ - {"swc", HB_TAG('S','W','K',' ')}, /* Congo Swahili -> Swahili */ - {"swh", HB_TAG('S','W','K',' ')}, /* Swahili */ - {"swk", HB_TAG_NONE }, /* Malawi Sena != Swahili */ - {"swn", HB_TAG('B','B','R',' ')}, /* Sawknah -> Berber */ - {"swv", HB_TAG('M','A','W',' ')}, /* Shekhawati -> Marwari */ -/*{"sxu", HB_TAG('S','X','U',' ')},*/ /* Upper Saxon */ - {"syc", HB_TAG('S','Y','R',' ')}, /* Classical Syriac -> Syriac */ -/*{"syl", HB_TAG('S','Y','L',' ')},*/ /* Sylheti */ -/*{"syr", HB_TAG('S','Y','R',' ')},*/ /* Syriac [macrolanguage] */ -/*{"szl", HB_TAG('S','Z','L',' ')},*/ /* Silesian */ - {"ta", HB_TAG('T','A','M',' ')}, /* Tamil */ - {"taa", HB_TAG('A','T','H',' ')}, /* Lower Tanana -> Athapaskan */ -/*{"tab", HB_TAG('T','A','B',' ')},*/ /* Tabassaran -> Tabasaran */ - {"taj", HB_TAG_NONE }, /* Eastern Tamang != Tajiki */ - {"taq", HB_TAG('T','M','H',' ')}, /* Tamasheq -> Tamashek */ - {"taq", HB_TAG('B','B','R',' ')}, /* Tamasheq -> Berber */ - {"tas", HB_TAG('C','P','P',' ')}, /* Tay Boi -> Creoles */ - {"tau", HB_TAG('A','T','H',' ')}, /* Upper Tanana -> Athapaskan */ - {"tcb", HB_TAG('A','T','H',' ')}, /* Tanacross -> Athapaskan */ - {"tce", HB_TAG('A','T','H',' ')}, /* Southern Tutchone -> Athapaskan */ - {"tch", HB_TAG('C','P','P',' ')}, /* Turks And Caicos Creole English -> Creoles */ - {"tcp", HB_TAG('Q','I','N',' ')}, /* Tawr Chin -> Chin */ - {"tcs", HB_TAG('C','P','P',' ')}, /* Torres Strait Creole -> Creoles */ - {"tcy", HB_TAG('T','U','L',' ')}, /* Tulu -> Tumbuka */ - {"tcz", HB_TAG('Q','I','N',' ')}, /* Thado Chin -> Chin */ -/*{"tdd", HB_TAG('T','D','D',' ')},*/ /* Tai Nüa -> Dehong Dai */ - {"tdx", HB_TAG('M','L','G',' ')}, /* Tandroy-Mahafaly Malagasy -> Malagasy */ - {"te", HB_TAG('T','E','L',' ')}, /* Telugu */ - {"tec", HB_TAG('K','A','L',' ')}, /* Terik -> Kalenjin */ - {"tem", HB_TAG('T','M','N',' ')}, /* Timne -> Temne */ -/*{"tet", HB_TAG('T','E','T',' ')},*/ /* Tetum */ - {"tez", HB_TAG('B','B','R',' ')}, /* Tetserret -> Berber */ - {"tfn", HB_TAG('A','T','H',' ')}, /* Tanaina -> Athapaskan */ - {"tg", HB_TAG('T','A','J',' ')}, /* Tajik -> Tajiki */ - {"tgh", HB_TAG('C','P','P',' ')}, /* Tobagonian Creole English -> Creoles */ - {"tgj", HB_TAG('N','I','S',' ')}, /* Tagin -> Nisi */ - {"tgn", HB_TAG_NONE }, /* Tandaganon != Tongan */ - {"tgr", HB_TAG_NONE }, /* Tareng != Tigre */ - {"tgx", HB_TAG('A','T','H',' ')}, /* Tagish -> Athapaskan */ - {"tgy", HB_TAG_NONE }, /* Togoyo != Tigrinya */ - {"th", HB_TAG('T','H','A',' ')}, /* Thai */ - {"tht", HB_TAG('A','T','H',' ')}, /* Tahltan -> Athapaskan */ - {"thv", HB_TAG('T','M','H',' ')}, /* Tahaggart Tamahaq -> Tamashek */ - {"thv", HB_TAG('B','B','R',' ')}, /* Tahaggart Tamahaq -> Berber */ - {"thz", HB_TAG('T','M','H',' ')}, /* Tayart Tamajeq -> Tamashek */ - {"thz", HB_TAG('B','B','R',' ')}, /* Tayart Tamajeq -> Berber */ - {"ti", HB_TAG('T','G','Y',' ')}, /* Tigrinya */ - {"tia", HB_TAG('B','B','R',' ')}, /* Tidikelt Tamazight -> Berber */ - {"tig", HB_TAG('T','G','R',' ')}, /* Tigre */ -/*{"tiv", HB_TAG('T','I','V',' ')},*/ /* Tiv */ -/*{"tjl", HB_TAG('T','J','L',' ')},*/ /* Tai Laing */ - {"tjo", HB_TAG('B','B','R',' ')}, /* Temacine Tamazight -> Berber */ - {"tk", HB_TAG('T','K','M',' ')}, /* Turkmen */ - {"tkg", HB_TAG('M','L','G',' ')}, /* Tesaka Malagasy -> Malagasy */ - {"tkm", HB_TAG_NONE }, /* Takelma != Turkmen */ - {"tl", HB_TAG('T','G','L',' ')}, /* Tagalog */ -/*{"tli", HB_TAG('T','L','I',' ')},*/ /* Tlingit */ - {"tmg", HB_TAG('C','P','P',' ')}, /* Ternateño -> Creoles */ - {"tmh", HB_TAG('T','M','H',' ')}, /* Tamashek [macrolanguage] */ - {"tmh", HB_TAG('B','B','R',' ')}, /* Tamashek [macrolanguage] -> Berber */ - {"tmn", HB_TAG_NONE }, /* Taman (Indonesia) != Temne */ - {"tmw", HB_TAG('M','L','Y',' ')}, /* Temuan -> Malay */ - {"tn", HB_TAG('T','N','A',' ')}, /* Tswana */ - {"tna", HB_TAG_NONE }, /* Tacana != Tswana */ - {"tne", HB_TAG_NONE }, /* Tinoc Kallahan (retired code) != Tundra Enets */ - {"tnf", HB_TAG('D','R','I',' ')}, /* Tangshewi (retired code) -> Dari */ - {"tnf", HB_TAG('F','A','R',' ')}, /* Tangshewi (retired code) -> Persian */ - {"tng", HB_TAG_NONE }, /* Tobanga != Tonga */ - {"to", HB_TAG('T','G','N',' ')}, /* Tonga (Tonga Islands) -> Tongan */ - {"tod", HB_TAG('T','O','D','0')}, /* Toma */ - {"toi", HB_TAG('T','N','G',' ')}, /* Tonga (Zambia) */ - {"toj", HB_TAG('M','Y','N',' ')}, /* Tojolabal -> Mayan */ - {"tol", HB_TAG('A','T','H',' ')}, /* Tolowa -> Athapaskan */ - {"tor", HB_TAG('B','A','D','0')}, /* Togbo-Vara Banda -> Banda */ - {"tpi", HB_TAG('T','P','I',' ')}, /* Tok Pisin */ - {"tpi", HB_TAG('C','P','P',' ')}, /* Tok Pisin -> Creoles */ - {"tr", HB_TAG('T','R','K',' ')}, /* Turkish */ - {"trf", HB_TAG('C','P','P',' ')}, /* Trinidadian Creole English -> Creoles */ - {"trk", HB_TAG_NONE }, /* Turkic [collection] != Turkish */ - {"tru", HB_TAG('T','U','A',' ')}, /* Turoyo -> Turoyo Aramaic */ - {"tru", HB_TAG('S','Y','R',' ')}, /* Turoyo -> Syriac */ - {"ts", HB_TAG('T','S','G',' ')}, /* Tsonga */ - {"tsg", HB_TAG_NONE }, /* Tausug != Tsonga */ -/*{"tsj", HB_TAG('T','S','J',' ')},*/ /* Tshangla */ - {"tt", HB_TAG('T','A','T',' ')}, /* Tatar */ - {"ttc", HB_TAG('M','Y','N',' ')}, /* Tektiteko -> Mayan */ - {"ttm", HB_TAG('A','T','H',' ')}, /* Northern Tutchone -> Athapaskan */ - {"ttq", HB_TAG('T','M','H',' ')}, /* Tawallammat Tamajaq -> Tamashek */ - {"ttq", HB_TAG('B','B','R',' ')}, /* Tawallammat Tamajaq -> Berber */ - {"tua", HB_TAG_NONE }, /* Wiarumus != Turoyo Aramaic */ - {"tul", HB_TAG_NONE }, /* Tula != Tumbuka */ -/*{"tum", HB_TAG('T','U','M',' ')},*/ /* Tumbuka -> Tulu */ - {"tuu", HB_TAG('A','T','H',' ')}, /* Tututni -> Athapaskan */ - {"tuv", HB_TAG_NONE }, /* Turkana != Tuvin */ - {"tuy", HB_TAG('K','A','L',' ')}, /* Tugen -> Kalenjin */ -/*{"tvl", HB_TAG('T','V','L',' ')},*/ /* Tuvalu */ - {"tvy", HB_TAG('C','P','P',' ')}, /* Timor Pidgin -> Creoles */ - {"tw", HB_TAG('T','W','I',' ')}, /* Twi */ - {"tw", HB_TAG('A','K','A',' ')}, /* Twi -> Akan */ - {"txc", HB_TAG('A','T','H',' ')}, /* Tsetsaut -> Athapaskan */ - {"txy", HB_TAG('M','L','G',' ')}, /* Tanosy Malagasy -> Malagasy */ - {"ty", HB_TAG('T','H','T',' ')}, /* Tahitian */ - {"tyv", HB_TAG('T','U','V',' ')}, /* Tuvinian -> Tuvin */ -/*{"tyz", HB_TAG('T','Y','Z',' ')},*/ /* Tà y */ - {"tzh", HB_TAG('M','Y','N',' ')}, /* Tzeltal -> Mayan */ - {"tzj", HB_TAG('M','Y','N',' ')}, /* Tz'utujil -> Mayan */ - {"tzm", HB_TAG('T','Z','M',' ')}, /* Central Atlas Tamazight -> Tamazight */ - {"tzm", HB_TAG('B','B','R',' ')}, /* Central Atlas Tamazight -> Berber */ - {"tzo", HB_TAG('T','Z','O',' ')}, /* Tzotzil */ - {"tzo", HB_TAG('M','Y','N',' ')}, /* Tzotzil -> Mayan */ - {"ubl", HB_TAG('B','I','K',' ')}, /* Buhi'non Bikol -> Bikol */ -/*{"udm", HB_TAG('U','D','M',' ')},*/ /* Udmurt */ - {"ug", HB_TAG('U','Y','G',' ')}, /* Uyghur */ - {"uk", HB_TAG('U','K','R',' ')}, /* Ukrainian */ - {"uki", HB_TAG('K','U','I',' ')}, /* Kui (India) */ - {"uln", HB_TAG('C','P','P',' ')}, /* Unserdeutsch -> Creoles */ -/*{"umb", HB_TAG('U','M','B',' ')},*/ /* Umbundu */ - {"unr", HB_TAG('M','U','N',' ')}, /* Mundari */ - {"ur", HB_TAG('U','R','D',' ')}, /* Urdu */ - {"urk", HB_TAG('M','L','Y',' ')}, /* Urak Lawoi' -> Malay */ - {"usp", HB_TAG('M','Y','N',' ')}, /* Uspanteco -> Mayan */ - {"uz", HB_TAG('U','Z','B',' ')}, /* Uzbek [macrolanguage] */ - {"uzn", HB_TAG('U','Z','B',' ')}, /* Northern Uzbek -> Uzbek */ - {"uzs", HB_TAG('U','Z','B',' ')}, /* Southern Uzbek -> Uzbek */ - {"vap", HB_TAG('Q','I','N',' ')}, /* Vaiphei -> Chin */ - {"ve", HB_TAG('V','E','N',' ')}, /* Venda */ -/*{"vec", HB_TAG('V','E','C',' ')},*/ /* Venetian */ - {"vi", HB_TAG('V','I','T',' ')}, /* Vietnamese */ - {"vic", HB_TAG('C','P','P',' ')}, /* Virgin Islands Creole English -> Creoles */ - {"vit", HB_TAG_NONE }, /* Viti != Vietnamese */ - {"vkk", HB_TAG('M','L','Y',' ')}, /* Kaur -> Malay */ - {"vkp", HB_TAG('C','P','P',' ')}, /* Korlai Creole Portuguese -> Creoles */ - {"vkt", HB_TAG('M','L','Y',' ')}, /* Tenggarong Kutai Malay -> Malay */ - {"vls", HB_TAG('F','L','E',' ')}, /* Vlaams -> Dutch (Flemish) */ - {"vmw", HB_TAG('M','A','K',' ')}, /* Makhuwa */ - {"vo", HB_TAG('V','O','L',' ')}, /* Volapük */ -/*{"vro", HB_TAG('V','R','O',' ')},*/ /* Võro */ - {"wa", HB_TAG('W','L','N',' ')}, /* Walloon */ - {"wag", HB_TAG_NONE }, /* Wa'ema != Wagdi */ -/*{"war", HB_TAG('W','A','R',' ')},*/ /* Waray (Philippines) -> Waray-Waray */ - {"wbm", HB_TAG('W','A',' ',' ')}, /* Wa */ - {"wbr", HB_TAG('W','A','G',' ')}, /* Wagdi */ - {"wbr", HB_TAG('R','A','J',' ')}, /* Wagdi -> Rajasthani */ -/*{"wci", HB_TAG('W','C','I',' ')},*/ /* Waci Gbe */ - {"wea", HB_TAG('K','R','N',' ')}, /* Wewaw -> Karen */ - {"wes", HB_TAG('C','P','P',' ')}, /* Cameroon Pidgin -> Creoles */ - {"weu", HB_TAG('Q','I','N',' ')}, /* Rawngtu Chin -> Chin */ - {"wlc", HB_TAG('C','M','R',' ')}, /* Mwali Comorian -> Comorian */ - {"wle", HB_TAG('S','I','G',' ')}, /* Wolane -> Silte Gurage */ - {"wlk", HB_TAG('A','T','H',' ')}, /* Wailaki -> Athapaskan */ - {"wni", HB_TAG('C','M','R',' ')}, /* Ndzwani Comorian -> Comorian */ - {"wo", HB_TAG('W','L','F',' ')}, /* Wolof */ - {"wry", HB_TAG('M','A','W',' ')}, /* Merwari -> Marwari */ - {"wsg", HB_TAG('G','O','N',' ')}, /* Adilabad Gondi -> Gondi */ -/*{"wtm", HB_TAG('W','T','M',' ')},*/ /* Mewati */ - {"wuu", HB_TAG('Z','H','S',' ')}, /* Wu Chinese -> Chinese, Simplified */ - {"xal", HB_TAG('K','L','M',' ')}, /* Kalmyk */ - {"xal", HB_TAG('T','O','D',' ')}, /* Kalmyk -> Todo */ - {"xan", HB_TAG('S','E','K',' ')}, /* Xamtanga -> Sekota */ - {"xbd", HB_TAG_NONE }, /* Bindal != Lü */ - {"xh", HB_TAG('X','H','S',' ')}, /* Xhosa */ -/*{"xjb", HB_TAG('X','J','B',' ')},*/ /* Minjungbal -> Minjangbal */ -/*{"xkf", HB_TAG('X','K','F',' ')},*/ /* Khengkha */ - {"xmg", HB_TAG('B','M','L',' ')}, /* Mengaka -> Bamileke */ - {"xmm", HB_TAG('M','L','Y',' ')}, /* Manado Malay -> Malay */ - {"xmm", HB_TAG('C','P','P',' ')}, /* Manado Malay -> Creoles */ - {"xmv", HB_TAG('M','L','G',' ')}, /* Antankarana Malagasy -> Malagasy */ - {"xmw", HB_TAG('M','L','G',' ')}, /* Tsimihety Malagasy -> Malagasy */ - {"xnj", HB_TAG('S','X','T',' ')}, /* Ngoni (Tanzania) -> Sutu */ - {"xnq", HB_TAG('S','X','T',' ')}, /* Ngoni (Mozambique) -> Sutu */ - {"xnr", HB_TAG('D','G','R',' ')}, /* Kangri -> Dogri (macrolanguage) */ -/*{"xog", HB_TAG('X','O','G',' ')},*/ /* Soga */ - {"xpe", HB_TAG('X','P','E',' ')}, /* Liberia Kpelle -> Kpelle (Liberia) */ - {"xpe", HB_TAG('K','P','L',' ')}, /* Liberia Kpelle -> Kpelle */ - {"xsl", HB_TAG('S','S','L',' ')}, /* South Slavey */ - {"xsl", HB_TAG('S','L','A',' ')}, /* South Slavey -> Slavey */ - {"xsl", HB_TAG('A','T','H',' ')}, /* South Slavey -> Athapaskan */ - {"xst", HB_TAG('S','I','G',' ')}, /* Silt'e (retired code) -> Silte Gurage */ -/*{"xub", HB_TAG('X','U','B',' ')},*/ /* Betta Kurumba -> Bette Kuruma */ -/*{"xuj", HB_TAG('X','U','J',' ')},*/ /* Jennu Kurumba -> Jennu Kuruma */ - {"xup", HB_TAG('A','T','H',' ')}, /* Upper Umpqua -> Athapaskan */ - {"xwo", HB_TAG('T','O','D',' ')}, /* Written Oirat -> Todo */ - {"yaj", HB_TAG('B','A','D','0')}, /* Banda-Yangere -> Banda */ - {"yak", HB_TAG_NONE }, /* Yakama != Sakha */ -/*{"yao", HB_TAG('Y','A','O',' ')},*/ /* Yao */ -/*{"yap", HB_TAG('Y','A','P',' ')},*/ /* Yapese */ - {"yba", HB_TAG_NONE }, /* Yala != Yoruba */ - {"ybb", HB_TAG('B','M','L',' ')}, /* Yemba -> Bamileke */ - {"ybd", HB_TAG('A','R','K',' ')}, /* Yangbye (retired code) -> Rakhine */ - {"ydd", HB_TAG('J','I','I',' ')}, /* Eastern Yiddish -> Yiddish */ -/*{"ygp", HB_TAG('Y','G','P',' ')},*/ /* Gepo */ - {"yi", HB_TAG('J','I','I',' ')}, /* Yiddish [macrolanguage] */ - {"yih", HB_TAG('J','I','I',' ')}, /* Western Yiddish -> Yiddish */ - {"yim", HB_TAG_NONE }, /* Yimchungru Naga != Yi Modern */ -/*{"yna", HB_TAG('Y','N','A',' ')},*/ /* Aluo */ - {"yo", HB_TAG('Y','B','A',' ')}, /* Yoruba */ - {"yos", HB_TAG('Q','I','N',' ')}, /* Yos (retired code) -> Chin */ - {"yua", HB_TAG('M','Y','N',' ')}, /* Yucateco -> Mayan */ - {"yue", HB_TAG('Z','H','H',' ')}, /* Yue Chinese -> Chinese, Traditional, Hong Kong SAR */ -/*{"ywq", HB_TAG('Y','W','Q',' ')},*/ /* Wuding-Luquan Yi */ - {"za", HB_TAG('Z','H','A',' ')}, /* Zhuang [macrolanguage] */ - {"zch", HB_TAG('Z','H','A',' ')}, /* Central Hongshuihe Zhuang -> Zhuang */ - {"zdj", HB_TAG('C','M','R',' ')}, /* Ngazidja Comorian -> Comorian */ -/*{"zea", HB_TAG('Z','E','A',' ')},*/ /* Zeeuws -> Zealandic */ - {"zeh", HB_TAG('Z','H','A',' ')}, /* Eastern Hongshuihe Zhuang -> Zhuang */ - {"zen", HB_TAG('B','B','R',' ')}, /* Zenaga -> Berber */ - {"zgb", HB_TAG('Z','H','A',' ')}, /* Guibei Zhuang -> Zhuang */ - {"zgh", HB_TAG('Z','G','H',' ')}, /* Standard Moroccan Tamazight */ - {"zgh", HB_TAG('B','B','R',' ')}, /* Standard Moroccan Tamazight -> Berber */ - {"zgm", HB_TAG('Z','H','A',' ')}, /* Minz Zhuang -> Zhuang */ - {"zgn", HB_TAG('Z','H','A',' ')}, /* Guibian Zhuang -> Zhuang */ - {"zh", HB_TAG('Z','H','S',' ')}, /* Chinese, Simplified [macrolanguage] */ - {"zhd", HB_TAG('Z','H','A',' ')}, /* Dai Zhuang -> Zhuang */ - {"zhn", HB_TAG('Z','H','A',' ')}, /* Nong Zhuang -> Zhuang */ - {"zlj", HB_TAG('Z','H','A',' ')}, /* Liujiang Zhuang -> Zhuang */ - {"zlm", HB_TAG('M','L','Y',' ')}, /* Malay */ - {"zln", HB_TAG('Z','H','A',' ')}, /* Lianshan Zhuang -> Zhuang */ - {"zlq", HB_TAG('Z','H','A',' ')}, /* Liuqian Zhuang -> Zhuang */ - {"zmi", HB_TAG('M','L','Y',' ')}, /* Negeri Sembilan Malay -> Malay */ - {"zmz", HB_TAG('B','A','D','0')}, /* Mbandja -> Banda */ - {"znd", HB_TAG_NONE }, /* Zande [collection] != Zande */ - {"zne", HB_TAG('Z','N','D',' ')}, /* Zande */ - {"zom", HB_TAG('Q','I','N',' ')}, /* Zou -> Chin */ - {"zqe", HB_TAG('Z','H','A',' ')}, /* Qiubei Zhuang -> Zhuang */ - {"zsm", HB_TAG('M','L','Y',' ')}, /* Standard Malay -> Malay */ - {"zu", HB_TAG('Z','U','L',' ')}, /* Zulu */ - {"zum", HB_TAG('L','R','C',' ')}, /* Kumzari -> Luri */ - {"zyb", HB_TAG('Z','H','A',' ')}, /* Yongbei Zhuang -> Zhuang */ - {"zyg", HB_TAG('Z','H','A',' ')}, /* Yang Zhuang -> Zhuang */ - {"zyj", HB_TAG('Z','H','A',' ')}, /* Youjiang Zhuang -> Zhuang */ - {"zyn", HB_TAG('Z','H','A',' ')}, /* Yongnan Zhuang -> Zhuang */ - {"zyp", HB_TAG('Q','I','N',' ')}, /* Zyphe Chin -> Chin */ -/*{"zza", HB_TAG('Z','Z','A',' ')},*/ /* Zazaki [macrolanguage] */ - {"zzj", HB_TAG('Z','H','A',' ')}, /* Zuojiang Zhuang -> Zhuang */ +static const LangTag ot_languages2[] = { + {HB_TAG('a','a',' ',' '), HB_TAG('A','F','R',' ')}, /* Afar */ + {HB_TAG('a','b',' ',' '), HB_TAG('A','B','K',' ')}, /* Abkhazian */ + {HB_TAG('a','f',' ',' '), HB_TAG('A','F','K',' ')}, /* Afrikaans */ + {HB_TAG('a','k',' ',' '), HB_TAG('A','K','A',' ')}, /* Akan [macrolanguage] */ + {HB_TAG('a','m',' ',' '), HB_TAG('A','M','H',' ')}, /* Amharic */ + {HB_TAG('a','n',' ',' '), HB_TAG('A','R','G',' ')}, /* Aragonese */ + {HB_TAG('a','r',' ',' '), HB_TAG('A','R','A',' ')}, /* Arabic [macrolanguage] */ + {HB_TAG('a','s',' ',' '), HB_TAG('A','S','M',' ')}, /* Assamese */ + {HB_TAG('a','v',' ',' '), HB_TAG('A','V','R',' ')}, /* Avaric -> Avar */ + {HB_TAG('a','y',' ',' '), HB_TAG('A','Y','M',' ')}, /* Aymara [macrolanguage] */ + {HB_TAG('a','z',' ',' '), HB_TAG('A','Z','E',' ')}, /* Azerbaijani [macrolanguage] */ + {HB_TAG('b','a',' ',' '), HB_TAG('B','S','H',' ')}, /* Bashkir */ + {HB_TAG('b','e',' ',' '), HB_TAG('B','E','L',' ')}, /* Belarusian -> Belarussian */ + {HB_TAG('b','g',' ',' '), HB_TAG('B','G','R',' ')}, /* Bulgarian */ + {HB_TAG('b','i',' ',' '), HB_TAG('B','I','S',' ')}, /* Bislama */ + {HB_TAG('b','i',' ',' '), HB_TAG('C','P','P',' ')}, /* Bislama -> Creoles */ + {HB_TAG('b','m',' ',' '), HB_TAG('B','M','B',' ')}, /* Bambara (Bamanankan) */ + {HB_TAG('b','n',' ',' '), HB_TAG('B','E','N',' ')}, /* Bengali */ + {HB_TAG('b','o',' ',' '), HB_TAG('T','I','B',' ')}, /* Tibetan */ + {HB_TAG('b','r',' ',' '), HB_TAG('B','R','E',' ')}, /* Breton */ + {HB_TAG('b','s',' ',' '), HB_TAG('B','O','S',' ')}, /* Bosnian */ + {HB_TAG('c','a',' ',' '), HB_TAG('C','A','T',' ')}, /* Catalan */ + {HB_TAG('c','e',' ',' '), HB_TAG('C','H','E',' ')}, /* Chechen */ + {HB_TAG('c','h',' ',' '), HB_TAG('C','H','A',' ')}, /* Chamorro */ + {HB_TAG('c','o',' ',' '), HB_TAG('C','O','S',' ')}, /* Corsican */ + {HB_TAG('c','r',' ',' '), HB_TAG('C','R','E',' ')}, /* Cree [macrolanguage] */ + {HB_TAG('c','s',' ',' '), HB_TAG('C','S','Y',' ')}, /* Czech */ + {HB_TAG('c','u',' ',' '), HB_TAG('C','S','L',' ')}, /* Church Slavonic */ + {HB_TAG('c','v',' ',' '), HB_TAG('C','H','U',' ')}, /* Chuvash */ + {HB_TAG('c','y',' ',' '), HB_TAG('W','E','L',' ')}, /* Welsh */ + {HB_TAG('d','a',' ',' '), HB_TAG('D','A','N',' ')}, /* Danish */ + {HB_TAG('d','e',' ',' '), HB_TAG('D','E','U',' ')}, /* German */ + {HB_TAG('d','v',' ',' '), HB_TAG('D','I','V',' ')}, /* Divehi (Dhivehi, Maldivian) */ + {HB_TAG('d','v',' ',' '), HB_TAG('D','H','V',' ')}, /* Divehi (Dhivehi, Maldivian) (deprecated) */ + {HB_TAG('d','z',' ',' '), HB_TAG('D','Z','N',' ')}, /* Dzongkha */ + {HB_TAG('e','e',' ',' '), HB_TAG('E','W','E',' ')}, /* Ewe */ + {HB_TAG('e','l',' ',' '), HB_TAG('E','L','L',' ')}, /* Modern Greek (1453-) -> Greek */ + {HB_TAG('e','n',' ',' '), HB_TAG('E','N','G',' ')}, /* English */ + {HB_TAG('e','o',' ',' '), HB_TAG('N','T','O',' ')}, /* Esperanto */ + {HB_TAG('e','s',' ',' '), HB_TAG('E','S','P',' ')}, /* Spanish */ + {HB_TAG('e','t',' ',' '), HB_TAG('E','T','I',' ')}, /* Estonian [macrolanguage] */ + {HB_TAG('e','u',' ',' '), HB_TAG('E','U','Q',' ')}, /* Basque */ + {HB_TAG('f','a',' ',' '), HB_TAG('F','A','R',' ')}, /* Persian [macrolanguage] */ + {HB_TAG('f','f',' ',' '), HB_TAG('F','U','L',' ')}, /* Fulah [macrolanguage] */ + {HB_TAG('f','i',' ',' '), HB_TAG('F','I','N',' ')}, /* Finnish */ + {HB_TAG('f','j',' ',' '), HB_TAG('F','J','I',' ')}, /* Fijian */ + {HB_TAG('f','o',' ',' '), HB_TAG('F','O','S',' ')}, /* Faroese */ + {HB_TAG('f','r',' ',' '), HB_TAG('F','R','A',' ')}, /* French */ + {HB_TAG('f','y',' ',' '), HB_TAG('F','R','I',' ')}, /* Western Frisian -> Frisian */ + {HB_TAG('g','a',' ',' '), HB_TAG('I','R','I',' ')}, /* Irish */ + {HB_TAG('g','d',' ',' '), HB_TAG('G','A','E',' ')}, /* Scottish Gaelic (Gaelic) */ + {HB_TAG('g','l',' ',' '), HB_TAG('G','A','L',' ')}, /* Galician */ + {HB_TAG('g','n',' ',' '), HB_TAG('G','U','A',' ')}, /* Guarani [macrolanguage] */ + {HB_TAG('g','u',' ',' '), HB_TAG('G','U','J',' ')}, /* Gujarati */ + {HB_TAG('g','v',' ',' '), HB_TAG('M','N','X',' ')}, /* Manx */ + {HB_TAG('h','a',' ',' '), HB_TAG('H','A','U',' ')}, /* Hausa */ + {HB_TAG('h','e',' ',' '), HB_TAG('I','W','R',' ')}, /* Hebrew */ + {HB_TAG('h','i',' ',' '), HB_TAG('H','I','N',' ')}, /* Hindi */ + {HB_TAG('h','o',' ',' '), HB_TAG('H','M','O',' ')}, /* Hiri Motu */ + {HB_TAG('h','o',' ',' '), HB_TAG('C','P','P',' ')}, /* Hiri Motu -> Creoles */ + {HB_TAG('h','r',' ',' '), HB_TAG('H','R','V',' ')}, /* Croatian */ + {HB_TAG('h','t',' ',' '), HB_TAG('H','A','I',' ')}, /* Haitian (Haitian Creole) */ + {HB_TAG('h','t',' ',' '), HB_TAG('C','P','P',' ')}, /* Haitian -> Creoles */ + {HB_TAG('h','u',' ',' '), HB_TAG('H','U','N',' ')}, /* Hungarian */ + {HB_TAG('h','y',' ',' '), HB_TAG('H','Y','E','0')}, /* Armenian -> Armenian East */ + {HB_TAG('h','y',' ',' '), HB_TAG('H','Y','E',' ')}, /* Armenian */ + {HB_TAG('h','z',' ',' '), HB_TAG('H','E','R',' ')}, /* Herero */ + {HB_TAG('i','a',' ',' '), HB_TAG('I','N','A',' ')}, /* Interlingua (International Auxiliary Language Association) */ + {HB_TAG('i','d',' ',' '), HB_TAG('I','N','D',' ')}, /* Indonesian */ + {HB_TAG('i','d',' ',' '), HB_TAG('M','L','Y',' ')}, /* Indonesian -> Malay */ + {HB_TAG('i','e',' ',' '), HB_TAG('I','L','E',' ')}, /* Interlingue */ + {HB_TAG('i','g',' ',' '), HB_TAG('I','B','O',' ')}, /* Igbo */ + {HB_TAG('i','i',' ',' '), HB_TAG('Y','I','M',' ')}, /* Sichuan Yi -> Yi Modern */ + {HB_TAG('i','k',' ',' '), HB_TAG('I','P','K',' ')}, /* Inupiaq [macrolanguage] -> Inupiat */ + {HB_TAG('i','n',' ',' '), HB_TAG('I','N','D',' ')}, /* Indonesian (retired code) */ + {HB_TAG('i','n',' ',' '), HB_TAG('M','L','Y',' ')}, /* Indonesian (retired code) -> Malay */ + {HB_TAG('i','o',' ',' '), HB_TAG('I','D','O',' ')}, /* Ido */ + {HB_TAG('i','s',' ',' '), HB_TAG('I','S','L',' ')}, /* Icelandic */ + {HB_TAG('i','t',' ',' '), HB_TAG('I','T','A',' ')}, /* Italian */ + {HB_TAG('i','u',' ',' '), HB_TAG('I','N','U',' ')}, /* Inuktitut [macrolanguage] */ + {HB_TAG('i','u',' ',' '), HB_TAG('I','N','U','K')}, /* Inuktitut [macrolanguage] -> Nunavik Inuktitut */ + {HB_TAG('i','w',' ',' '), HB_TAG('I','W','R',' ')}, /* Hebrew (retired code) */ + {HB_TAG('j','a',' ',' '), HB_TAG('J','A','N',' ')}, /* Japanese */ + {HB_TAG('j','i',' ',' '), HB_TAG('J','I','I',' ')}, /* Yiddish (retired code) */ + {HB_TAG('j','v',' ',' '), HB_TAG('J','A','V',' ')}, /* Javanese */ + {HB_TAG('j','w',' ',' '), HB_TAG('J','A','V',' ')}, /* Javanese (retired code) */ + {HB_TAG('k','a',' ',' '), HB_TAG('K','A','T',' ')}, /* Georgian */ + {HB_TAG('k','g',' ',' '), HB_TAG('K','O','N','0')}, /* Kongo [macrolanguage] */ + {HB_TAG('k','i',' ',' '), HB_TAG('K','I','K',' ')}, /* Kikuyu (Gikuyu) */ + {HB_TAG('k','j',' ',' '), HB_TAG('K','U','A',' ')}, /* Kuanyama */ + {HB_TAG('k','k',' ',' '), HB_TAG('K','A','Z',' ')}, /* Kazakh */ + {HB_TAG('k','l',' ',' '), HB_TAG('G','R','N',' ')}, /* Greenlandic */ + {HB_TAG('k','m',' ',' '), HB_TAG('K','H','M',' ')}, /* Khmer */ + {HB_TAG('k','n',' ',' '), HB_TAG('K','A','N',' ')}, /* Kannada */ + {HB_TAG('k','o',' ',' '), HB_TAG('K','O','R',' ')}, /* Korean */ + {HB_TAG('k','o',' ',' '), HB_TAG('K','O','H',' ')}, /* Korean -> Korean Old Hangul */ + {HB_TAG('k','r',' ',' '), HB_TAG('K','N','R',' ')}, /* Kanuri [macrolanguage] */ + {HB_TAG('k','s',' ',' '), HB_TAG('K','S','H',' ')}, /* Kashmiri */ + {HB_TAG('k','u',' ',' '), HB_TAG('K','U','R',' ')}, /* Kurdish [macrolanguage] */ + {HB_TAG('k','v',' ',' '), HB_TAG('K','O','M',' ')}, /* Komi [macrolanguage] */ + {HB_TAG('k','w',' ',' '), HB_TAG('C','O','R',' ')}, /* Cornish */ + {HB_TAG('k','y',' ',' '), HB_TAG('K','I','R',' ')}, /* Kirghiz (Kyrgyz) */ + {HB_TAG('l','a',' ',' '), HB_TAG('L','A','T',' ')}, /* Latin */ + {HB_TAG('l','b',' ',' '), HB_TAG('L','T','Z',' ')}, /* Luxembourgish */ + {HB_TAG('l','g',' ',' '), HB_TAG('L','U','G',' ')}, /* Ganda */ + {HB_TAG('l','i',' ',' '), HB_TAG('L','I','M',' ')}, /* Limburgish */ + {HB_TAG('l','n',' ',' '), HB_TAG('L','I','N',' ')}, /* Lingala */ + {HB_TAG('l','o',' ',' '), HB_TAG('L','A','O',' ')}, /* Lao */ + {HB_TAG('l','t',' ',' '), HB_TAG('L','T','H',' ')}, /* Lithuanian */ + {HB_TAG('l','u',' ',' '), HB_TAG('L','U','B',' ')}, /* Luba-Katanga */ + {HB_TAG('l','v',' ',' '), HB_TAG('L','V','I',' ')}, /* Latvian [macrolanguage] */ + {HB_TAG('m','g',' ',' '), HB_TAG('M','L','G',' ')}, /* Malagasy [macrolanguage] */ + {HB_TAG('m','h',' ',' '), HB_TAG('M','A','H',' ')}, /* Marshallese */ + {HB_TAG('m','i',' ',' '), HB_TAG('M','R','I',' ')}, /* Maori */ + {HB_TAG('m','k',' ',' '), HB_TAG('M','K','D',' ')}, /* Macedonian */ + {HB_TAG('m','l',' ',' '), HB_TAG('M','A','L',' ')}, /* Malayalam -> Malayalam Traditional */ + {HB_TAG('m','l',' ',' '), HB_TAG('M','L','R',' ')}, /* Malayalam -> Malayalam Reformed */ + {HB_TAG('m','n',' ',' '), HB_TAG('M','N','G',' ')}, /* Mongolian [macrolanguage] */ + {HB_TAG('m','o',' ',' '), HB_TAG('M','O','L',' ')}, /* Moldavian (retired code) */ + {HB_TAG('m','o',' ',' '), HB_TAG('R','O','M',' ')}, /* Moldavian (retired code) -> Romanian */ + {HB_TAG('m','r',' ',' '), HB_TAG('M','A','R',' ')}, /* Marathi */ + {HB_TAG('m','s',' ',' '), HB_TAG('M','L','Y',' ')}, /* Malay [macrolanguage] */ + {HB_TAG('m','t',' ',' '), HB_TAG('M','T','S',' ')}, /* Maltese */ + {HB_TAG('m','y',' ',' '), HB_TAG('B','R','M',' ')}, /* Burmese */ + {HB_TAG('n','a',' ',' '), HB_TAG('N','A','U',' ')}, /* Nauru -> Nauruan */ + {HB_TAG('n','b',' ',' '), HB_TAG('N','O','R',' ')}, /* Norwegian BokmÃ¥l -> Norwegian */ + {HB_TAG('n','d',' ',' '), HB_TAG('N','D','B',' ')}, /* North Ndebele -> Ndebele */ + {HB_TAG('n','e',' ',' '), HB_TAG('N','E','P',' ')}, /* Nepali [macrolanguage] */ + {HB_TAG('n','g',' ',' '), HB_TAG('N','D','G',' ')}, /* Ndonga */ + {HB_TAG('n','l',' ',' '), HB_TAG('N','L','D',' ')}, /* Dutch */ + {HB_TAG('n','n',' ',' '), HB_TAG('N','Y','N',' ')}, /* Norwegian Nynorsk (Nynorsk, Norwegian) */ + {HB_TAG('n','o',' ',' '), HB_TAG('N','O','R',' ')}, /* Norwegian [macrolanguage] */ + {HB_TAG('n','r',' ',' '), HB_TAG('N','D','B',' ')}, /* South Ndebele -> Ndebele */ + {HB_TAG('n','v',' ',' '), HB_TAG('N','A','V',' ')}, /* Navajo */ + {HB_TAG('n','v',' ',' '), HB_TAG('A','T','H',' ')}, /* Navajo -> Athapaskan */ + {HB_TAG('n','y',' ',' '), HB_TAG('C','H','I',' ')}, /* Chichewa (Chewa, Nyanja) */ + {HB_TAG('o','c',' ',' '), HB_TAG('O','C','I',' ')}, /* Occitan (post 1500) */ + {HB_TAG('o','j',' ',' '), HB_TAG('O','J','B',' ')}, /* Ojibwa [macrolanguage] -> Ojibway */ + {HB_TAG('o','m',' ',' '), HB_TAG('O','R','O',' ')}, /* Oromo [macrolanguage] */ + {HB_TAG('o','r',' ',' '), HB_TAG('O','R','I',' ')}, /* Odia (formerly Oriya) [macrolanguage] */ + {HB_TAG('o','s',' ',' '), HB_TAG('O','S','S',' ')}, /* Ossetian */ + {HB_TAG('p','a',' ',' '), HB_TAG('P','A','N',' ')}, /* Punjabi */ + {HB_TAG('p','i',' ',' '), HB_TAG('P','A','L',' ')}, /* Pali */ + {HB_TAG('p','l',' ',' '), HB_TAG('P','L','K',' ')}, /* Polish */ + {HB_TAG('p','s',' ',' '), HB_TAG('P','A','S',' ')}, /* Pashto [macrolanguage] */ + {HB_TAG('p','t',' ',' '), HB_TAG('P','T','G',' ')}, /* Portuguese */ + {HB_TAG('q','u',' ',' '), HB_TAG('Q','U','Z',' ')}, /* Quechua [macrolanguage] */ + {HB_TAG('r','m',' ',' '), HB_TAG('R','M','S',' ')}, /* Romansh */ + {HB_TAG('r','n',' ',' '), HB_TAG('R','U','N',' ')}, /* Rundi */ + {HB_TAG('r','o',' ',' '), HB_TAG('R','O','M',' ')}, /* Romanian */ + {HB_TAG('r','u',' ',' '), HB_TAG('R','U','S',' ')}, /* Russian */ + {HB_TAG('r','w',' ',' '), HB_TAG('R','U','A',' ')}, /* Kinyarwanda */ + {HB_TAG('s','a',' ',' '), HB_TAG('S','A','N',' ')}, /* Sanskrit */ + {HB_TAG('s','c',' ',' '), HB_TAG('S','R','D',' ')}, /* Sardinian [macrolanguage] */ + {HB_TAG('s','d',' ',' '), HB_TAG('S','N','D',' ')}, /* Sindhi */ + {HB_TAG('s','e',' ',' '), HB_TAG('N','S','M',' ')}, /* Northern Sami */ + {HB_TAG('s','g',' ',' '), HB_TAG('S','G','O',' ')}, /* Sango */ + {HB_TAG('s','h',' ',' '), HB_TAG('B','O','S',' ')}, /* Serbo-Croatian [macrolanguage] -> Bosnian */ + {HB_TAG('s','h',' ',' '), HB_TAG('H','R','V',' ')}, /* Serbo-Croatian [macrolanguage] -> Croatian */ + {HB_TAG('s','h',' ',' '), HB_TAG('S','R','B',' ')}, /* Serbo-Croatian [macrolanguage] -> Serbian */ + {HB_TAG('s','i',' ',' '), HB_TAG('S','N','H',' ')}, /* Sinhala (Sinhalese) */ + {HB_TAG('s','k',' ',' '), HB_TAG('S','K','Y',' ')}, /* Slovak */ + {HB_TAG('s','l',' ',' '), HB_TAG('S','L','V',' ')}, /* Slovenian */ + {HB_TAG('s','m',' ',' '), HB_TAG('S','M','O',' ')}, /* Samoan */ + {HB_TAG('s','n',' ',' '), HB_TAG('S','N','A','0')}, /* Shona */ + {HB_TAG('s','o',' ',' '), HB_TAG('S','M','L',' ')}, /* Somali */ + {HB_TAG('s','q',' ',' '), HB_TAG('S','Q','I',' ')}, /* Albanian [macrolanguage] */ + {HB_TAG('s','r',' ',' '), HB_TAG('S','R','B',' ')}, /* Serbian */ + {HB_TAG('s','s',' ',' '), HB_TAG('S','W','Z',' ')}, /* Swati */ + {HB_TAG('s','t',' ',' '), HB_TAG('S','O','T',' ')}, /* Southern Sotho */ + {HB_TAG('s','u',' ',' '), HB_TAG('S','U','N',' ')}, /* Sundanese */ + {HB_TAG('s','v',' ',' '), HB_TAG('S','V','E',' ')}, /* Swedish */ + {HB_TAG('s','w',' ',' '), HB_TAG('S','W','K',' ')}, /* Swahili [macrolanguage] */ + {HB_TAG('t','a',' ',' '), HB_TAG('T','A','M',' ')}, /* Tamil */ + {HB_TAG('t','e',' ',' '), HB_TAG('T','E','L',' ')}, /* Telugu */ + {HB_TAG('t','g',' ',' '), HB_TAG('T','A','J',' ')}, /* Tajik -> Tajiki */ + {HB_TAG('t','h',' ',' '), HB_TAG('T','H','A',' ')}, /* Thai */ + {HB_TAG('t','i',' ',' '), HB_TAG('T','G','Y',' ')}, /* Tigrinya */ + {HB_TAG('t','k',' ',' '), HB_TAG('T','K','M',' ')}, /* Turkmen */ + {HB_TAG('t','l',' ',' '), HB_TAG('T','G','L',' ')}, /* Tagalog */ + {HB_TAG('t','n',' ',' '), HB_TAG('T','N','A',' ')}, /* Tswana */ + {HB_TAG('t','o',' ',' '), HB_TAG('T','G','N',' ')}, /* Tonga (Tonga Islands) -> Tongan */ + {HB_TAG('t','r',' ',' '), HB_TAG('T','R','K',' ')}, /* Turkish */ + {HB_TAG('t','s',' ',' '), HB_TAG('T','S','G',' ')}, /* Tsonga */ + {HB_TAG('t','t',' ',' '), HB_TAG('T','A','T',' ')}, /* Tatar */ + {HB_TAG('t','w',' ',' '), HB_TAG('T','W','I',' ')}, /* Twi */ + {HB_TAG('t','w',' ',' '), HB_TAG('A','K','A',' ')}, /* Twi -> Akan */ + {HB_TAG('t','y',' ',' '), HB_TAG('T','H','T',' ')}, /* Tahitian */ + {HB_TAG('u','g',' ',' '), HB_TAG('U','Y','G',' ')}, /* Uyghur */ + {HB_TAG('u','k',' ',' '), HB_TAG('U','K','R',' ')}, /* Ukrainian */ + {HB_TAG('u','r',' ',' '), HB_TAG('U','R','D',' ')}, /* Urdu */ + {HB_TAG('u','z',' ',' '), HB_TAG('U','Z','B',' ')}, /* Uzbek [macrolanguage] */ + {HB_TAG('v','e',' ',' '), HB_TAG('V','E','N',' ')}, /* Venda */ + {HB_TAG('v','i',' ',' '), HB_TAG('V','I','T',' ')}, /* Vietnamese */ + {HB_TAG('v','o',' ',' '), HB_TAG('V','O','L',' ')}, /* Volapük */ + {HB_TAG('w','a',' ',' '), HB_TAG('W','L','N',' ')}, /* Walloon */ + {HB_TAG('w','o',' ',' '), HB_TAG('W','L','F',' ')}, /* Wolof */ + {HB_TAG('x','h',' ',' '), HB_TAG('X','H','S',' ')}, /* Xhosa */ + {HB_TAG('y','i',' ',' '), HB_TAG('J','I','I',' ')}, /* Yiddish [macrolanguage] */ + {HB_TAG('y','o',' ',' '), HB_TAG('Y','B','A',' ')}, /* Yoruba */ + {HB_TAG('z','a',' ',' '), HB_TAG('Z','H','A',' ')}, /* Zhuang [macrolanguage] */ + {HB_TAG('z','h',' ',' '), HB_TAG('Z','H','S',' ')}, /* Chinese, Simplified [macrolanguage] */ + {HB_TAG('z','u',' ',' '), HB_TAG('Z','U','L',' ')}, /* Zulu */ }; +#ifndef HB_NO_LANGUAGE_LONG +static const LangTag ot_languages3[] = { + {HB_TAG('a','a','e',' '), HB_TAG('S','Q','I',' ')}, /* Arbëreshë Albanian -> Albanian */ + {HB_TAG('a','a','o',' '), HB_TAG('A','R','A',' ')}, /* Algerian Saharan Arabic -> Arabic */ + {HB_TAG('a','a','t',' '), HB_TAG('S','Q','I',' ')}, /* Arvanitika Albanian -> Albanian */ + {HB_TAG('a','b','a',' '), HB_TAG_NONE }, /* Abé != Abaza */ + {HB_TAG('a','b','h',' '), HB_TAG('A','R','A',' ')}, /* Tajiki Arabic -> Arabic */ + {HB_TAG('a','b','q',' '), HB_TAG('A','B','A',' ')}, /* Abaza */ + {HB_TAG('a','b','s',' '), HB_TAG('C','P','P',' ')}, /* Ambonese Malay -> Creoles */ + {HB_TAG('a','b','v',' '), HB_TAG('A','R','A',' ')}, /* Baharna Arabic -> Arabic */ + {HB_TAG('a','c','f',' '), HB_TAG('F','A','N',' ')}, /* Saint Lucian Creole French -> French Antillean */ + {HB_TAG('a','c','f',' '), HB_TAG('C','P','P',' ')}, /* Saint Lucian Creole French -> Creoles */ +/*{HB_TAG('a','c','h',' '), HB_TAG('A','C','H',' ')},*/ /* Acoli -> Acholi */ + {HB_TAG('a','c','m',' '), HB_TAG('A','R','A',' ')}, /* Mesopotamian Arabic -> Arabic */ + {HB_TAG('a','c','q',' '), HB_TAG('A','R','A',' ')}, /* Ta'izzi-Adeni Arabic -> Arabic */ + {HB_TAG('a','c','r',' '), HB_TAG('A','C','R',' ')}, /* Achi */ + {HB_TAG('a','c','r',' '), HB_TAG('M','Y','N',' ')}, /* Achi -> Mayan */ + {HB_TAG('a','c','w',' '), HB_TAG('A','R','A',' ')}, /* Hijazi Arabic -> Arabic */ + {HB_TAG('a','c','x',' '), HB_TAG('A','R','A',' ')}, /* Omani Arabic -> Arabic */ + {HB_TAG('a','c','y',' '), HB_TAG('A','R','A',' ')}, /* Cypriot Arabic -> Arabic */ + {HB_TAG('a','d','a',' '), HB_TAG('D','N','G',' ')}, /* Adangme -> Dangme */ + {HB_TAG('a','d','f',' '), HB_TAG('A','R','A',' ')}, /* Dhofari Arabic -> Arabic */ + {HB_TAG('a','d','p',' '), HB_TAG('D','Z','N',' ')}, /* Adap (retired code) -> Dzongkha */ +/*{HB_TAG('a','d','y',' '), HB_TAG('A','D','Y',' ')},*/ /* Adyghe */ + {HB_TAG('a','e','b',' '), HB_TAG('A','R','A',' ')}, /* Tunisian Arabic -> Arabic */ + {HB_TAG('a','e','c',' '), HB_TAG('A','R','A',' ')}, /* Saidi Arabic -> Arabic */ + {HB_TAG('a','f','b',' '), HB_TAG('A','R','A',' ')}, /* Gulf Arabic -> Arabic */ + {HB_TAG('a','f','k',' '), HB_TAG_NONE }, /* Nanubae != Afrikaans */ + {HB_TAG('a','f','s',' '), HB_TAG('C','P','P',' ')}, /* Afro-Seminole Creole -> Creoles */ + {HB_TAG('a','g','u',' '), HB_TAG('M','Y','N',' ')}, /* Aguacateco -> Mayan */ + {HB_TAG('a','g','w',' '), HB_TAG_NONE }, /* Kahua != Agaw */ + {HB_TAG('a','h','g',' '), HB_TAG('A','G','W',' ')}, /* Qimant -> Agaw */ + {HB_TAG('a','h','t',' '), HB_TAG('A','T','H',' ')}, /* Ahtena -> Athapaskan */ + {HB_TAG('a','i','g',' '), HB_TAG('C','P','P',' ')}, /* Antigua and Barbuda Creole English -> Creoles */ + {HB_TAG('a','i','i',' '), HB_TAG('S','W','A',' ')}, /* Assyrian Neo-Aramaic -> Swadaya Aramaic */ + {HB_TAG('a','i','i',' '), HB_TAG('S','Y','R',' ')}, /* Assyrian Neo-Aramaic -> Syriac */ +/*{HB_TAG('a','i','o',' '), HB_TAG('A','I','O',' ')},*/ /* Aiton */ + {HB_TAG('a','i','w',' '), HB_TAG('A','R','I',' ')}, /* Aari */ + {HB_TAG('a','j','p',' '), HB_TAG('A','R','A',' ')}, /* South Levantine Arabic -> Arabic */ + {HB_TAG('a','j','t',' '), HB_TAG('A','R','A',' ')}, /* Judeo-Tunisian Arabic (retired code) -> Arabic */ + {HB_TAG('a','k','b',' '), HB_TAG('A','K','B',' ')}, /* Batak Angkola */ + {HB_TAG('a','k','b',' '), HB_TAG('B','T','K',' ')}, /* Batak Angkola -> Batak */ + {HB_TAG('a','l','n',' '), HB_TAG('S','Q','I',' ')}, /* Gheg Albanian -> Albanian */ + {HB_TAG('a','l','s',' '), HB_TAG('S','Q','I',' ')}, /* Tosk Albanian -> Albanian */ +/*{HB_TAG('a','l','t',' '), HB_TAG('A','L','T',' ')},*/ /* Southern Altai -> Altai */ + {HB_TAG('a','m','f',' '), HB_TAG('H','B','N',' ')}, /* Hamer-Banna -> Hammer-Banna */ + {HB_TAG('a','m','w',' '), HB_TAG('S','Y','R',' ')}, /* Western Neo-Aramaic -> Syriac */ +/*{HB_TAG('a','n','g',' '), HB_TAG('A','N','G',' ')},*/ /* Old English (ca. 450-1100) -> Anglo-Saxon */ + {HB_TAG('a','o','a',' '), HB_TAG('C','P','P',' ')}, /* Angolar -> Creoles */ + {HB_TAG('a','p','a',' '), HB_TAG('A','T','H',' ')}, /* Apache [collection] -> Athapaskan */ + {HB_TAG('a','p','c',' '), HB_TAG('A','R','A',' ')}, /* North Levantine Arabic -> Arabic */ + {HB_TAG('a','p','d',' '), HB_TAG('A','R','A',' ')}, /* Sudanese Arabic -> Arabic */ + {HB_TAG('a','p','j',' '), HB_TAG('A','T','H',' ')}, /* Jicarilla Apache -> Athapaskan */ + {HB_TAG('a','p','k',' '), HB_TAG('A','T','H',' ')}, /* Kiowa Apache -> Athapaskan */ + {HB_TAG('a','p','l',' '), HB_TAG('A','T','H',' ')}, /* Lipan Apache -> Athapaskan */ + {HB_TAG('a','p','m',' '), HB_TAG('A','T','H',' ')}, /* Mescalero-Chiricahua Apache -> Athapaskan */ + {HB_TAG('a','p','w',' '), HB_TAG('A','T','H',' ')}, /* Western Apache -> Athapaskan */ + {HB_TAG('a','r','b',' '), HB_TAG('A','R','A',' ')}, /* Standard Arabic -> Arabic */ + {HB_TAG('a','r','i',' '), HB_TAG_NONE }, /* Arikara != Aari */ + {HB_TAG('a','r','k',' '), HB_TAG_NONE }, /* Arikapú != Rakhine */ + {HB_TAG('a','r','n',' '), HB_TAG('M','A','P',' ')}, /* Mapudungun */ + {HB_TAG('a','r','q',' '), HB_TAG('A','R','A',' ')}, /* Algerian Arabic -> Arabic */ + {HB_TAG('a','r','s',' '), HB_TAG('A','R','A',' ')}, /* Najdi Arabic -> Arabic */ + {HB_TAG('a','r','y',' '), HB_TAG('M','O','R',' ')}, /* Moroccan Arabic -> Moroccan */ + {HB_TAG('a','r','y',' '), HB_TAG('A','R','A',' ')}, /* Moroccan Arabic -> Arabic */ + {HB_TAG('a','r','z',' '), HB_TAG('A','R','A',' ')}, /* Egyptian Arabic -> Arabic */ +/*{HB_TAG('a','s','t',' '), HB_TAG('A','S','T',' ')},*/ /* Asturian */ +/*{HB_TAG('a','t','h',' '), HB_TAG('A','T','H',' ')},*/ /* Athapascan [collection] -> Athapaskan */ + {HB_TAG('a','t','j',' '), HB_TAG('R','C','R',' ')}, /* Atikamekw -> R-Cree */ + {HB_TAG('a','t','v',' '), HB_TAG('A','L','T',' ')}, /* Northern Altai -> Altai */ + {HB_TAG('a','u','j',' '), HB_TAG('B','B','R',' ')}, /* Awjilah -> Berber */ + {HB_TAG('a','u','z',' '), HB_TAG('A','R','A',' ')}, /* Uzbeki Arabic -> Arabic */ + {HB_TAG('a','v','l',' '), HB_TAG('A','R','A',' ')}, /* Eastern Egyptian Bedawi Arabic -> Arabic */ +/*{HB_TAG('a','v','n',' '), HB_TAG('A','V','N',' ')},*/ /* Avatime */ +/*{HB_TAG('a','w','a',' '), HB_TAG('A','W','A',' ')},*/ /* Awadhi */ + {HB_TAG('a','y','c',' '), HB_TAG('A','Y','M',' ')}, /* Southern Aymara -> Aymara */ + {HB_TAG('a','y','h',' '), HB_TAG('A','R','A',' ')}, /* Hadrami Arabic -> Arabic */ + {HB_TAG('a','y','l',' '), HB_TAG('A','R','A',' ')}, /* Libyan Arabic -> Arabic */ + {HB_TAG('a','y','n',' '), HB_TAG('A','R','A',' ')}, /* Sanaani Arabic -> Arabic */ + {HB_TAG('a','y','p',' '), HB_TAG('A','R','A',' ')}, /* North Mesopotamian Arabic -> Arabic */ + {HB_TAG('a','y','r',' '), HB_TAG('A','Y','M',' ')}, /* Central Aymara -> Aymara */ + {HB_TAG('a','z','b',' '), HB_TAG('A','Z','B',' ')}, /* South Azerbaijani -> Torki */ + {HB_TAG('a','z','b',' '), HB_TAG('A','Z','E',' ')}, /* South Azerbaijani -> Azerbaijani */ + {HB_TAG('a','z','d',' '), HB_TAG('N','A','H',' ')}, /* Eastern Durango Nahuatl -> Nahuatl */ + {HB_TAG('a','z','j',' '), HB_TAG('A','Z','E',' ')}, /* North Azerbaijani -> Azerbaijani */ + {HB_TAG('a','z','n',' '), HB_TAG('N','A','H',' ')}, /* Western Durango Nahuatl -> Nahuatl */ + {HB_TAG('a','z','z',' '), HB_TAG('N','A','H',' ')}, /* Highland Puebla Nahuatl -> Nahuatl */ + {HB_TAG('b','a','d',' '), HB_TAG('B','A','D','0')}, /* Banda [collection] */ + {HB_TAG('b','a','g',' '), HB_TAG_NONE }, /* Tuki != Baghelkhandi */ + {HB_TAG('b','a','h',' '), HB_TAG('C','P','P',' ')}, /* Bahamas Creole English -> Creoles */ + {HB_TAG('b','a','i',' '), HB_TAG('B','M','L',' ')}, /* Bamileke [collection] */ + {HB_TAG('b','a','l',' '), HB_TAG('B','L','I',' ')}, /* Baluchi [macrolanguage] */ +/*{HB_TAG('b','a','n',' '), HB_TAG('B','A','N',' ')},*/ /* Balinese */ +/*{HB_TAG('b','a','r',' '), HB_TAG('B','A','R',' ')},*/ /* Bavarian */ + {HB_TAG('b','a','u',' '), HB_TAG_NONE }, /* Bada (Nigeria) != Baulé */ + {HB_TAG('b','b','c',' '), HB_TAG('B','B','C',' ')}, /* Batak Toba */ + {HB_TAG('b','b','c',' '), HB_TAG('B','T','K',' ')}, /* Batak Toba -> Batak */ + {HB_TAG('b','b','j',' '), HB_TAG('B','M','L',' ')}, /* Ghomálá' -> Bamileke */ + {HB_TAG('b','b','p',' '), HB_TAG('B','A','D','0')}, /* West Central Banda -> Banda */ + {HB_TAG('b','b','r',' '), HB_TAG_NONE }, /* Girawa != Berber */ + {HB_TAG('b','b','z',' '), HB_TAG('A','R','A',' ')}, /* Babalia Creole Arabic (retired code) -> Arabic */ + {HB_TAG('b','c','c',' '), HB_TAG('B','L','I',' ')}, /* Southern Balochi -> Baluchi */ + {HB_TAG('b','c','h',' '), HB_TAG_NONE }, /* Bariai != Bench */ + {HB_TAG('b','c','i',' '), HB_TAG('B','A','U',' ')}, /* Baoulé -> Baulé */ + {HB_TAG('b','c','l',' '), HB_TAG('B','I','K',' ')}, /* Central Bikol -> Bikol */ + {HB_TAG('b','c','q',' '), HB_TAG('B','C','H',' ')}, /* Bench */ + {HB_TAG('b','c','r',' '), HB_TAG('A','T','H',' ')}, /* Babine -> Athapaskan */ +/*{HB_TAG('b','d','y',' '), HB_TAG('B','D','Y',' ')},*/ /* Bandjalang */ + {HB_TAG('b','e','a',' '), HB_TAG('A','T','H',' ')}, /* Beaver -> Athapaskan */ + {HB_TAG('b','e','b',' '), HB_TAG('B','T','I',' ')}, /* Bebele -> Beti */ +/*{HB_TAG('b','e','m',' '), HB_TAG('B','E','M',' ')},*/ /* Bemba (Zambia) */ + {HB_TAG('b','e','r',' '), HB_TAG('B','B','R',' ')}, /* Berber [collection] */ + {HB_TAG('b','e','w',' '), HB_TAG('C','P','P',' ')}, /* Betawi -> Creoles */ + {HB_TAG('b','f','l',' '), HB_TAG('B','A','D','0')}, /* Banda-Ndélé -> Banda */ + {HB_TAG('b','f','q',' '), HB_TAG('B','A','D',' ')}, /* Badaga */ + {HB_TAG('b','f','t',' '), HB_TAG('B','L','T',' ')}, /* Balti */ + {HB_TAG('b','f','u',' '), HB_TAG('L','A','H',' ')}, /* Gahri -> Lahuli */ + {HB_TAG('b','f','y',' '), HB_TAG('B','A','G',' ')}, /* Bagheli -> Baghelkhandi */ +/*{HB_TAG('b','g','c',' '), HB_TAG('B','G','C',' ')},*/ /* Haryanvi */ + {HB_TAG('b','g','n',' '), HB_TAG('B','L','I',' ')}, /* Western Balochi -> Baluchi */ + {HB_TAG('b','g','p',' '), HB_TAG('B','L','I',' ')}, /* Eastern Balochi -> Baluchi */ + {HB_TAG('b','g','q',' '), HB_TAG('B','G','Q',' ')}, /* Bagri */ + {HB_TAG('b','g','q',' '), HB_TAG('R','A','J',' ')}, /* Bagri -> Rajasthani */ + {HB_TAG('b','g','r',' '), HB_TAG('Q','I','N',' ')}, /* Bawm Chin -> Chin */ + {HB_TAG('b','h','b',' '), HB_TAG('B','H','I',' ')}, /* Bhili */ +/*{HB_TAG('b','h','i',' '), HB_TAG('B','H','I',' ')},*/ /* Bhilali -> Bhili */ + {HB_TAG('b','h','k',' '), HB_TAG('B','I','K',' ')}, /* Albay Bicolano (retired code) -> Bikol */ +/*{HB_TAG('b','h','o',' '), HB_TAG('B','H','O',' ')},*/ /* Bhojpuri */ + {HB_TAG('b','h','r',' '), HB_TAG('M','L','G',' ')}, /* Bara Malagasy -> Malagasy */ +/*{HB_TAG('b','i','k',' '), HB_TAG('B','I','K',' ')},*/ /* Bikol [macrolanguage] */ + {HB_TAG('b','i','l',' '), HB_TAG_NONE }, /* Bile != Bilen */ + {HB_TAG('b','i','n',' '), HB_TAG('E','D','O',' ')}, /* Edo */ + {HB_TAG('b','i','u',' '), HB_TAG('Q','I','N',' ')}, /* Biete -> Chin */ +/*{HB_TAG('b','j','j',' '), HB_TAG('B','J','J',' ')},*/ /* Kanauji */ + {HB_TAG('b','j','n',' '), HB_TAG('M','L','Y',' ')}, /* Banjar -> Malay */ + {HB_TAG('b','j','o',' '), HB_TAG('B','A','D','0')}, /* Mid-Southern Banda -> Banda */ + {HB_TAG('b','j','q',' '), HB_TAG('M','L','G',' ')}, /* Southern Betsimisaraka Malagasy (retired code) -> Malagasy */ + {HB_TAG('b','j','s',' '), HB_TAG('C','P','P',' ')}, /* Bajan -> Creoles */ + {HB_TAG('b','j','t',' '), HB_TAG('B','L','N',' ')}, /* Balanta-Ganja -> Balante */ + {HB_TAG('b','k','f',' '), HB_TAG_NONE }, /* Beeke != Blackfoot */ + {HB_TAG('b','k','o',' '), HB_TAG('B','M','L',' ')}, /* Kwa' -> Bamileke */ + {HB_TAG('b','l','a',' '), HB_TAG('B','K','F',' ')}, /* Siksika -> Blackfoot */ + {HB_TAG('b','l','e',' '), HB_TAG('B','L','N',' ')}, /* Balanta-Kentohe -> Balante */ + {HB_TAG('b','l','g',' '), HB_TAG('I','B','A',' ')}, /* Balau (retired code) -> Iban */ + {HB_TAG('b','l','i',' '), HB_TAG_NONE }, /* Bolia != Baluchi */ + {HB_TAG('b','l','k',' '), HB_TAG('B','L','K',' ')}, /* Pa’o Karen */ + {HB_TAG('b','l','k',' '), HB_TAG('K','R','N',' ')}, /* Pa'o Karen -> Karen */ + {HB_TAG('b','l','n',' '), HB_TAG('B','I','K',' ')}, /* Southern Catanduanes Bikol -> Bikol */ + {HB_TAG('b','l','t',' '), HB_TAG_NONE }, /* Tai Dam != Balti */ + {HB_TAG('b','m','b',' '), HB_TAG_NONE }, /* Bembe != Bambara (Bamanankan) */ + {HB_TAG('b','m','l',' '), HB_TAG_NONE }, /* Bomboli != Bamileke */ + {HB_TAG('b','m','m',' '), HB_TAG('M','L','G',' ')}, /* Northern Betsimisaraka Malagasy -> Malagasy */ + {HB_TAG('b','p','d',' '), HB_TAG('B','A','D','0')}, /* Banda-Banda -> Banda */ + {HB_TAG('b','p','l',' '), HB_TAG('C','P','P',' ')}, /* Broome Pearling Lugger Pidgin -> Creoles */ + {HB_TAG('b','p','q',' '), HB_TAG('C','P','P',' ')}, /* Banda Malay -> Creoles */ +/*{HB_TAG('b','p','y',' '), HB_TAG('B','P','Y',' ')},*/ /* Bishnupriya -> Bishnupriya Manipuri */ + {HB_TAG('b','q','i',' '), HB_TAG('L','R','C',' ')}, /* Bakhtiari -> Luri */ + {HB_TAG('b','q','k',' '), HB_TAG('B','A','D','0')}, /* Banda-Mbrès -> Banda */ + {HB_TAG('b','r','a',' '), HB_TAG('B','R','I',' ')}, /* Braj -> Braj Bhasha */ + {HB_TAG('b','r','c',' '), HB_TAG('C','P','P',' ')}, /* Berbice Creole Dutch -> Creoles */ +/*{HB_TAG('b','r','h',' '), HB_TAG('B','R','H',' ')},*/ /* Brahui */ + {HB_TAG('b','r','i',' '), HB_TAG_NONE }, /* Mokpwe != Braj Bhasha */ + {HB_TAG('b','r','m',' '), HB_TAG_NONE }, /* Barambu != Burmese */ +/*{HB_TAG('b','r','x',' '), HB_TAG('B','R','X',' ')},*/ /* Bodo (India) */ + {HB_TAG('b','s','h',' '), HB_TAG_NONE }, /* Kati != Bashkir */ +/*{HB_TAG('b','s','k',' '), HB_TAG('B','S','K',' ')},*/ /* Burushaski */ + {HB_TAG('b','t','b',' '), HB_TAG('B','T','I',' ')}, /* Beti (Cameroon) (retired code) */ + {HB_TAG('b','t','d',' '), HB_TAG('B','T','D',' ')}, /* Batak Dairi (Pakpak) */ + {HB_TAG('b','t','d',' '), HB_TAG('B','T','K',' ')}, /* Batak Dairi -> Batak */ + {HB_TAG('b','t','i',' '), HB_TAG_NONE }, /* Burate != Beti */ + {HB_TAG('b','t','j',' '), HB_TAG('M','L','Y',' ')}, /* Bacanese Malay -> Malay */ +/*{HB_TAG('b','t','k',' '), HB_TAG('B','T','K',' ')},*/ /* Batak [collection] */ + {HB_TAG('b','t','m',' '), HB_TAG('B','T','M',' ')}, /* Batak Mandailing */ + {HB_TAG('b','t','m',' '), HB_TAG('B','T','K',' ')}, /* Batak Mandailing -> Batak */ + {HB_TAG('b','t','o',' '), HB_TAG('B','I','K',' ')}, /* Rinconada Bikol -> Bikol */ + {HB_TAG('b','t','s',' '), HB_TAG('B','T','S',' ')}, /* Batak Simalungun */ + {HB_TAG('b','t','s',' '), HB_TAG('B','T','K',' ')}, /* Batak Simalungun -> Batak */ + {HB_TAG('b','t','x',' '), HB_TAG('B','T','X',' ')}, /* Batak Karo */ + {HB_TAG('b','t','x',' '), HB_TAG('B','T','K',' ')}, /* Batak Karo -> Batak */ + {HB_TAG('b','t','z',' '), HB_TAG('B','T','Z',' ')}, /* Batak Alas-Kluet */ + {HB_TAG('b','t','z',' '), HB_TAG('B','T','K',' ')}, /* Batak Alas-Kluet -> Batak */ +/*{HB_TAG('b','u','g',' '), HB_TAG('B','U','G',' ')},*/ /* Buginese -> Bugis */ + {HB_TAG('b','u','m',' '), HB_TAG('B','T','I',' ')}, /* Bulu (Cameroon) -> Beti */ + {HB_TAG('b','v','e',' '), HB_TAG('M','L','Y',' ')}, /* Berau Malay -> Malay */ + {HB_TAG('b','v','u',' '), HB_TAG('M','L','Y',' ')}, /* Bukit Malay -> Malay */ + {HB_TAG('b','w','e',' '), HB_TAG('K','R','N',' ')}, /* Bwe Karen -> Karen */ + {HB_TAG('b','x','k',' '), HB_TAG('L','U','H',' ')}, /* Bukusu -> Luyia */ + {HB_TAG('b','x','o',' '), HB_TAG('C','P','P',' ')}, /* Barikanchi -> Creoles */ + {HB_TAG('b','x','p',' '), HB_TAG('B','T','I',' ')}, /* Bebil -> Beti */ + {HB_TAG('b','x','r',' '), HB_TAG('R','B','U',' ')}, /* Russia Buriat -> Russian Buriat */ + {HB_TAG('b','y','n',' '), HB_TAG('B','I','L',' ')}, /* Bilin -> Bilen */ + {HB_TAG('b','y','v',' '), HB_TAG('B','Y','V',' ')}, /* Medumba */ + {HB_TAG('b','y','v',' '), HB_TAG('B','M','L',' ')}, /* Medumba -> Bamileke */ + {HB_TAG('b','z','c',' '), HB_TAG('M','L','G',' ')}, /* Southern Betsimisaraka Malagasy -> Malagasy */ + {HB_TAG('b','z','j',' '), HB_TAG('C','P','P',' ')}, /* Belize Kriol English -> Creoles */ + {HB_TAG('b','z','k',' '), HB_TAG('C','P','P',' ')}, /* Nicaragua Creole English -> Creoles */ + {HB_TAG('c','a','a',' '), HB_TAG('M','Y','N',' ')}, /* Chortà -> Mayan */ + {HB_TAG('c','a','c',' '), HB_TAG('M','Y','N',' ')}, /* Chuj -> Mayan */ + {HB_TAG('c','a','f',' '), HB_TAG('C','R','R',' ')}, /* Southern Carrier -> Carrier */ + {HB_TAG('c','a','f',' '), HB_TAG('A','T','H',' ')}, /* Southern Carrier -> Athapaskan */ + {HB_TAG('c','a','k',' '), HB_TAG('C','A','K',' ')}, /* Kaqchikel */ + {HB_TAG('c','a','k',' '), HB_TAG('M','Y','N',' ')}, /* Kaqchikel -> Mayan */ + {HB_TAG('c','b','k',' '), HB_TAG('C','B','K',' ')}, /* Chavacano -> Zamboanga Chavacano */ + {HB_TAG('c','b','k',' '), HB_TAG('C','P','P',' ')}, /* Chavacano -> Creoles */ + {HB_TAG('c','b','l',' '), HB_TAG('Q','I','N',' ')}, /* Bualkhaw Chin -> Chin */ + {HB_TAG('c','c','l',' '), HB_TAG('C','P','P',' ')}, /* Cutchi-Swahili -> Creoles */ + {HB_TAG('c','c','m',' '), HB_TAG('C','P','P',' ')}, /* Malaccan Creole Malay -> Creoles */ + {HB_TAG('c','c','o',' '), HB_TAG('C','C','H','N')}, /* Comaltepec Chinantec -> Chinantec */ + {HB_TAG('c','c','q',' '), HB_TAG('A','R','K',' ')}, /* Chaungtha (retired code) -> Rakhine */ + {HB_TAG('c','d','o',' '), HB_TAG('Z','H','S',' ')}, /* Min Dong Chinese -> Chinese, Simplified */ +/*{HB_TAG('c','e','b',' '), HB_TAG('C','E','B',' ')},*/ /* Cebuano */ + {HB_TAG('c','e','k',' '), HB_TAG('Q','I','N',' ')}, /* Eastern Khumi Chin -> Chin */ + {HB_TAG('c','e','y',' '), HB_TAG('Q','I','N',' ')}, /* Ekai Chin -> Chin */ + {HB_TAG('c','f','m',' '), HB_TAG('H','A','L',' ')}, /* Halam (Falam Chin) */ + {HB_TAG('c','f','m',' '), HB_TAG('Q','I','N',' ')}, /* Falam Chin -> Chin */ +/*{HB_TAG('c','g','g',' '), HB_TAG('C','G','G',' ')},*/ /* Chiga */ + {HB_TAG('c','h','f',' '), HB_TAG('M','Y','N',' ')}, /* Tabasco Chontal -> Mayan */ + {HB_TAG('c','h','g',' '), HB_TAG_NONE }, /* Chagatai != Chaha Gurage */ + {HB_TAG('c','h','h',' '), HB_TAG_NONE }, /* Chinook != Chattisgarhi */ + {HB_TAG('c','h','j',' '), HB_TAG('C','C','H','N')}, /* Ojitlán Chinantec -> Chinantec */ + {HB_TAG('c','h','k',' '), HB_TAG('C','H','K','0')}, /* Chuukese */ + {HB_TAG('c','h','m',' '), HB_TAG('H','M','A',' ')}, /* Mari (Russia) [macrolanguage] -> High Mari */ + {HB_TAG('c','h','m',' '), HB_TAG('L','M','A',' ')}, /* Mari (Russia) [macrolanguage] -> Low Mari */ + {HB_TAG('c','h','n',' '), HB_TAG('C','P','P',' ')}, /* Chinook jargon -> Creoles */ +/*{HB_TAG('c','h','o',' '), HB_TAG('C','H','O',' ')},*/ /* Choctaw */ + {HB_TAG('c','h','p',' '), HB_TAG('C','H','P',' ')}, /* Chipewyan */ + {HB_TAG('c','h','p',' '), HB_TAG('S','A','Y',' ')}, /* Chipewyan -> Sayisi */ + {HB_TAG('c','h','p',' '), HB_TAG('A','T','H',' ')}, /* Chipewyan -> Athapaskan */ + {HB_TAG('c','h','q',' '), HB_TAG('C','C','H','N')}, /* Quiotepec Chinantec -> Chinantec */ +/*{HB_TAG('c','h','r',' '), HB_TAG('C','H','R',' ')},*/ /* Cherokee */ +/*{HB_TAG('c','h','y',' '), HB_TAG('C','H','Y',' ')},*/ /* Cheyenne */ + {HB_TAG('c','h','z',' '), HB_TAG('C','C','H','N')}, /* OzumacÃn Chinantec -> Chinantec */ + {HB_TAG('c','i','w',' '), HB_TAG('O','J','B',' ')}, /* Chippewa -> Ojibway */ +/*{HB_TAG('c','j','a',' '), HB_TAG('C','J','A',' ')},*/ /* Western Cham */ +/*{HB_TAG('c','j','m',' '), HB_TAG('C','J','M',' ')},*/ /* Eastern Cham */ + {HB_TAG('c','j','y',' '), HB_TAG('Z','H','S',' ')}, /* Jinyu Chinese -> Chinese, Simplified */ + {HB_TAG('c','k','a',' '), HB_TAG('Q','I','N',' ')}, /* Khumi Awa Chin (retired code) -> Chin */ + {HB_TAG('c','k','b',' '), HB_TAG('K','U','R',' ')}, /* Central Kurdish -> Kurdish */ + {HB_TAG('c','k','n',' '), HB_TAG('Q','I','N',' ')}, /* Kaang Chin -> Chin */ + {HB_TAG('c','k','s',' '), HB_TAG('C','P','P',' ')}, /* Tayo -> Creoles */ + {HB_TAG('c','k','t',' '), HB_TAG('C','H','K',' ')}, /* Chukot -> Chukchi */ + {HB_TAG('c','k','z',' '), HB_TAG('M','Y','N',' ')}, /* Cakchiquel-Quiché Mixed Language -> Mayan */ + {HB_TAG('c','l','c',' '), HB_TAG('A','T','H',' ')}, /* Chilcotin -> Athapaskan */ + {HB_TAG('c','l','d',' '), HB_TAG('S','Y','R',' ')}, /* Chaldean Neo-Aramaic -> Syriac */ + {HB_TAG('c','l','e',' '), HB_TAG('C','C','H','N')}, /* Lealao Chinantec -> Chinantec */ + {HB_TAG('c','l','j',' '), HB_TAG('Q','I','N',' ')}, /* Laitu Chin -> Chin */ + {HB_TAG('c','l','t',' '), HB_TAG('Q','I','N',' ')}, /* Lautu Chin -> Chin */ + {HB_TAG('c','m','n',' '), HB_TAG('Z','H','S',' ')}, /* Mandarin Chinese -> Chinese, Simplified */ + {HB_TAG('c','m','r',' '), HB_TAG('Q','I','N',' ')}, /* Mro-Khimi Chin -> Chin */ + {HB_TAG('c','n','b',' '), HB_TAG('Q','I','N',' ')}, /* Chinbon Chin -> Chin */ + {HB_TAG('c','n','h',' '), HB_TAG('Q','I','N',' ')}, /* Hakha Chin -> Chin */ + {HB_TAG('c','n','k',' '), HB_TAG('Q','I','N',' ')}, /* Khumi Chin -> Chin */ + {HB_TAG('c','n','l',' '), HB_TAG('C','C','H','N')}, /* Lalana Chinantec -> Chinantec */ + {HB_TAG('c','n','p',' '), HB_TAG('Z','H','S',' ')}, /* Northern Ping Chinese -> Chinese, Simplified */ + {HB_TAG('c','n','r',' '), HB_TAG('S','R','B',' ')}, /* Montenegrin -> Serbian */ + {HB_TAG('c','n','t',' '), HB_TAG('C','C','H','N')}, /* Tepetotutla Chinantec -> Chinantec */ + {HB_TAG('c','n','u',' '), HB_TAG('B','B','R',' ')}, /* Chenoua -> Berber */ + {HB_TAG('c','n','w',' '), HB_TAG('Q','I','N',' ')}, /* Ngawn Chin -> Chin */ + {HB_TAG('c','o','a',' '), HB_TAG('M','L','Y',' ')}, /* Cocos Islands Malay -> Malay */ + {HB_TAG('c','o','b',' '), HB_TAG('M','Y','N',' ')}, /* Chicomuceltec -> Mayan */ +/*{HB_TAG('c','o','p',' '), HB_TAG('C','O','P',' ')},*/ /* Coptic */ + {HB_TAG('c','o','q',' '), HB_TAG('A','T','H',' ')}, /* Coquille -> Athapaskan */ + {HB_TAG('c','p','a',' '), HB_TAG('C','C','H','N')}, /* Palantla Chinantec -> Chinantec */ + {HB_TAG('c','p','e',' '), HB_TAG('C','P','P',' ')}, /* English-based creoles and pidgins [collection] -> Creoles */ + {HB_TAG('c','p','f',' '), HB_TAG('C','P','P',' ')}, /* French-based creoles and pidgins [collection] -> Creoles */ + {HB_TAG('c','p','i',' '), HB_TAG('C','P','P',' ')}, /* Chinese Pidgin English -> Creoles */ +/*{HB_TAG('c','p','p',' '), HB_TAG('C','P','P',' ')},*/ /* Portuguese-based creoles and pidgins [collection] -> Creoles */ + {HB_TAG('c','p','x',' '), HB_TAG('Z','H','S',' ')}, /* Pu-Xian Chinese -> Chinese, Simplified */ + {HB_TAG('c','q','d',' '), HB_TAG('H','M','N',' ')}, /* Chuanqiandian Cluster Miao -> Hmong */ + {HB_TAG('c','q','u',' '), HB_TAG('Q','U','H',' ')}, /* Chilean Quechua (retired code) -> Quechua (Bolivia) */ + {HB_TAG('c','q','u',' '), HB_TAG('Q','U','Z',' ')}, /* Chilean Quechua (retired code) -> Quechua */ + {HB_TAG('c','r','h',' '), HB_TAG('C','R','T',' ')}, /* Crimean Tatar */ + {HB_TAG('c','r','i',' '), HB_TAG('C','P','P',' ')}, /* Sãotomense -> Creoles */ + {HB_TAG('c','r','j',' '), HB_TAG('E','C','R',' ')}, /* Southern East Cree -> Eastern Cree */ + {HB_TAG('c','r','j',' '), HB_TAG('Y','C','R',' ')}, /* Southern East Cree -> Y-Cree */ + {HB_TAG('c','r','j',' '), HB_TAG('C','R','E',' ')}, /* Southern East Cree -> Cree */ + {HB_TAG('c','r','k',' '), HB_TAG('W','C','R',' ')}, /* Plains Cree -> West-Cree */ + {HB_TAG('c','r','k',' '), HB_TAG('Y','C','R',' ')}, /* Plains Cree -> Y-Cree */ + {HB_TAG('c','r','k',' '), HB_TAG('C','R','E',' ')}, /* Plains Cree -> Cree */ + {HB_TAG('c','r','l',' '), HB_TAG('E','C','R',' ')}, /* Northern East Cree -> Eastern Cree */ + {HB_TAG('c','r','l',' '), HB_TAG('Y','C','R',' ')}, /* Northern East Cree -> Y-Cree */ + {HB_TAG('c','r','l',' '), HB_TAG('C','R','E',' ')}, /* Northern East Cree -> Cree */ + {HB_TAG('c','r','m',' '), HB_TAG('M','C','R',' ')}, /* Moose Cree */ + {HB_TAG('c','r','m',' '), HB_TAG('L','C','R',' ')}, /* Moose Cree -> L-Cree */ + {HB_TAG('c','r','m',' '), HB_TAG('C','R','E',' ')}, /* Moose Cree -> Cree */ + {HB_TAG('c','r','p',' '), HB_TAG('C','P','P',' ')}, /* Creoles and pidgins [collection] -> Creoles */ + {HB_TAG('c','r','r',' '), HB_TAG_NONE }, /* Carolina Algonquian != Carrier */ + {HB_TAG('c','r','s',' '), HB_TAG('C','P','P',' ')}, /* Seselwa Creole French -> Creoles */ + {HB_TAG('c','r','t',' '), HB_TAG_NONE }, /* Iyojwa'ja Chorote != Crimean Tatar */ + {HB_TAG('c','r','x',' '), HB_TAG('C','R','R',' ')}, /* Carrier */ + {HB_TAG('c','r','x',' '), HB_TAG('A','T','H',' ')}, /* Carrier -> Athapaskan */ + {HB_TAG('c','s','a',' '), HB_TAG('C','C','H','N')}, /* Chiltepec Chinantec -> Chinantec */ +/*{HB_TAG('c','s','b',' '), HB_TAG('C','S','B',' ')},*/ /* Kashubian */ + {HB_TAG('c','s','h',' '), HB_TAG('Q','I','N',' ')}, /* Asho Chin -> Chin */ + {HB_TAG('c','s','j',' '), HB_TAG('Q','I','N',' ')}, /* Songlai Chin -> Chin */ + {HB_TAG('c','s','l',' '), HB_TAG_NONE }, /* Chinese Sign Language != Church Slavonic */ + {HB_TAG('c','s','o',' '), HB_TAG('C','C','H','N')}, /* Sochiapam Chinantec -> Chinantec */ + {HB_TAG('c','s','p',' '), HB_TAG('Z','H','S',' ')}, /* Southern Ping Chinese -> Chinese, Simplified */ + {HB_TAG('c','s','v',' '), HB_TAG('Q','I','N',' ')}, /* Sumtu Chin -> Chin */ + {HB_TAG('c','s','w',' '), HB_TAG('N','C','R',' ')}, /* Swampy Cree -> N-Cree */ + {HB_TAG('c','s','w',' '), HB_TAG('N','H','C',' ')}, /* Swampy Cree -> Norway House Cree */ + {HB_TAG('c','s','w',' '), HB_TAG('C','R','E',' ')}, /* Swampy Cree -> Cree */ + {HB_TAG('c','s','y',' '), HB_TAG('Q','I','N',' ')}, /* Siyin Chin -> Chin */ + {HB_TAG('c','t','c',' '), HB_TAG('A','T','H',' ')}, /* Chetco -> Athapaskan */ + {HB_TAG('c','t','d',' '), HB_TAG('Q','I','N',' ')}, /* Tedim Chin -> Chin */ + {HB_TAG('c','t','e',' '), HB_TAG('C','C','H','N')}, /* Tepinapa Chinantec -> Chinantec */ +/*{HB_TAG('c','t','g',' '), HB_TAG('C','T','G',' ')},*/ /* Chittagonian */ + {HB_TAG('c','t','h',' '), HB_TAG('Q','I','N',' ')}, /* Thaiphum Chin -> Chin */ + {HB_TAG('c','t','l',' '), HB_TAG('C','C','H','N')}, /* Tlacoatzintepec Chinantec -> Chinantec */ + {HB_TAG('c','t','s',' '), HB_TAG('B','I','K',' ')}, /* Northern Catanduanes Bikol -> Bikol */ +/*{HB_TAG('c','t','t',' '), HB_TAG('C','T','T',' ')},*/ /* Wayanad Chetti */ + {HB_TAG('c','t','u',' '), HB_TAG('M','Y','N',' ')}, /* Chol -> Mayan */ + {HB_TAG('c','u','c',' '), HB_TAG('C','C','H','N')}, /* Usila Chinantec -> Chinantec */ +/*{HB_TAG('c','u','k',' '), HB_TAG('C','U','K',' ')},*/ /* San Blas Kuna */ + {HB_TAG('c','v','n',' '), HB_TAG('C','C','H','N')}, /* Valle Nacional Chinantec -> Chinantec */ + {HB_TAG('c','w','d',' '), HB_TAG('D','C','R',' ')}, /* Woods Cree */ + {HB_TAG('c','w','d',' '), HB_TAG('T','C','R',' ')}, /* Woods Cree -> TH-Cree */ + {HB_TAG('c','w','d',' '), HB_TAG('C','R','E',' ')}, /* Woods Cree -> Cree */ + {HB_TAG('c','z','h',' '), HB_TAG('Z','H','S',' ')}, /* Huizhou Chinese -> Chinese, Simplified */ + {HB_TAG('c','z','o',' '), HB_TAG('Z','H','S',' ')}, /* Min Zhong Chinese -> Chinese, Simplified */ + {HB_TAG('c','z','t',' '), HB_TAG('Q','I','N',' ')}, /* Zotung Chin -> Chin */ +/*{HB_TAG('d','a','g',' '), HB_TAG('D','A','G',' ')},*/ /* Dagbani */ + {HB_TAG('d','a','o',' '), HB_TAG('Q','I','N',' ')}, /* Daai Chin -> Chin */ + {HB_TAG('d','a','p',' '), HB_TAG('N','I','S',' ')}, /* Nisi (India) (retired code) */ +/*{HB_TAG('d','a','r',' '), HB_TAG('D','A','R',' ')},*/ /* Dargwa */ +/*{HB_TAG('d','a','x',' '), HB_TAG('D','A','X',' ')},*/ /* Dayi */ + {HB_TAG('d','c','r',' '), HB_TAG('C','P','P',' ')}, /* Negerhollands -> Creoles */ + {HB_TAG('d','e','n',' '), HB_TAG('S','L','A',' ')}, /* Slave (Athapascan) [macrolanguage] -> Slavey */ + {HB_TAG('d','e','n',' '), HB_TAG('A','T','H',' ')}, /* Slave (Athapascan) [macrolanguage] -> Athapaskan */ + {HB_TAG('d','e','p',' '), HB_TAG('C','P','P',' ')}, /* Pidgin Delaware -> Creoles */ + {HB_TAG('d','g','o',' '), HB_TAG('D','G','O',' ')}, /* Dogri (individual language) */ + {HB_TAG('d','g','o',' '), HB_TAG('D','G','R',' ')}, /* Dogri (macrolanguage) */ + {HB_TAG('d','g','r',' '), HB_TAG('A','T','H',' ')}, /* Dogrib -> Athapaskan */ + {HB_TAG('d','h','d',' '), HB_TAG('M','A','W',' ')}, /* Dhundari -> Marwari */ +/*{HB_TAG('d','h','g',' '), HB_TAG('D','H','G',' ')},*/ /* Dhangu */ + {HB_TAG('d','h','v',' '), HB_TAG_NONE }, /* Dehu != Divehi (Dhivehi, Maldivian) (deprecated) */ + {HB_TAG('d','i','b',' '), HB_TAG('D','N','K',' ')}, /* South Central Dinka -> Dinka */ + {HB_TAG('d','i','k',' '), HB_TAG('D','N','K',' ')}, /* Southwestern Dinka -> Dinka */ + {HB_TAG('d','i','n',' '), HB_TAG('D','N','K',' ')}, /* Dinka [macrolanguage] */ + {HB_TAG('d','i','p',' '), HB_TAG('D','N','K',' ')}, /* Northeastern Dinka -> Dinka */ + {HB_TAG('d','i','q',' '), HB_TAG('D','I','Q',' ')}, /* Dimli */ + {HB_TAG('d','i','q',' '), HB_TAG('Z','Z','A',' ')}, /* Dimli -> Zazaki */ + {HB_TAG('d','i','w',' '), HB_TAG('D','N','K',' ')}, /* Northwestern Dinka -> Dinka */ + {HB_TAG('d','j','e',' '), HB_TAG('D','J','R',' ')}, /* Zarma */ + {HB_TAG('d','j','k',' '), HB_TAG('C','P','P',' ')}, /* Eastern Maroon Creole -> Creoles */ + {HB_TAG('d','j','r',' '), HB_TAG('D','J','R','0')}, /* Djambarrpuyngu */ + {HB_TAG('d','k','s',' '), HB_TAG('D','N','K',' ')}, /* Southeastern Dinka -> Dinka */ + {HB_TAG('d','n','g',' '), HB_TAG('D','U','N',' ')}, /* Dungan */ +/*{HB_TAG('d','n','j',' '), HB_TAG('D','N','J',' ')},*/ /* Dan */ + {HB_TAG('d','n','k',' '), HB_TAG_NONE }, /* Dengka != Dinka */ + {HB_TAG('d','o','i',' '), HB_TAG('D','G','R',' ')}, /* Dogri (macrolanguage) [macrolanguage] */ + {HB_TAG('d','r','h',' '), HB_TAG('M','N','G',' ')}, /* Darkhat (retired code) -> Mongolian */ + {HB_TAG('d','r','i',' '), HB_TAG_NONE }, /* C'Lela != Dari */ + {HB_TAG('d','r','w',' '), HB_TAG('D','R','I',' ')}, /* Darwazi (retired code) -> Dari */ + {HB_TAG('d','r','w',' '), HB_TAG('F','A','R',' ')}, /* Darwazi (retired code) -> Persian */ + {HB_TAG('d','s','b',' '), HB_TAG('L','S','B',' ')}, /* Lower Sorbian */ + {HB_TAG('d','t','y',' '), HB_TAG('N','E','P',' ')}, /* Dotyali -> Nepali */ +/*{HB_TAG('d','u','j',' '), HB_TAG('D','U','J',' ')},*/ /* Dhuwal (retired code) */ + {HB_TAG('d','u','n',' '), HB_TAG_NONE }, /* Dusun Deyah != Dungan */ + {HB_TAG('d','u','p',' '), HB_TAG('M','L','Y',' ')}, /* Duano -> Malay */ + {HB_TAG('d','w','k',' '), HB_TAG('K','U','I',' ')}, /* Dawik Kui -> Kui */ + {HB_TAG('d','w','u',' '), HB_TAG('D','U','J',' ')}, /* Dhuwal */ + {HB_TAG('d','w','y',' '), HB_TAG('D','U','J',' ')}, /* Dhuwaya -> Dhuwal */ + {HB_TAG('d','y','u',' '), HB_TAG('J','U','L',' ')}, /* Dyula -> Jula */ + {HB_TAG('d','z','n',' '), HB_TAG_NONE }, /* Dzando != Dzongkha */ + {HB_TAG('e','c','r',' '), HB_TAG_NONE }, /* Eteocretan != Eastern Cree */ +/*{HB_TAG('e','f','i',' '), HB_TAG('E','F','I',' ')},*/ /* Efik */ + {HB_TAG('e','k','k',' '), HB_TAG('E','T','I',' ')}, /* Standard Estonian -> Estonian */ + {HB_TAG('e','k','y',' '), HB_TAG('K','R','N',' ')}, /* Eastern Kayah -> Karen */ + {HB_TAG('e','m','k',' '), HB_TAG('E','M','K',' ')}, /* Eastern Maninkakan */ + {HB_TAG('e','m','k',' '), HB_TAG('M','N','K',' ')}, /* Eastern Maninkakan -> Maninka */ + {HB_TAG('e','m','y',' '), HB_TAG('M','Y','N',' ')}, /* Epigraphic Mayan -> Mayan */ + {HB_TAG('e','n','b',' '), HB_TAG('K','A','L',' ')}, /* Markweeta -> Kalenjin */ + {HB_TAG('e','n','f',' '), HB_TAG('F','N','E',' ')}, /* Forest Enets */ + {HB_TAG('e','n','h',' '), HB_TAG('T','N','E',' ')}, /* Tundra Enets */ + {HB_TAG('e','s','g',' '), HB_TAG('G','O','N',' ')}, /* Aheri Gondi -> Gondi */ + {HB_TAG('e','s','i',' '), HB_TAG('I','P','K',' ')}, /* North Alaskan Inupiatun -> Inupiat */ + {HB_TAG('e','s','k',' '), HB_TAG('I','P','K',' ')}, /* Northwest Alaska Inupiatun -> Inupiat */ +/*{HB_TAG('e','s','u',' '), HB_TAG('E','S','U',' ')},*/ /* Central Yupik */ + {HB_TAG('e','t','o',' '), HB_TAG('B','T','I',' ')}, /* Eton (Cameroon) -> Beti */ + {HB_TAG('e','u','q',' '), HB_TAG_NONE }, /* Basque [collection] != Basque */ + {HB_TAG('e','v','e',' '), HB_TAG('E','V','N',' ')}, /* Even */ + {HB_TAG('e','v','n',' '), HB_TAG('E','V','K',' ')}, /* Evenki */ + {HB_TAG('e','w','o',' '), HB_TAG('B','T','I',' ')}, /* Ewondo -> Beti */ + {HB_TAG('e','y','o',' '), HB_TAG('K','A','L',' ')}, /* Keiyo -> Kalenjin */ + {HB_TAG('f','a','b',' '), HB_TAG('C','P','P',' ')}, /* Fa d'Ambu -> Creoles */ + {HB_TAG('f','a','n',' '), HB_TAG('F','A','N','0')}, /* Fang (Equatorial Guinea) */ + {HB_TAG('f','a','n',' '), HB_TAG('B','T','I',' ')}, /* Fang (Equatorial Guinea) -> Beti */ + {HB_TAG('f','a','r',' '), HB_TAG_NONE }, /* Fataleka != Persian */ + {HB_TAG('f','a','t',' '), HB_TAG('F','A','T',' ')}, /* Fanti */ + {HB_TAG('f','a','t',' '), HB_TAG('A','K','A',' ')}, /* Fanti -> Akan */ + {HB_TAG('f','b','l',' '), HB_TAG('B','I','K',' ')}, /* West Albay Bikol -> Bikol */ + {HB_TAG('f','f','m',' '), HB_TAG('F','U','L',' ')}, /* Maasina Fulfulde -> Fulah */ + {HB_TAG('f','i','l',' '), HB_TAG('P','I','L',' ')}, /* Filipino */ + {HB_TAG('f','l','m',' '), HB_TAG('H','A','L',' ')}, /* Halam (Falam Chin) (retired code) */ + {HB_TAG('f','l','m',' '), HB_TAG('Q','I','N',' ')}, /* Falam Chin (retired code) -> Chin */ + {HB_TAG('f','m','p',' '), HB_TAG('F','M','P',' ')}, /* Fe’fe’ */ + {HB_TAG('f','m','p',' '), HB_TAG('B','M','L',' ')}, /* Fe'fe' -> Bamileke */ + {HB_TAG('f','n','g',' '), HB_TAG('C','P','P',' ')}, /* Fanagalo -> Creoles */ +/*{HB_TAG('f','o','n',' '), HB_TAG('F','O','N',' ')},*/ /* Fon */ + {HB_TAG('f','o','s',' '), HB_TAG_NONE }, /* Siraya != Faroese */ + {HB_TAG('f','p','e',' '), HB_TAG('C','P','P',' ')}, /* Fernando Po Creole English -> Creoles */ +/*{HB_TAG('f','r','c',' '), HB_TAG('F','R','C',' ')},*/ /* Cajun French */ +/*{HB_TAG('f','r','p',' '), HB_TAG('F','R','P',' ')},*/ /* Arpitan */ + {HB_TAG('f','u','b',' '), HB_TAG('F','U','L',' ')}, /* Adamawa Fulfulde -> Fulah */ + {HB_TAG('f','u','c',' '), HB_TAG('F','U','L',' ')}, /* Pulaar -> Fulah */ + {HB_TAG('f','u','e',' '), HB_TAG('F','U','L',' ')}, /* Borgu Fulfulde -> Fulah */ + {HB_TAG('f','u','f',' '), HB_TAG('F','T','A',' ')}, /* Pular -> Futa */ + {HB_TAG('f','u','f',' '), HB_TAG('F','U','L',' ')}, /* Pular -> Fulah */ + {HB_TAG('f','u','h',' '), HB_TAG('F','U','L',' ')}, /* Western Niger Fulfulde -> Fulah */ + {HB_TAG('f','u','i',' '), HB_TAG('F','U','L',' ')}, /* Bagirmi Fulfulde -> Fulah */ + {HB_TAG('f','u','q',' '), HB_TAG('F','U','L',' ')}, /* Central-Eastern Niger Fulfulde -> Fulah */ + {HB_TAG('f','u','r',' '), HB_TAG('F','R','L',' ')}, /* Friulian */ + {HB_TAG('f','u','v',' '), HB_TAG('F','U','V',' ')}, /* Nigerian Fulfulde */ + {HB_TAG('f','u','v',' '), HB_TAG('F','U','L',' ')}, /* Nigerian Fulfulde -> Fulah */ + {HB_TAG('g','a','a',' '), HB_TAG('G','A','D',' ')}, /* Ga */ + {HB_TAG('g','a','c',' '), HB_TAG('C','P','P',' ')}, /* Mixed Great Andamanese -> Creoles */ + {HB_TAG('g','a','d',' '), HB_TAG_NONE }, /* Gaddang != Ga */ + {HB_TAG('g','a','e',' '), HB_TAG_NONE }, /* Guarequena != Scottish Gaelic (Gaelic) */ +/*{HB_TAG('g','a','g',' '), HB_TAG('G','A','G',' ')},*/ /* Gagauz */ + {HB_TAG('g','a','l',' '), HB_TAG_NONE }, /* Galolen != Galician */ + {HB_TAG('g','a','n',' '), HB_TAG('Z','H','S',' ')}, /* Gan Chinese -> Chinese, Simplified */ + {HB_TAG('g','a','r',' '), HB_TAG_NONE }, /* Galeya != Garshuni */ + {HB_TAG('g','a','w',' '), HB_TAG_NONE }, /* Nobonob != Garhwali */ + {HB_TAG('g','a','x',' '), HB_TAG('O','R','O',' ')}, /* Borana-Arsi-Guji Oromo -> Oromo */ + {HB_TAG('g','a','z',' '), HB_TAG('O','R','O',' ')}, /* West Central Oromo -> Oromo */ + {HB_TAG('g','b','m',' '), HB_TAG('G','A','W',' ')}, /* Garhwali */ + {HB_TAG('g','c','e',' '), HB_TAG('A','T','H',' ')}, /* Galice -> Athapaskan */ + {HB_TAG('g','c','f',' '), HB_TAG('C','P','P',' ')}, /* Guadeloupean Creole French -> Creoles */ + {HB_TAG('g','c','l',' '), HB_TAG('C','P','P',' ')}, /* Grenadian Creole English -> Creoles */ + {HB_TAG('g','c','r',' '), HB_TAG('C','P','P',' ')}, /* Guianese Creole French -> Creoles */ + {HB_TAG('g','d','a',' '), HB_TAG('R','A','J',' ')}, /* Gade Lohar -> Rajasthani */ +/*{HB_TAG('g','e','z',' '), HB_TAG('G','E','Z',' ')},*/ /* Geez */ + {HB_TAG('g','g','o',' '), HB_TAG('G','O','N',' ')}, /* Southern Gondi (retired code) -> Gondi */ + {HB_TAG('g','h','a',' '), HB_TAG('B','B','R',' ')}, /* Ghadamès -> Berber */ + {HB_TAG('g','h','k',' '), HB_TAG('K','R','N',' ')}, /* Geko Karen -> Karen */ + {HB_TAG('g','h','o',' '), HB_TAG('B','B','R',' ')}, /* Ghomara -> Berber */ + {HB_TAG('g','i','b',' '), HB_TAG('C','P','P',' ')}, /* Gibanawa -> Creoles */ +/*{HB_TAG('g','i','h',' '), HB_TAG('G','I','H',' ')},*/ /* Githabul */ + {HB_TAG('g','i','l',' '), HB_TAG('G','I','L','0')}, /* Kiribati (Gilbertese) */ + {HB_TAG('g','j','u',' '), HB_TAG('R','A','J',' ')}, /* Gujari -> Rajasthani */ + {HB_TAG('g','k','p',' '), HB_TAG('G','K','P',' ')}, /* Guinea Kpelle -> Kpelle (Guinea) */ + {HB_TAG('g','k','p',' '), HB_TAG('K','P','L',' ')}, /* Guinea Kpelle -> Kpelle */ + {HB_TAG('g','l','d',' '), HB_TAG('N','A','N',' ')}, /* Nanai */ +/*{HB_TAG('g','l','k',' '), HB_TAG('G','L','K',' ')},*/ /* Gilaki */ + {HB_TAG('g','m','z',' '), HB_TAG_NONE }, /* Mgbolizhia != Gumuz */ + {HB_TAG('g','n','b',' '), HB_TAG('Q','I','N',' ')}, /* Gangte -> Chin */ +/*{HB_TAG('g','n','n',' '), HB_TAG('G','N','N',' ')},*/ /* Gumatj */ + {HB_TAG('g','n','o',' '), HB_TAG('G','O','N',' ')}, /* Northern Gondi -> Gondi */ + {HB_TAG('g','n','w',' '), HB_TAG('G','U','A',' ')}, /* Western Bolivian Guaranà -> Guarani */ +/*{HB_TAG('g','o','g',' '), HB_TAG('G','O','G',' ')},*/ /* Gogo */ + {HB_TAG('g','o','m',' '), HB_TAG('K','O','K',' ')}, /* Goan Konkani -> Konkani */ +/*{HB_TAG('g','o','n',' '), HB_TAG('G','O','N',' ')},*/ /* Gondi [macrolanguage] */ + {HB_TAG('g','o','q',' '), HB_TAG('C','P','P',' ')}, /* Gorap -> Creoles */ + {HB_TAG('g','o','x',' '), HB_TAG('B','A','D','0')}, /* Gobu -> Banda */ + {HB_TAG('g','p','e',' '), HB_TAG('C','P','P',' ')}, /* Ghanaian Pidgin English -> Creoles */ + {HB_TAG('g','r','o',' '), HB_TAG_NONE }, /* Groma != Garo */ + {HB_TAG('g','r','r',' '), HB_TAG('B','B','R',' ')}, /* Taznatit -> Berber */ + {HB_TAG('g','r','t',' '), HB_TAG('G','R','O',' ')}, /* Garo */ + {HB_TAG('g','r','u',' '), HB_TAG('S','O','G',' ')}, /* Kistane -> Sodo Gurage */ + {HB_TAG('g','s','w',' '), HB_TAG('A','L','S',' ')}, /* Alsatian */ + {HB_TAG('g','u','a',' '), HB_TAG_NONE }, /* Shiki != Guarani */ +/*{HB_TAG('g','u','c',' '), HB_TAG('G','U','C',' ')},*/ /* Wayuu */ +/*{HB_TAG('g','u','f',' '), HB_TAG('G','U','F',' ')},*/ /* Gupapuyngu */ + {HB_TAG('g','u','g',' '), HB_TAG('G','U','A',' ')}, /* Paraguayan Guaranà -> Guarani */ + {HB_TAG('g','u','i',' '), HB_TAG('G','U','A',' ')}, /* Eastern Bolivian Guaranà -> Guarani */ + {HB_TAG('g','u','k',' '), HB_TAG('G','M','Z',' ')}, /* Gumuz */ + {HB_TAG('g','u','l',' '), HB_TAG('C','P','P',' ')}, /* Sea Island Creole English -> Creoles */ + {HB_TAG('g','u','n',' '), HB_TAG('G','U','A',' ')}, /* Mbyá Guaranà -> Guarani */ +/*{HB_TAG('g','u','z',' '), HB_TAG('G','U','Z',' ')},*/ /* Gusii */ + {HB_TAG('g','w','i',' '), HB_TAG('A','T','H',' ')}, /* Gwichʼin -> Athapaskan */ + {HB_TAG('g','y','n',' '), HB_TAG('C','P','P',' ')}, /* Guyanese Creole English -> Creoles */ + {HB_TAG('h','a','a',' '), HB_TAG('A','T','H',' ')}, /* Han -> Athapaskan */ + {HB_TAG('h','a','e',' '), HB_TAG('O','R','O',' ')}, /* Eastern Oromo -> Oromo */ + {HB_TAG('h','a','i',' '), HB_TAG('H','A','I','0')}, /* Haida [macrolanguage] */ + {HB_TAG('h','a','k',' '), HB_TAG('Z','H','S',' ')}, /* Hakka Chinese -> Chinese, Simplified */ + {HB_TAG('h','a','l',' '), HB_TAG_NONE }, /* Halang != Halam (Falam Chin) */ + {HB_TAG('h','a','r',' '), HB_TAG('H','R','I',' ')}, /* Harari */ +/*{HB_TAG('h','a','w',' '), HB_TAG('H','A','W',' ')},*/ /* Hawaiian */ + {HB_TAG('h','a','x',' '), HB_TAG('H','A','I','0')}, /* Southern Haida -> Haida */ +/*{HB_TAG('h','a','y',' '), HB_TAG('H','A','Y',' ')},*/ /* Haya */ +/*{HB_TAG('h','a','z',' '), HB_TAG('H','A','Z',' ')},*/ /* Hazaragi */ + {HB_TAG('h','b','n',' '), HB_TAG_NONE }, /* Heiban != Hammer-Banna */ + {HB_TAG('h','c','a',' '), HB_TAG('C','P','P',' ')}, /* Andaman Creole Hindi -> Creoles */ + {HB_TAG('h','d','n',' '), HB_TAG('H','A','I','0')}, /* Northern Haida -> Haida */ + {HB_TAG('h','e','a',' '), HB_TAG('H','M','N',' ')}, /* Northern Qiandong Miao -> Hmong */ +/*{HB_TAG('h','e','i',' '), HB_TAG('H','E','I',' ')},*/ /* Heiltsuk */ +/*{HB_TAG('h','i','l',' '), HB_TAG('H','I','L',' ')},*/ /* Hiligaynon */ + {HB_TAG('h','j','i',' '), HB_TAG('M','L','Y',' ')}, /* Haji -> Malay */ + {HB_TAG('h','l','t',' '), HB_TAG('Q','I','N',' ')}, /* Matu Chin -> Chin */ + {HB_TAG('h','m','a',' '), HB_TAG('H','M','N',' ')}, /* Southern Mashan Hmong -> Hmong */ + {HB_TAG('h','m','c',' '), HB_TAG('H','M','N',' ')}, /* Central Huishui Hmong -> Hmong */ + {HB_TAG('h','m','d',' '), HB_TAG('H','M','D',' ')}, /* Large Flowery Miao -> A-Hmao */ + {HB_TAG('h','m','d',' '), HB_TAG('H','M','N',' ')}, /* Large Flowery Miao -> Hmong */ + {HB_TAG('h','m','e',' '), HB_TAG('H','M','N',' ')}, /* Eastern Huishui Hmong -> Hmong */ + {HB_TAG('h','m','g',' '), HB_TAG('H','M','N',' ')}, /* Southwestern Guiyang Hmong -> Hmong */ + {HB_TAG('h','m','h',' '), HB_TAG('H','M','N',' ')}, /* Southwestern Huishui Hmong -> Hmong */ + {HB_TAG('h','m','i',' '), HB_TAG('H','M','N',' ')}, /* Northern Huishui Hmong -> Hmong */ + {HB_TAG('h','m','j',' '), HB_TAG('H','M','N',' ')}, /* Ge -> Hmong */ + {HB_TAG('h','m','l',' '), HB_TAG('H','M','N',' ')}, /* Luopohe Hmong -> Hmong */ + {HB_TAG('h','m','m',' '), HB_TAG('H','M','N',' ')}, /* Central Mashan Hmong -> Hmong */ +/*{HB_TAG('h','m','n',' '), HB_TAG('H','M','N',' ')},*/ /* Hmong [macrolanguage] */ + {HB_TAG('h','m','p',' '), HB_TAG('H','M','N',' ')}, /* Northern Mashan Hmong -> Hmong */ + {HB_TAG('h','m','q',' '), HB_TAG('H','M','N',' ')}, /* Eastern Qiandong Miao -> Hmong */ + {HB_TAG('h','m','r',' '), HB_TAG('Q','I','N',' ')}, /* Hmar -> Chin */ + {HB_TAG('h','m','s',' '), HB_TAG('H','M','N',' ')}, /* Southern Qiandong Miao -> Hmong */ + {HB_TAG('h','m','w',' '), HB_TAG('H','M','N',' ')}, /* Western Mashan Hmong -> Hmong */ + {HB_TAG('h','m','y',' '), HB_TAG('H','M','N',' ')}, /* Southern Guiyang Hmong -> Hmong */ + {HB_TAG('h','m','z',' '), HB_TAG('H','M','Z',' ')}, /* Hmong Shua -> Hmong Shuat */ + {HB_TAG('h','m','z',' '), HB_TAG('H','M','N',' ')}, /* Hmong Shua -> Hmong */ +/*{HB_TAG('h','n','d',' '), HB_TAG('H','N','D',' ')},*/ /* Southern Hindko -> Hindko */ + {HB_TAG('h','n','e',' '), HB_TAG('C','H','H',' ')}, /* Chhattisgarhi -> Chattisgarhi */ + {HB_TAG('h','n','j',' '), HB_TAG('H','M','N',' ')}, /* Hmong Njua -> Hmong */ + {HB_TAG('h','n','o',' '), HB_TAG('H','N','D',' ')}, /* Northern Hindko -> Hindko */ + {HB_TAG('h','o','c',' '), HB_TAG('H','O',' ',' ')}, /* Ho */ + {HB_TAG('h','o','i',' '), HB_TAG('A','T','H',' ')}, /* Holikachuk -> Athapaskan */ + {HB_TAG('h','o','j',' '), HB_TAG('H','A','R',' ')}, /* Hadothi -> Harauti */ + {HB_TAG('h','o','j',' '), HB_TAG('R','A','J',' ')}, /* Hadothi -> Rajasthani */ + {HB_TAG('h','r','a',' '), HB_TAG('Q','I','N',' ')}, /* Hrangkhol -> Chin */ + {HB_TAG('h','r','m',' '), HB_TAG('H','M','N',' ')}, /* Horned Miao -> Hmong */ + {HB_TAG('h','s','b',' '), HB_TAG('U','S','B',' ')}, /* Upper Sorbian */ + {HB_TAG('h','s','n',' '), HB_TAG('Z','H','S',' ')}, /* Xiang Chinese -> Chinese, Simplified */ + {HB_TAG('h','u','j',' '), HB_TAG('H','M','N',' ')}, /* Northern Guiyang Hmong -> Hmong */ + {HB_TAG('h','u','p',' '), HB_TAG('A','T','H',' ')}, /* Hupa -> Athapaskan */ + {HB_TAG('h','u','s',' '), HB_TAG('M','Y','N',' ')}, /* Huastec -> Mayan */ + {HB_TAG('h','w','c',' '), HB_TAG('C','P','P',' ')}, /* Hawai'i Creole English -> Creoles */ + {HB_TAG('h','y','w',' '), HB_TAG('H','Y','E',' ')}, /* Western Armenian -> Armenian */ +/*{HB_TAG('i','b','a',' '), HB_TAG('I','B','A',' ')},*/ /* Iban */ +/*{HB_TAG('i','b','b',' '), HB_TAG('I','B','B',' ')},*/ /* Ibibio */ + {HB_TAG('i','b','y',' '), HB_TAG('I','J','O',' ')}, /* Ibani -> Ijo */ + {HB_TAG('i','c','r',' '), HB_TAG('C','P','P',' ')}, /* Islander Creole English -> Creoles */ + {HB_TAG('i','d','a',' '), HB_TAG('L','U','H',' ')}, /* Idakho-Isukha-Tiriki -> Luyia */ + {HB_TAG('i','d','b',' '), HB_TAG('C','P','P',' ')}, /* Indo-Portuguese -> Creoles */ + {HB_TAG('i','g','b',' '), HB_TAG('E','B','I',' ')}, /* Ebira */ + {HB_TAG('i','h','b',' '), HB_TAG('C','P','P',' ')}, /* Iha Based Pidgin -> Creoles */ + {HB_TAG('i','j','c',' '), HB_TAG('I','J','O',' ')}, /* Izon -> Ijo */ + {HB_TAG('i','j','e',' '), HB_TAG('I','J','O',' ')}, /* Biseni -> Ijo */ + {HB_TAG('i','j','n',' '), HB_TAG('I','J','O',' ')}, /* Kalabari -> Ijo */ +/*{HB_TAG('i','j','o',' '), HB_TAG('I','J','O',' ')},*/ /* Ijo [collection] */ + {HB_TAG('i','j','s',' '), HB_TAG('I','J','O',' ')}, /* Southeast Ijo -> Ijo */ + {HB_TAG('i','k','e',' '), HB_TAG('I','N','U',' ')}, /* Eastern Canadian Inuktitut -> Inuktitut */ + {HB_TAG('i','k','e',' '), HB_TAG('I','N','U','K')}, /* Eastern Canadian Inuktitut -> Nunavik Inuktitut */ + {HB_TAG('i','k','t',' '), HB_TAG('I','N','U',' ')}, /* Inuinnaqtun -> Inuktitut */ +/*{HB_TAG('i','l','o',' '), HB_TAG('I','L','O',' ')},*/ /* Iloko -> Ilokano */ + {HB_TAG('i','n','g',' '), HB_TAG('A','T','H',' ')}, /* Degexit'an -> Athapaskan */ + {HB_TAG('i','n','h',' '), HB_TAG('I','N','G',' ')}, /* Ingush */ + {HB_TAG('i','r','i',' '), HB_TAG_NONE }, /* Rigwe != Irish */ +/*{HB_TAG('i','r','u',' '), HB_TAG('I','R','U',' ')},*/ /* Irula */ + {HB_TAG('i','s','m',' '), HB_TAG_NONE }, /* Masimasi != Inari Sami */ + {HB_TAG('i','t','z',' '), HB_TAG('M','Y','N',' ')}, /* Itzá -> Mayan */ + {HB_TAG('i','x','l',' '), HB_TAG('M','Y','N',' ')}, /* Ixil -> Mayan */ + {HB_TAG('j','a','c',' '), HB_TAG('M','Y','N',' ')}, /* Popti' -> Mayan */ + {HB_TAG('j','a','k',' '), HB_TAG('M','L','Y',' ')}, /* Jakun -> Malay */ + {HB_TAG('j','a','m',' '), HB_TAG('J','A','M',' ')}, /* Jamaican Creole English -> Jamaican Creole */ + {HB_TAG('j','a','m',' '), HB_TAG('C','P','P',' ')}, /* Jamaican Creole English -> Creoles */ + {HB_TAG('j','a','n',' '), HB_TAG_NONE }, /* Jandai != Japanese */ + {HB_TAG('j','a','x',' '), HB_TAG('M','L','Y',' ')}, /* Jambi Malay -> Malay */ + {HB_TAG('j','b','e',' '), HB_TAG('B','B','R',' ')}, /* Judeo-Berber -> Berber */ + {HB_TAG('j','b','n',' '), HB_TAG('B','B','R',' ')}, /* Nafusi -> Berber */ +/*{HB_TAG('j','b','o',' '), HB_TAG('J','B','O',' ')},*/ /* Lojban */ +/*{HB_TAG('j','c','t',' '), HB_TAG('J','C','T',' ')},*/ /* Krymchak */ + {HB_TAG('j','g','o',' '), HB_TAG('B','M','L',' ')}, /* Ngomba -> Bamileke */ + {HB_TAG('j','i','i',' '), HB_TAG_NONE }, /* Jiiddu != Yiddish */ + {HB_TAG('j','k','m',' '), HB_TAG('K','R','N',' ')}, /* Mobwa Karen -> Karen */ + {HB_TAG('j','k','p',' '), HB_TAG('K','R','N',' ')}, /* Paku Karen -> Karen */ + {HB_TAG('j','u','d',' '), HB_TAG_NONE }, /* Worodougou != Ladino */ + {HB_TAG('j','u','l',' '), HB_TAG_NONE }, /* Jirel != Jula */ + {HB_TAG('j','v','d',' '), HB_TAG('C','P','P',' ')}, /* Javindo -> Creoles */ + {HB_TAG('k','a','a',' '), HB_TAG('K','R','K',' ')}, /* Karakalpak */ + {HB_TAG('k','a','b',' '), HB_TAG('K','A','B','0')}, /* Kabyle */ + {HB_TAG('k','a','b',' '), HB_TAG('B','B','R',' ')}, /* Kabyle -> Berber */ + {HB_TAG('k','a','c',' '), HB_TAG_NONE }, /* Kachin != Kachchi */ + {HB_TAG('k','a','m',' '), HB_TAG('K','M','B',' ')}, /* Kamba (Kenya) */ + {HB_TAG('k','a','r',' '), HB_TAG('K','R','N',' ')}, /* Karen [collection] */ +/*{HB_TAG('k','a','w',' '), HB_TAG('K','A','W',' ')},*/ /* Kawi (Old Javanese) */ + {HB_TAG('k','b','d',' '), HB_TAG('K','A','B',' ')}, /* Kabardian */ + {HB_TAG('k','b','y',' '), HB_TAG('K','N','R',' ')}, /* Manga Kanuri -> Kanuri */ + {HB_TAG('k','c','a',' '), HB_TAG('K','H','K',' ')}, /* Khanty -> Khanty-Kazim */ + {HB_TAG('k','c','a',' '), HB_TAG('K','H','S',' ')}, /* Khanty -> Khanty-Shurishkar */ + {HB_TAG('k','c','a',' '), HB_TAG('K','H','V',' ')}, /* Khanty -> Khanty-Vakhi */ + {HB_TAG('k','c','n',' '), HB_TAG('C','P','P',' ')}, /* Nubi -> Creoles */ +/*{HB_TAG('k','d','e',' '), HB_TAG('K','D','E',' ')},*/ /* Makonde */ + {HB_TAG('k','d','r',' '), HB_TAG('K','R','M',' ')}, /* Karaim */ + {HB_TAG('k','d','t',' '), HB_TAG('K','U','Y',' ')}, /* Kuy */ + {HB_TAG('k','e','a',' '), HB_TAG('K','E','A',' ')}, /* Kabuverdianu (Crioulo) */ + {HB_TAG('k','e','a',' '), HB_TAG('C','P','P',' ')}, /* Kabuverdianu -> Creoles */ + {HB_TAG('k','e','b',' '), HB_TAG_NONE }, /* Kélé != Kebena */ + {HB_TAG('k','e','k',' '), HB_TAG('K','E','K',' ')}, /* Kekchi */ + {HB_TAG('k','e','k',' '), HB_TAG('M','Y','N',' ')}, /* Kekchà -> Mayan */ + {HB_TAG('k','e','x',' '), HB_TAG('K','K','N',' ')}, /* Kukna -> Kokni */ + {HB_TAG('k','f','a',' '), HB_TAG('K','O','D',' ')}, /* Kodava -> Kodagu */ + {HB_TAG('k','f','r',' '), HB_TAG('K','A','C',' ')}, /* Kachhi -> Kachchi */ + {HB_TAG('k','f','x',' '), HB_TAG('K','U','L',' ')}, /* Kullu Pahari -> Kulvi */ + {HB_TAG('k','f','y',' '), HB_TAG('K','M','N',' ')}, /* Kumaoni */ + {HB_TAG('k','g','e',' '), HB_TAG_NONE }, /* Komering != Khutsuri Georgian */ + {HB_TAG('k','h','a',' '), HB_TAG('K','S','I',' ')}, /* Khasi */ + {HB_TAG('k','h','b',' '), HB_TAG('X','B','D',' ')}, /* Lü */ + {HB_TAG('k','h','k',' '), HB_TAG('M','N','G',' ')}, /* Halh Mongolian -> Mongolian */ + {HB_TAG('k','h','n',' '), HB_TAG_NONE }, /* Khandesi != Khamti Shan (Microsoft fonts) */ + {HB_TAG('k','h','s',' '), HB_TAG_NONE }, /* Kasua != Khanty-Shurishkar */ + {HB_TAG('k','h','t',' '), HB_TAG('K','H','T',' ')}, /* Khamti -> Khamti Shan */ + {HB_TAG('k','h','t',' '), HB_TAG('K','H','N',' ')}, /* Khamti -> Khamti Shan (Microsoft fonts) */ + {HB_TAG('k','h','v',' '), HB_TAG_NONE }, /* Khvarshi != Khanty-Vakhi */ +/*{HB_TAG('k','h','w',' '), HB_TAG('K','H','W',' ')},*/ /* Khowar */ + {HB_TAG('k','i','s',' '), HB_TAG_NONE }, /* Kis != Kisii */ + {HB_TAG('k','i','u',' '), HB_TAG('K','I','U',' ')}, /* Kirmanjki */ + {HB_TAG('k','i','u',' '), HB_TAG('Z','Z','A',' ')}, /* Kirmanjki -> Zazaki */ + {HB_TAG('k','j','b',' '), HB_TAG('M','Y','N',' ')}, /* Q'anjob'al -> Mayan */ +/*{HB_TAG('k','j','d',' '), HB_TAG('K','J','D',' ')},*/ /* Southern Kiwai */ + {HB_TAG('k','j','h',' '), HB_TAG('K','H','A',' ')}, /* Khakas -> Khakass */ + {HB_TAG('k','j','p',' '), HB_TAG('K','J','P',' ')}, /* Pwo Eastern Karen -> Eastern Pwo Karen */ + {HB_TAG('k','j','p',' '), HB_TAG('K','R','N',' ')}, /* Pwo Eastern Karen -> Karen */ + {HB_TAG('k','j','t',' '), HB_TAG('K','R','N',' ')}, /* Phrae Pwo Karen -> Karen */ +/*{HB_TAG('k','j','z',' '), HB_TAG('K','J','Z',' ')},*/ /* Bumthangkha */ + {HB_TAG('k','k','n',' '), HB_TAG_NONE }, /* Kon Keu != Kokni */ + {HB_TAG('k','k','z',' '), HB_TAG('A','T','H',' ')}, /* Kaska -> Athapaskan */ + {HB_TAG('k','l','m',' '), HB_TAG_NONE }, /* Migum != Kalmyk */ + {HB_TAG('k','l','n',' '), HB_TAG('K','A','L',' ')}, /* Kalenjin [macrolanguage] */ + {HB_TAG('k','m','b',' '), HB_TAG('M','B','N',' ')}, /* Kimbundu -> Mbundu */ + {HB_TAG('k','m','n',' '), HB_TAG_NONE }, /* Awtuw != Kumaoni */ + {HB_TAG('k','m','o',' '), HB_TAG_NONE }, /* Kwoma != Komo */ + {HB_TAG('k','m','r',' '), HB_TAG('K','U','R',' ')}, /* Northern Kurdish -> Kurdish */ + {HB_TAG('k','m','s',' '), HB_TAG_NONE }, /* Kamasau != Komso */ + {HB_TAG('k','m','v',' '), HB_TAG('C','P','P',' ')}, /* Karipúna Creole French -> Creoles */ + {HB_TAG('k','m','w',' '), HB_TAG('K','M','O',' ')}, /* Komo (Democratic Republic of Congo) */ +/*{HB_TAG('k','m','z',' '), HB_TAG('K','M','Z',' ')},*/ /* Khorasani Turkish -> Khorasani Turkic */ + {HB_TAG('k','n','c',' '), HB_TAG('K','N','R',' ')}, /* Central Kanuri -> Kanuri */ + {HB_TAG('k','n','g',' '), HB_TAG('K','O','N','0')}, /* Koongo -> Kongo */ + {HB_TAG('k','n','j',' '), HB_TAG('M','Y','N',' ')}, /* Western Kanjobal -> Mayan */ + {HB_TAG('k','n','n',' '), HB_TAG('K','O','K',' ')}, /* Konkani */ + {HB_TAG('k','n','r',' '), HB_TAG_NONE }, /* Kaningra != Kanuri */ + {HB_TAG('k','o','d',' '), HB_TAG_NONE }, /* Kodi != Kodagu */ + {HB_TAG('k','o','h',' '), HB_TAG_NONE }, /* Koyo != Korean Old Hangul */ + {HB_TAG('k','o','i',' '), HB_TAG('K','O','P',' ')}, /* Komi-Permyak */ + {HB_TAG('k','o','i',' '), HB_TAG('K','O','M',' ')}, /* Komi-Permyak -> Komi */ +/*{HB_TAG('k','o','k',' '), HB_TAG('K','O','K',' ')},*/ /* Konkani [macrolanguage] */ + {HB_TAG('k','o','p',' '), HB_TAG_NONE }, /* Waube != Komi-Permyak */ +/*{HB_TAG('k','o','s',' '), HB_TAG('K','O','S',' ')},*/ /* Kosraean */ + {HB_TAG('k','o','y',' '), HB_TAG('A','T','H',' ')}, /* Koyukon -> Athapaskan */ + {HB_TAG('k','o','z',' '), HB_TAG_NONE }, /* Korak != Komi-Zyrian */ + {HB_TAG('k','p','e',' '), HB_TAG('K','P','L',' ')}, /* Kpelle [macrolanguage] */ + {HB_TAG('k','p','l',' '), HB_TAG_NONE }, /* Kpala != Kpelle */ + {HB_TAG('k','p','p',' '), HB_TAG('K','R','N',' ')}, /* Paku Karen (retired code) -> Karen */ + {HB_TAG('k','p','v',' '), HB_TAG('K','O','Z',' ')}, /* Komi-Zyrian */ + {HB_TAG('k','p','v',' '), HB_TAG('K','O','M',' ')}, /* Komi-Zyrian -> Komi */ + {HB_TAG('k','p','y',' '), HB_TAG('K','Y','K',' ')}, /* Koryak */ + {HB_TAG('k','q','s',' '), HB_TAG('K','I','S',' ')}, /* Northern Kissi -> Kisii */ + {HB_TAG('k','q','y',' '), HB_TAG('K','R','T',' ')}, /* Koorete */ + {HB_TAG('k','r','c',' '), HB_TAG('K','A','R',' ')}, /* Karachay-Balkar -> Karachay */ + {HB_TAG('k','r','c',' '), HB_TAG('B','A','L',' ')}, /* Karachay-Balkar -> Balkar */ + {HB_TAG('k','r','i',' '), HB_TAG('K','R','I',' ')}, /* Krio */ + {HB_TAG('k','r','i',' '), HB_TAG('C','P','P',' ')}, /* Krio -> Creoles */ + {HB_TAG('k','r','k',' '), HB_TAG_NONE }, /* Kerek != Karakalpak */ +/*{HB_TAG('k','r','l',' '), HB_TAG('K','R','L',' ')},*/ /* Karelian */ + {HB_TAG('k','r','m',' '), HB_TAG_NONE }, /* Krim (retired code) != Karaim */ + {HB_TAG('k','r','n',' '), HB_TAG_NONE }, /* Sapo != Karen */ + {HB_TAG('k','r','t',' '), HB_TAG('K','N','R',' ')}, /* Tumari Kanuri -> Kanuri */ + {HB_TAG('k','r','u',' '), HB_TAG('K','U','U',' ')}, /* Kurukh */ + {HB_TAG('k','s','h',' '), HB_TAG('K','S','H','0')}, /* Kölsch -> Ripuarian */ + {HB_TAG('k','s','i',' '), HB_TAG_NONE }, /* Krisa != Khasi */ + {HB_TAG('k','s','m',' '), HB_TAG_NONE }, /* Kumba != Kildin Sami */ + {HB_TAG('k','s','s',' '), HB_TAG('K','I','S',' ')}, /* Southern Kisi -> Kisii */ + {HB_TAG('k','s','w',' '), HB_TAG('K','S','W',' ')}, /* S’gaw Karen */ + {HB_TAG('k','s','w',' '), HB_TAG('K','R','N',' ')}, /* S'gaw Karen -> Karen */ + {HB_TAG('k','t','b',' '), HB_TAG('K','E','B',' ')}, /* Kambaata -> Kebena */ + {HB_TAG('k','t','u',' '), HB_TAG('K','O','N',' ')}, /* Kituba (Democratic Republic of Congo) -> Kikongo */ + {HB_TAG('k','t','w',' '), HB_TAG('A','T','H',' ')}, /* Kato -> Athapaskan */ + {HB_TAG('k','u','i',' '), HB_TAG_NONE }, /* Kuikúro-Kalapálo != Kui */ + {HB_TAG('k','u','l',' '), HB_TAG_NONE }, /* Kulere != Kulvi */ +/*{HB_TAG('k','u','m',' '), HB_TAG('K','U','M',' ')},*/ /* Kumyk */ + {HB_TAG('k','u','u',' '), HB_TAG('A','T','H',' ')}, /* Upper Kuskokwim -> Athapaskan */ + {HB_TAG('k','u','w',' '), HB_TAG('B','A','D','0')}, /* Kpagua -> Banda */ + {HB_TAG('k','u','y',' '), HB_TAG_NONE }, /* Kuuku-Ya'u != Kuy */ + {HB_TAG('k','v','b',' '), HB_TAG('M','L','Y',' ')}, /* Kubu -> Malay */ + {HB_TAG('k','v','l',' '), HB_TAG('K','R','N',' ')}, /* Kayaw -> Karen */ + {HB_TAG('k','v','q',' '), HB_TAG('K','R','N',' ')}, /* Geba Karen -> Karen */ + {HB_TAG('k','v','r',' '), HB_TAG('M','L','Y',' ')}, /* Kerinci -> Malay */ + {HB_TAG('k','v','t',' '), HB_TAG('K','R','N',' ')}, /* Lahta Karen -> Karen */ + {HB_TAG('k','v','u',' '), HB_TAG('K','R','N',' ')}, /* Yinbaw Karen -> Karen */ + {HB_TAG('k','v','y',' '), HB_TAG('K','R','N',' ')}, /* Yintale Karen -> Karen */ +/*{HB_TAG('k','w','k',' '), HB_TAG('K','W','K',' ')},*/ /* Kwakiutl -> Kwakʼwala */ + {HB_TAG('k','w','w',' '), HB_TAG('C','P','P',' ')}, /* Kwinti -> Creoles */ + {HB_TAG('k','w','y',' '), HB_TAG('K','O','N','0')}, /* San Salvador Kongo -> Kongo */ + {HB_TAG('k','x','c',' '), HB_TAG('K','M','S',' ')}, /* Konso -> Komso */ + {HB_TAG('k','x','d',' '), HB_TAG('M','L','Y',' ')}, /* Brunei -> Malay */ + {HB_TAG('k','x','f',' '), HB_TAG('K','R','N',' ')}, /* Manumanaw Karen -> Karen */ + {HB_TAG('k','x','k',' '), HB_TAG('K','R','N',' ')}, /* Zayein Karen -> Karen */ + {HB_TAG('k','x','l',' '), HB_TAG('K','U','U',' ')}, /* Nepali Kurux (retired code) -> Kurukh */ + {HB_TAG('k','x','u',' '), HB_TAG('K','U','I',' ')}, /* Kui (India) (retired code) */ + {HB_TAG('k','y','k',' '), HB_TAG_NONE }, /* Kamayo != Koryak */ + {HB_TAG('k','y','u',' '), HB_TAG('K','Y','U',' ')}, /* Western Kayah */ + {HB_TAG('k','y','u',' '), HB_TAG('K','R','N',' ')}, /* Western Kayah -> Karen */ + {HB_TAG('l','a','c',' '), HB_TAG('M','Y','N',' ')}, /* Lacandon -> Mayan */ + {HB_TAG('l','a','d',' '), HB_TAG('J','U','D',' ')}, /* Ladino */ + {HB_TAG('l','a','h',' '), HB_TAG_NONE }, /* Lahnda [macrolanguage] != Lahuli */ + {HB_TAG('l','a','k',' '), HB_TAG_NONE }, /* Laka (Nigeria) (retired code) != Lak */ + {HB_TAG('l','a','m',' '), HB_TAG_NONE }, /* Lamba != Lambani */ + {HB_TAG('l','a','z',' '), HB_TAG_NONE }, /* Aribwatsa != Laz */ + {HB_TAG('l','b','e',' '), HB_TAG('L','A','K',' ')}, /* Lak */ + {HB_TAG('l','b','j',' '), HB_TAG('L','D','K',' ')}, /* Ladakhi */ + {HB_TAG('l','b','l',' '), HB_TAG('B','I','K',' ')}, /* Libon Bikol -> Bikol */ + {HB_TAG('l','c','e',' '), HB_TAG('M','L','Y',' ')}, /* Loncong -> Malay */ + {HB_TAG('l','c','f',' '), HB_TAG('M','L','Y',' ')}, /* Lubu -> Malay */ + {HB_TAG('l','d','i',' '), HB_TAG('K','O','N','0')}, /* Laari -> Kongo */ + {HB_TAG('l','d','k',' '), HB_TAG_NONE }, /* Leelau != Ladakhi */ +/*{HB_TAG('l','e','f',' '), HB_TAG('L','E','F',' ')},*/ /* Lelemi */ +/*{HB_TAG('l','e','z',' '), HB_TAG('L','E','Z',' ')},*/ /* Lezghian -> Lezgi */ + {HB_TAG('l','i','f',' '), HB_TAG('L','M','B',' ')}, /* Limbu */ +/*{HB_TAG('l','i','j',' '), HB_TAG('L','I','J',' ')},*/ /* Ligurian */ + {HB_TAG('l','i','r',' '), HB_TAG('C','P','P',' ')}, /* Liberian English -> Creoles */ +/*{HB_TAG('l','i','s',' '), HB_TAG('L','I','S',' ')},*/ /* Lisu */ + {HB_TAG('l','i','w',' '), HB_TAG('M','L','Y',' ')}, /* Col -> Malay */ + {HB_TAG('l','i','y',' '), HB_TAG('B','A','D','0')}, /* Banda-Bambari -> Banda */ +/*{HB_TAG('l','j','p',' '), HB_TAG('L','J','P',' ')},*/ /* Lampung Api -> Lampung */ + {HB_TAG('l','k','b',' '), HB_TAG('L','U','H',' ')}, /* Kabras -> Luyia */ +/*{HB_TAG('l','k','i',' '), HB_TAG('L','K','I',' ')},*/ /* Laki */ + {HB_TAG('l','k','o',' '), HB_TAG('L','U','H',' ')}, /* Khayo -> Luyia */ + {HB_TAG('l','k','s',' '), HB_TAG('L','U','H',' ')}, /* Kisa -> Luyia */ + {HB_TAG('l','l','d',' '), HB_TAG('L','A','D',' ')}, /* Ladin */ + {HB_TAG('l','m','a',' '), HB_TAG_NONE }, /* East Limba != Low Mari */ + {HB_TAG('l','m','b',' '), HB_TAG_NONE }, /* Merei != Limbu */ + {HB_TAG('l','m','n',' '), HB_TAG('L','A','M',' ')}, /* Lambadi -> Lambani */ +/*{HB_TAG('l','m','o',' '), HB_TAG('L','M','O',' ')},*/ /* Lombard */ + {HB_TAG('l','m','w',' '), HB_TAG_NONE }, /* Lake Miwok != Lomwe */ + {HB_TAG('l','n','a',' '), HB_TAG('B','A','D','0')}, /* Langbashe -> Banda */ + {HB_TAG('l','n','l',' '), HB_TAG('B','A','D','0')}, /* South Central Banda -> Banda */ +/*{HB_TAG('l','o','m',' '), HB_TAG('L','O','M',' ')},*/ /* Loma (Liberia) */ + {HB_TAG('l','o','u',' '), HB_TAG('C','P','P',' ')}, /* Louisiana Creole -> Creoles */ +/*{HB_TAG('l','p','o',' '), HB_TAG('L','P','O',' ')},*/ /* Lipo */ +/*{HB_TAG('l','r','c',' '), HB_TAG('L','R','C',' ')},*/ /* Northern Luri -> Luri */ + {HB_TAG('l','r','i',' '), HB_TAG('L','U','H',' ')}, /* Marachi -> Luyia */ + {HB_TAG('l','r','m',' '), HB_TAG('L','U','H',' ')}, /* Marama -> Luyia */ + {HB_TAG('l','r','t',' '), HB_TAG('C','P','P',' ')}, /* Larantuka Malay -> Creoles */ + {HB_TAG('l','s','b',' '), HB_TAG_NONE }, /* Burundian Sign Language != Lower Sorbian */ + {HB_TAG('l','s','m',' '), HB_TAG('L','U','H',' ')}, /* Saamia -> Luyia */ + {HB_TAG('l','t','g',' '), HB_TAG('L','V','I',' ')}, /* Latgalian -> Latvian */ + {HB_TAG('l','t','h',' '), HB_TAG_NONE }, /* Thur != Lithuanian */ + {HB_TAG('l','t','o',' '), HB_TAG('L','U','H',' ')}, /* Tsotso -> Luyia */ + {HB_TAG('l','t','s',' '), HB_TAG('L','U','H',' ')}, /* Tachoni -> Luyia */ +/*{HB_TAG('l','u','a',' '), HB_TAG('L','U','A',' ')},*/ /* Luba-Lulua */ +/*{HB_TAG('l','u','o',' '), HB_TAG('L','U','O',' ')},*/ /* Luo (Kenya and Tanzania) */ + {HB_TAG('l','u','s',' '), HB_TAG('M','I','Z',' ')}, /* Lushai -> Mizo */ + {HB_TAG('l','u','s',' '), HB_TAG('Q','I','N',' ')}, /* Lushai -> Chin */ + {HB_TAG('l','u','y',' '), HB_TAG('L','U','H',' ')}, /* Luyia [macrolanguage] */ + {HB_TAG('l','u','z',' '), HB_TAG('L','R','C',' ')}, /* Southern Luri -> Luri */ + {HB_TAG('l','v','i',' '), HB_TAG_NONE }, /* Lavi != Latvian */ + {HB_TAG('l','v','s',' '), HB_TAG('L','V','I',' ')}, /* Standard Latvian -> Latvian */ + {HB_TAG('l','w','g',' '), HB_TAG('L','U','H',' ')}, /* Wanga -> Luyia */ + {HB_TAG('l','z','h',' '), HB_TAG('Z','H','T',' ')}, /* Literary Chinese -> Chinese, Traditional */ + {HB_TAG('l','z','z',' '), HB_TAG('L','A','Z',' ')}, /* Laz */ +/*{HB_TAG('m','a','d',' '), HB_TAG('M','A','D',' ')},*/ /* Madurese -> Madura */ +/*{HB_TAG('m','a','g',' '), HB_TAG('M','A','G',' ')},*/ /* Magahi */ + {HB_TAG('m','a','i',' '), HB_TAG('M','T','H',' ')}, /* Maithili */ + {HB_TAG('m','a','j',' '), HB_TAG_NONE }, /* Jalapa De DÃaz Mazatec != Majang */ + {HB_TAG('m','a','k',' '), HB_TAG('M','K','R',' ')}, /* Makasar */ + {HB_TAG('m','a','m',' '), HB_TAG('M','A','M',' ')}, /* Mam */ + {HB_TAG('m','a','m',' '), HB_TAG('M','Y','N',' ')}, /* Mam -> Mayan */ + {HB_TAG('m','a','n',' '), HB_TAG('M','N','K',' ')}, /* Mandingo [macrolanguage] -> Maninka */ + {HB_TAG('m','a','p',' '), HB_TAG_NONE }, /* Austronesian [collection] != Mapudungun */ + {HB_TAG('m','a','w',' '), HB_TAG_NONE }, /* Mampruli != Marwari */ + {HB_TAG('m','a','x',' '), HB_TAG('M','L','Y',' ')}, /* North Moluccan Malay -> Malay */ + {HB_TAG('m','a','x',' '), HB_TAG('C','P','P',' ')}, /* North Moluccan Malay -> Creoles */ + {HB_TAG('m','b','f',' '), HB_TAG('C','P','P',' ')}, /* Baba Malay -> Creoles */ + {HB_TAG('m','b','n',' '), HB_TAG_NONE }, /* Macaguán != Mbundu */ +/*{HB_TAG('m','b','o',' '), HB_TAG('M','B','O',' ')},*/ /* Mbo (Cameroon) */ + {HB_TAG('m','c','h',' '), HB_TAG_NONE }, /* Maquiritari != Manchu */ + {HB_TAG('m','c','m',' '), HB_TAG('C','P','P',' ')}, /* Malaccan Creole Portuguese -> Creoles */ + {HB_TAG('m','c','r',' '), HB_TAG_NONE }, /* Menya != Moose Cree */ + {HB_TAG('m','c','t',' '), HB_TAG('B','T','I',' ')}, /* Mengisa -> Beti */ + {HB_TAG('m','d','e',' '), HB_TAG_NONE }, /* Maba (Chad) != Mende */ + {HB_TAG('m','d','f',' '), HB_TAG('M','O','K',' ')}, /* Moksha */ +/*{HB_TAG('m','d','r',' '), HB_TAG('M','D','R',' ')},*/ /* Mandar */ + {HB_TAG('m','d','y',' '), HB_TAG('M','L','E',' ')}, /* Male (Ethiopia) */ + {HB_TAG('m','e','n',' '), HB_TAG('M','D','E',' ')}, /* Mende (Sierra Leone) */ + {HB_TAG('m','e','o',' '), HB_TAG('M','L','Y',' ')}, /* Kedah Malay -> Malay */ +/*{HB_TAG('m','e','r',' '), HB_TAG('M','E','R',' ')},*/ /* Meru */ + {HB_TAG('m','f','a',' '), HB_TAG('M','F','A',' ')}, /* Pattani Malay */ + {HB_TAG('m','f','a',' '), HB_TAG('M','L','Y',' ')}, /* Pattani Malay -> Malay */ + {HB_TAG('m','f','b',' '), HB_TAG('M','L','Y',' ')}, /* Bangka -> Malay */ + {HB_TAG('m','f','e',' '), HB_TAG('M','F','E',' ')}, /* Morisyen */ + {HB_TAG('m','f','e',' '), HB_TAG('C','P','P',' ')}, /* Morisyen -> Creoles */ + {HB_TAG('m','f','p',' '), HB_TAG('C','P','P',' ')}, /* Makassar Malay -> Creoles */ + {HB_TAG('m','h','c',' '), HB_TAG('M','Y','N',' ')}, /* Mocho -> Mayan */ + {HB_TAG('m','h','r',' '), HB_TAG('L','M','A',' ')}, /* Eastern Mari -> Low Mari */ + {HB_TAG('m','h','v',' '), HB_TAG('A','R','K',' ')}, /* Arakanese (retired code) -> Rakhine */ + {HB_TAG('m','i','n',' '), HB_TAG('M','I','N',' ')}, /* Minangkabau */ + {HB_TAG('m','i','n',' '), HB_TAG('M','L','Y',' ')}, /* Minangkabau -> Malay */ + {HB_TAG('m','i','z',' '), HB_TAG_NONE }, /* Coatzospan Mixtec != Mizo */ + {HB_TAG('m','k','n',' '), HB_TAG('C','P','P',' ')}, /* Kupang Malay -> Creoles */ + {HB_TAG('m','k','r',' '), HB_TAG_NONE }, /* Malas != Makasar */ + {HB_TAG('m','k','u',' '), HB_TAG('M','N','K',' ')}, /* Konyanka Maninka -> Maninka */ +/*{HB_TAG('m','k','w',' '), HB_TAG('M','K','W',' ')},*/ /* Kituba (Congo) */ + {HB_TAG('m','l','e',' '), HB_TAG_NONE }, /* Manambu != Male */ + {HB_TAG('m','l','n',' '), HB_TAG_NONE }, /* Malango != Malinke */ + {HB_TAG('m','l','q',' '), HB_TAG('M','L','N',' ')}, /* Western Maninkakan -> Malinke */ + {HB_TAG('m','l','q',' '), HB_TAG('M','N','K',' ')}, /* Western Maninkakan -> Maninka */ + {HB_TAG('m','l','r',' '), HB_TAG_NONE }, /* Vame != Malayalam Reformed */ + {HB_TAG('m','m','r',' '), HB_TAG('H','M','N',' ')}, /* Western Xiangxi Miao -> Hmong */ + {HB_TAG('m','n','c',' '), HB_TAG('M','C','H',' ')}, /* Manchu */ + {HB_TAG('m','n','d',' '), HB_TAG_NONE }, /* Mondé != Mandinka */ + {HB_TAG('m','n','g',' '), HB_TAG_NONE }, /* Eastern Mnong != Mongolian */ + {HB_TAG('m','n','h',' '), HB_TAG('B','A','D','0')}, /* Mono (Democratic Republic of Congo) -> Banda */ +/*{HB_TAG('m','n','i',' '), HB_TAG('M','N','I',' ')},*/ /* Manipuri */ + {HB_TAG('m','n','k',' '), HB_TAG('M','N','D',' ')}, /* Mandinka */ + {HB_TAG('m','n','k',' '), HB_TAG('M','N','K',' ')}, /* Mandinka -> Maninka */ + {HB_TAG('m','n','p',' '), HB_TAG('Z','H','S',' ')}, /* Min Bei Chinese -> Chinese, Simplified */ + {HB_TAG('m','n','s',' '), HB_TAG('M','A','N',' ')}, /* Mansi */ + {HB_TAG('m','n','w',' '), HB_TAG('M','O','N',' ')}, /* Mon */ + {HB_TAG('m','n','w',' '), HB_TAG('M','O','N','T')}, /* Mon -> Thailand Mon */ + {HB_TAG('m','n','x',' '), HB_TAG_NONE }, /* Manikion != Manx */ + {HB_TAG('m','o','d',' '), HB_TAG('C','P','P',' ')}, /* Mobilian -> Creoles */ +/*{HB_TAG('m','o','h',' '), HB_TAG('M','O','H',' ')},*/ /* Mohawk */ + {HB_TAG('m','o','k',' '), HB_TAG_NONE }, /* Morori != Moksha */ + {HB_TAG('m','o','p',' '), HB_TAG('M','Y','N',' ')}, /* Mopán Maya -> Mayan */ + {HB_TAG('m','o','r',' '), HB_TAG_NONE }, /* Moro != Moroccan */ +/*{HB_TAG('m','o','s',' '), HB_TAG('M','O','S',' ')},*/ /* Mossi */ + {HB_TAG('m','p','e',' '), HB_TAG('M','A','J',' ')}, /* Majang */ + {HB_TAG('m','q','g',' '), HB_TAG('M','L','Y',' ')}, /* Kota Bangun Kutai Malay -> Malay */ + {HB_TAG('m','r','h',' '), HB_TAG('Q','I','N',' ')}, /* Mara Chin -> Chin */ + {HB_TAG('m','r','j',' '), HB_TAG('H','M','A',' ')}, /* Western Mari -> High Mari */ + {HB_TAG('m','s','c',' '), HB_TAG('M','N','K',' ')}, /* Sankaran Maninka -> Maninka */ + {HB_TAG('m','s','h',' '), HB_TAG('M','L','G',' ')}, /* Masikoro Malagasy -> Malagasy */ + {HB_TAG('m','s','i',' '), HB_TAG('M','L','Y',' ')}, /* Sabah Malay -> Malay */ + {HB_TAG('m','s','i',' '), HB_TAG('C','P','P',' ')}, /* Sabah Malay -> Creoles */ + {HB_TAG('m','t','h',' '), HB_TAG_NONE }, /* Munggui != Maithili */ + {HB_TAG('m','t','r',' '), HB_TAG('M','A','W',' ')}, /* Mewari -> Marwari */ + {HB_TAG('m','t','s',' '), HB_TAG_NONE }, /* Yora != Maltese */ + {HB_TAG('m','u','d',' '), HB_TAG('C','P','P',' ')}, /* Mednyj Aleut -> Creoles */ + {HB_TAG('m','u','i',' '), HB_TAG('M','L','Y',' ')}, /* Musi -> Malay */ + {HB_TAG('m','u','n',' '), HB_TAG_NONE }, /* Munda [collection] != Mundari */ + {HB_TAG('m','u','p',' '), HB_TAG('R','A','J',' ')}, /* Malvi -> Rajasthani */ + {HB_TAG('m','u','q',' '), HB_TAG('H','M','N',' ')}, /* Eastern Xiangxi Miao -> Hmong */ +/*{HB_TAG('m','u','s',' '), HB_TAG('M','U','S',' ')},*/ /* Creek -> Muscogee */ + {HB_TAG('m','v','b',' '), HB_TAG('A','T','H',' ')}, /* Mattole -> Athapaskan */ + {HB_TAG('m','v','e',' '), HB_TAG('M','A','W',' ')}, /* Marwari (Pakistan) */ + {HB_TAG('m','v','f',' '), HB_TAG('M','N','G',' ')}, /* Peripheral Mongolian -> Mongolian */ + {HB_TAG('m','w','k',' '), HB_TAG('M','N','K',' ')}, /* Kita Maninkakan -> Maninka */ +/*{HB_TAG('m','w','l',' '), HB_TAG('M','W','L',' ')},*/ /* Mirandese */ + {HB_TAG('m','w','q',' '), HB_TAG('Q','I','N',' ')}, /* Mün Chin -> Chin */ + {HB_TAG('m','w','r',' '), HB_TAG('M','A','W',' ')}, /* Marwari [macrolanguage] */ + {HB_TAG('m','w','w',' '), HB_TAG('M','W','W',' ')}, /* Hmong Daw */ + {HB_TAG('m','w','w',' '), HB_TAG('H','M','N',' ')}, /* Hmong Daw -> Hmong */ + {HB_TAG('m','y','m',' '), HB_TAG('M','E','N',' ')}, /* Me’en */ +/*{HB_TAG('m','y','n',' '), HB_TAG('M','Y','N',' ')},*/ /* Mayan [collection] */ + {HB_TAG('m','y','q',' '), HB_TAG('M','N','K',' ')}, /* Forest Maninka (retired code) -> Maninka */ + {HB_TAG('m','y','v',' '), HB_TAG('E','R','Z',' ')}, /* Erzya */ + {HB_TAG('m','z','b',' '), HB_TAG('B','B','R',' ')}, /* Tumzabt -> Berber */ +/*{HB_TAG('m','z','n',' '), HB_TAG('M','Z','N',' ')},*/ /* Mazanderani */ + {HB_TAG('m','z','s',' '), HB_TAG('C','P','P',' ')}, /* Macanese -> Creoles */ + {HB_TAG('n','a','g',' '), HB_TAG('N','A','G',' ')}, /* Naga Pidgin -> Naga-Assamese */ + {HB_TAG('n','a','g',' '), HB_TAG('C','P','P',' ')}, /* Naga Pidgin -> Creoles */ +/*{HB_TAG('n','a','h',' '), HB_TAG('N','A','H',' ')},*/ /* Nahuatl [collection] */ + {HB_TAG('n','a','n',' '), HB_TAG('Z','H','S',' ')}, /* Min Nan Chinese -> Chinese, Simplified */ +/*{HB_TAG('n','a','p',' '), HB_TAG('N','A','P',' ')},*/ /* Neapolitan */ + {HB_TAG('n','a','s',' '), HB_TAG_NONE }, /* Naasioi != Naskapi */ + {HB_TAG('n','a','z',' '), HB_TAG('N','A','H',' ')}, /* Coatepec Nahuatl -> Nahuatl */ + {HB_TAG('n','c','h',' '), HB_TAG('N','A','H',' ')}, /* Central Huasteca Nahuatl -> Nahuatl */ + {HB_TAG('n','c','i',' '), HB_TAG('N','A','H',' ')}, /* Classical Nahuatl -> Nahuatl */ + {HB_TAG('n','c','j',' '), HB_TAG('N','A','H',' ')}, /* Northern Puebla Nahuatl -> Nahuatl */ + {HB_TAG('n','c','l',' '), HB_TAG('N','A','H',' ')}, /* Michoacán Nahuatl -> Nahuatl */ + {HB_TAG('n','c','r',' '), HB_TAG_NONE }, /* Ncane != N-Cree */ + {HB_TAG('n','c','x',' '), HB_TAG('N','A','H',' ')}, /* Central Puebla Nahuatl -> Nahuatl */ + {HB_TAG('n','d','b',' '), HB_TAG_NONE }, /* Kenswei Nsei != Ndebele */ +/*{HB_TAG('n','d','c',' '), HB_TAG('N','D','C',' ')},*/ /* Ndau */ + {HB_TAG('n','d','g',' '), HB_TAG_NONE }, /* Ndengereko != Ndonga */ +/*{HB_TAG('n','d','s',' '), HB_TAG('N','D','S',' ')},*/ /* Low Saxon */ + {HB_TAG('n','e','f',' '), HB_TAG('C','P','P',' ')}, /* Nefamese -> Creoles */ +/*{HB_TAG('n','e','w',' '), HB_TAG('N','E','W',' ')},*/ /* Newari */ +/*{HB_TAG('n','g','a',' '), HB_TAG('N','G','A',' ')},*/ /* Ngbaka */ + {HB_TAG('n','g','l',' '), HB_TAG('L','M','W',' ')}, /* Lomwe */ + {HB_TAG('n','g','m',' '), HB_TAG('C','P','P',' ')}, /* Ngatik Men's Creole -> Creoles */ + {HB_TAG('n','g','o',' '), HB_TAG('S','X','T',' ')}, /* Ngoni (retired code) -> Sutu */ + {HB_TAG('n','g','r',' '), HB_TAG_NONE }, /* Engdewu != Nagari */ + {HB_TAG('n','g','u',' '), HB_TAG('N','A','H',' ')}, /* Guerrero Nahuatl -> Nahuatl */ + {HB_TAG('n','h','c',' '), HB_TAG('N','A','H',' ')}, /* Tabasco Nahuatl -> Nahuatl */ + {HB_TAG('n','h','d',' '), HB_TAG('G','U','A',' ')}, /* Chiripá -> Guarani */ + {HB_TAG('n','h','e',' '), HB_TAG('N','A','H',' ')}, /* Eastern Huasteca Nahuatl -> Nahuatl */ + {HB_TAG('n','h','g',' '), HB_TAG('N','A','H',' ')}, /* Tetelcingo Nahuatl -> Nahuatl */ + {HB_TAG('n','h','i',' '), HB_TAG('N','A','H',' ')}, /* Zacatlán-Ahuacatlán-Tepetzintla Nahuatl -> Nahuatl */ + {HB_TAG('n','h','k',' '), HB_TAG('N','A','H',' ')}, /* Isthmus-Cosoleacaque Nahuatl -> Nahuatl */ + {HB_TAG('n','h','m',' '), HB_TAG('N','A','H',' ')}, /* Morelos Nahuatl -> Nahuatl */ + {HB_TAG('n','h','n',' '), HB_TAG('N','A','H',' ')}, /* Central Nahuatl -> Nahuatl */ + {HB_TAG('n','h','p',' '), HB_TAG('N','A','H',' ')}, /* Isthmus-Pajapan Nahuatl -> Nahuatl */ + {HB_TAG('n','h','q',' '), HB_TAG('N','A','H',' ')}, /* Huaxcaleca Nahuatl -> Nahuatl */ + {HB_TAG('n','h','t',' '), HB_TAG('N','A','H',' ')}, /* Ometepec Nahuatl -> Nahuatl */ + {HB_TAG('n','h','v',' '), HB_TAG('N','A','H',' ')}, /* Temascaltepec Nahuatl -> Nahuatl */ + {HB_TAG('n','h','w',' '), HB_TAG('N','A','H',' ')}, /* Western Huasteca Nahuatl -> Nahuatl */ + {HB_TAG('n','h','x',' '), HB_TAG('N','A','H',' ')}, /* Isthmus-Mecayapan Nahuatl -> Nahuatl */ + {HB_TAG('n','h','y',' '), HB_TAG('N','A','H',' ')}, /* Northern Oaxaca Nahuatl -> Nahuatl */ + {HB_TAG('n','h','z',' '), HB_TAG('N','A','H',' ')}, /* Santa MarÃa La Alta Nahuatl -> Nahuatl */ + {HB_TAG('n','i','q',' '), HB_TAG('K','A','L',' ')}, /* Nandi -> Kalenjin */ + {HB_TAG('n','i','s',' '), HB_TAG_NONE }, /* Nimi != Nisi */ +/*{HB_TAG('n','i','u',' '), HB_TAG('N','I','U',' ')},*/ /* Niuean */ + {HB_TAG('n','i','v',' '), HB_TAG('G','I','L',' ')}, /* Gilyak */ + {HB_TAG('n','j','t',' '), HB_TAG('C','P','P',' ')}, /* Ndyuka-Trio Pidgin -> Creoles */ + {HB_TAG('n','j','z',' '), HB_TAG('N','I','S',' ')}, /* Nyishi -> Nisi */ + {HB_TAG('n','k','o',' '), HB_TAG_NONE }, /* Nkonya != N’Ko */ + {HB_TAG('n','k','x',' '), HB_TAG('I','J','O',' ')}, /* Nkoroo -> Ijo */ + {HB_TAG('n','l','a',' '), HB_TAG('B','M','L',' ')}, /* Ngombale -> Bamileke */ + {HB_TAG('n','l','e',' '), HB_TAG('L','U','H',' ')}, /* East Nyala -> Luyia */ + {HB_TAG('n','l','n',' '), HB_TAG('N','A','H',' ')}, /* Durango Nahuatl (retired code) -> Nahuatl */ + {HB_TAG('n','l','v',' '), HB_TAG('N','A','H',' ')}, /* Orizaba Nahuatl -> Nahuatl */ + {HB_TAG('n','n','h',' '), HB_TAG('B','M','L',' ')}, /* Ngiemboon -> Bamileke */ + {HB_TAG('n','n','z',' '), HB_TAG('B','M','L',' ')}, /* Nda'nda' -> Bamileke */ + {HB_TAG('n','o','d',' '), HB_TAG('N','T','A',' ')}, /* Northern Thai -> Northern Tai */ +/*{HB_TAG('n','o','e',' '), HB_TAG('N','O','E',' ')},*/ /* Nimadi */ +/*{HB_TAG('n','o','g',' '), HB_TAG('N','O','G',' ')},*/ /* Nogai */ +/*{HB_TAG('n','o','v',' '), HB_TAG('N','O','V',' ')},*/ /* Novial */ + {HB_TAG('n','p','i',' '), HB_TAG('N','E','P',' ')}, /* Nepali */ + {HB_TAG('n','p','l',' '), HB_TAG('N','A','H',' ')}, /* Southeastern Puebla Nahuatl -> Nahuatl */ + {HB_TAG('n','q','o',' '), HB_TAG('N','K','O',' ')}, /* N’Ko */ + {HB_TAG('n','s','k',' '), HB_TAG('N','A','S',' ')}, /* Naskapi */ + {HB_TAG('n','s','m',' '), HB_TAG_NONE }, /* Sumi Naga != Northern Sami */ +/*{HB_TAG('n','s','o',' '), HB_TAG('N','S','O',' ')},*/ /* Northern Sotho */ + {HB_TAG('n','s','u',' '), HB_TAG('N','A','H',' ')}, /* Sierra Negra Nahuatl -> Nahuatl */ + {HB_TAG('n','t','o',' '), HB_TAG_NONE }, /* Ntomba != Esperanto */ + {HB_TAG('n','u','e',' '), HB_TAG('B','A','D','0')}, /* Ngundu -> Banda */ + {HB_TAG('n','u','u',' '), HB_TAG('B','A','D','0')}, /* Ngbundu -> Banda */ + {HB_TAG('n','u','z',' '), HB_TAG('N','A','H',' ')}, /* Tlamacazapa Nahuatl -> Nahuatl */ + {HB_TAG('n','w','e',' '), HB_TAG('B','M','L',' ')}, /* Ngwe -> Bamileke */ + {HB_TAG('n','y','d',' '), HB_TAG('L','U','H',' ')}, /* Nyore -> Luyia */ +/*{HB_TAG('n','y','m',' '), HB_TAG('N','Y','M',' ')},*/ /* Nyamwezi */ + {HB_TAG('n','y','n',' '), HB_TAG('N','K','L',' ')}, /* Nyankole */ +/*{HB_TAG('n','z','a',' '), HB_TAG('N','Z','A',' ')},*/ /* Tigon Mbembe -> Mbembe Tigon */ +/*{HB_TAG('o','j','b',' '), HB_TAG('O','J','B',' ')},*/ /* Northwestern Ojibwa -> Ojibway */ + {HB_TAG('o','j','c',' '), HB_TAG('O','J','B',' ')}, /* Central Ojibwa -> Ojibway */ + {HB_TAG('o','j','g',' '), HB_TAG('O','J','B',' ')}, /* Eastern Ojibwa -> Ojibway */ + {HB_TAG('o','j','s',' '), HB_TAG('O','C','R',' ')}, /* Severn Ojibwa -> Oji-Cree */ + {HB_TAG('o','j','s',' '), HB_TAG('O','J','B',' ')}, /* Severn Ojibwa -> Ojibway */ + {HB_TAG('o','j','w',' '), HB_TAG('O','J','B',' ')}, /* Western Ojibwa -> Ojibway */ + {HB_TAG('o','k','d',' '), HB_TAG('I','J','O',' ')}, /* Okodia -> Ijo */ + {HB_TAG('o','k','i',' '), HB_TAG('K','A','L',' ')}, /* Okiek -> Kalenjin */ + {HB_TAG('o','k','m',' '), HB_TAG('K','O','H',' ')}, /* Middle Korean (10th-16th cent.) -> Korean Old Hangul */ + {HB_TAG('o','k','r',' '), HB_TAG('I','J','O',' ')}, /* Kirike -> Ijo */ + {HB_TAG('o','n','x',' '), HB_TAG('C','P','P',' ')}, /* Onin Based Pidgin -> Creoles */ + {HB_TAG('o','o','r',' '), HB_TAG('C','P','P',' ')}, /* Oorlams -> Creoles */ + {HB_TAG('o','r','c',' '), HB_TAG('O','R','O',' ')}, /* Orma -> Oromo */ + {HB_TAG('o','r','n',' '), HB_TAG('M','L','Y',' ')}, /* Orang Kanaq -> Malay */ + {HB_TAG('o','r','o',' '), HB_TAG_NONE }, /* Orokolo != Oromo */ + {HB_TAG('o','r','r',' '), HB_TAG('I','J','O',' ')}, /* Oruma -> Ijo */ + {HB_TAG('o','r','s',' '), HB_TAG('M','L','Y',' ')}, /* Orang Seletar -> Malay */ + {HB_TAG('o','r','y',' '), HB_TAG('O','R','I',' ')}, /* Odia (formerly Oriya) */ + {HB_TAG('o','t','w',' '), HB_TAG('O','J','B',' ')}, /* Ottawa -> Ojibway */ + {HB_TAG('o','u','a',' '), HB_TAG('B','B','R',' ')}, /* Tagargrent -> Berber */ + {HB_TAG('p','a','a',' '), HB_TAG_NONE }, /* Papuan [collection] != Palestinian Aramaic */ +/*{HB_TAG('p','a','g',' '), HB_TAG('P','A','G',' ')},*/ /* Pangasinan */ + {HB_TAG('p','a','l',' '), HB_TAG_NONE }, /* Pahlavi != Pali */ +/*{HB_TAG('p','a','m',' '), HB_TAG('P','A','M',' ')},*/ /* Pampanga -> Pampangan */ + {HB_TAG('p','a','p',' '), HB_TAG('P','A','P','0')}, /* Papiamento -> Papiamentu */ + {HB_TAG('p','a','p',' '), HB_TAG('C','P','P',' ')}, /* Papiamento -> Creoles */ + {HB_TAG('p','a','s',' '), HB_TAG_NONE }, /* Papasena != Pashto */ +/*{HB_TAG('p','a','u',' '), HB_TAG('P','A','U',' ')},*/ /* Palauan */ + {HB_TAG('p','b','t',' '), HB_TAG('P','A','S',' ')}, /* Southern Pashto -> Pashto */ + {HB_TAG('p','b','u',' '), HB_TAG('P','A','S',' ')}, /* Northern Pashto -> Pashto */ +/*{HB_TAG('p','c','c',' '), HB_TAG('P','C','C',' ')},*/ /* Bouyei */ +/*{HB_TAG('p','c','d',' '), HB_TAG('P','C','D',' ')},*/ /* Picard */ + {HB_TAG('p','c','e',' '), HB_TAG('P','L','G',' ')}, /* Ruching Palaung -> Palaung */ + {HB_TAG('p','c','k',' '), HB_TAG('Q','I','N',' ')}, /* Paite Chin -> Chin */ + {HB_TAG('p','c','m',' '), HB_TAG('C','P','P',' ')}, /* Nigerian Pidgin -> Creoles */ +/*{HB_TAG('p','d','c',' '), HB_TAG('P','D','C',' ')},*/ /* Pennsylvania German */ + {HB_TAG('p','d','u',' '), HB_TAG('K','R','N',' ')}, /* Kayan -> Karen */ + {HB_TAG('p','e','a',' '), HB_TAG('C','P','P',' ')}, /* Peranakan Indonesian -> Creoles */ + {HB_TAG('p','e','l',' '), HB_TAG('M','L','Y',' ')}, /* Pekal -> Malay */ + {HB_TAG('p','e','s',' '), HB_TAG('F','A','R',' ')}, /* Iranian Persian -> Persian */ + {HB_TAG('p','e','y',' '), HB_TAG('C','P','P',' ')}, /* Petjo -> Creoles */ + {HB_TAG('p','g','a',' '), HB_TAG('A','R','A',' ')}, /* Sudanese Creole Arabic -> Arabic */ + {HB_TAG('p','g','a',' '), HB_TAG('C','P','P',' ')}, /* Sudanese Creole Arabic -> Creoles */ +/*{HB_TAG('p','h','k',' '), HB_TAG('P','H','K',' ')},*/ /* Phake */ + {HB_TAG('p','i','h',' '), HB_TAG('P','I','H',' ')}, /* Pitcairn-Norfolk -> Norfolk */ + {HB_TAG('p','i','h',' '), HB_TAG('C','P','P',' ')}, /* Pitcairn-Norfolk -> Creoles */ + {HB_TAG('p','i','l',' '), HB_TAG_NONE }, /* Yom != Filipino */ + {HB_TAG('p','i','s',' '), HB_TAG('C','P','P',' ')}, /* Pijin -> Creoles */ + {HB_TAG('p','k','h',' '), HB_TAG('Q','I','N',' ')}, /* Pankhu -> Chin */ + {HB_TAG('p','k','o',' '), HB_TAG('K','A','L',' ')}, /* Pökoot -> Kalenjin */ + {HB_TAG('p','l','g',' '), HB_TAG_NONE }, /* Pilagá != Palaung */ + {HB_TAG('p','l','k',' '), HB_TAG_NONE }, /* Kohistani Shina != Polish */ + {HB_TAG('p','l','l',' '), HB_TAG('P','L','G',' ')}, /* Shwe Palaung -> Palaung */ + {HB_TAG('p','l','n',' '), HB_TAG('C','P','P',' ')}, /* Palenquero -> Creoles */ + {HB_TAG('p','l','p',' '), HB_TAG('P','A','P',' ')}, /* Palpa (retired code) */ + {HB_TAG('p','l','t',' '), HB_TAG('M','L','G',' ')}, /* Plateau Malagasy -> Malagasy */ + {HB_TAG('p','m','l',' '), HB_TAG('C','P','P',' ')}, /* Lingua Franca -> Creoles */ +/*{HB_TAG('p','m','s',' '), HB_TAG('P','M','S',' ')},*/ /* Piemontese */ + {HB_TAG('p','m','y',' '), HB_TAG('C','P','P',' ')}, /* Papuan Malay -> Creoles */ +/*{HB_TAG('p','n','b',' '), HB_TAG('P','N','B',' ')},*/ /* Western Panjabi */ + {HB_TAG('p','o','c',' '), HB_TAG('M','Y','N',' ')}, /* Poqomam -> Mayan */ + {HB_TAG('p','o','h',' '), HB_TAG('P','O','H',' ')}, /* Poqomchi' -> Pocomchi */ + {HB_TAG('p','o','h',' '), HB_TAG('M','Y','N',' ')}, /* Poqomchi' -> Mayan */ +/*{HB_TAG('p','o','n',' '), HB_TAG('P','O','N',' ')},*/ /* Pohnpeian */ + {HB_TAG('p','o','v',' '), HB_TAG('C','P','P',' ')}, /* Upper Guinea Crioulo -> Creoles */ + {HB_TAG('p','p','a',' '), HB_TAG('B','A','G',' ')}, /* Pao (retired code) -> Baghelkhandi */ + {HB_TAG('p','r','e',' '), HB_TAG('C','P','P',' ')}, /* Principense -> Creoles */ +/*{HB_TAG('p','r','o',' '), HB_TAG('P','R','O',' ')},*/ /* Old Provençal (to 1500) -> Provençal / Old Provençal */ + {HB_TAG('p','r','s',' '), HB_TAG('D','R','I',' ')}, /* Dari */ + {HB_TAG('p','r','s',' '), HB_TAG('F','A','R',' ')}, /* Dari -> Persian */ + {HB_TAG('p','s','e',' '), HB_TAG('M','L','Y',' ')}, /* Central Malay -> Malay */ + {HB_TAG('p','s','t',' '), HB_TAG('P','A','S',' ')}, /* Central Pashto -> Pashto */ + {HB_TAG('p','u','b',' '), HB_TAG('Q','I','N',' ')}, /* Purum -> Chin */ + {HB_TAG('p','u','z',' '), HB_TAG('Q','I','N',' ')}, /* Purum Naga (retired code) -> Chin */ + {HB_TAG('p','w','o',' '), HB_TAG('P','W','O',' ')}, /* Pwo Western Karen -> Western Pwo Karen */ + {HB_TAG('p','w','o',' '), HB_TAG('K','R','N',' ')}, /* Pwo Western Karen -> Karen */ + {HB_TAG('p','w','w',' '), HB_TAG('K','R','N',' ')}, /* Pwo Northern Karen -> Karen */ + {HB_TAG('q','u','b',' '), HB_TAG('Q','W','H',' ')}, /* Huallaga Huánuco Quechua -> Quechua (Peru) */ + {HB_TAG('q','u','b',' '), HB_TAG('Q','U','Z',' ')}, /* Huallaga Huánuco Quechua -> Quechua */ + {HB_TAG('q','u','c',' '), HB_TAG('Q','U','C',' ')}, /* K’iche’ */ + {HB_TAG('q','u','c',' '), HB_TAG('M','Y','N',' ')}, /* K'iche' -> Mayan */ + {HB_TAG('q','u','d',' '), HB_TAG('Q','V','I',' ')}, /* Calderón Highland Quichua -> Quechua (Ecuador) */ + {HB_TAG('q','u','d',' '), HB_TAG('Q','U','Z',' ')}, /* Calderón Highland Quichua -> Quechua */ + {HB_TAG('q','u','f',' '), HB_TAG('Q','U','Z',' ')}, /* Lambayeque Quechua -> Quechua */ + {HB_TAG('q','u','g',' '), HB_TAG('Q','V','I',' ')}, /* Chimborazo Highland Quichua -> Quechua (Ecuador) */ + {HB_TAG('q','u','g',' '), HB_TAG('Q','U','Z',' ')}, /* Chimborazo Highland Quichua -> Quechua */ + {HB_TAG('q','u','h',' '), HB_TAG('Q','U','H',' ')}, /* South Bolivian Quechua -> Quechua (Bolivia) */ + {HB_TAG('q','u','h',' '), HB_TAG('Q','U','Z',' ')}, /* South Bolivian Quechua -> Quechua */ + {HB_TAG('q','u','k',' '), HB_TAG('Q','U','Z',' ')}, /* Chachapoyas Quechua -> Quechua */ + {HB_TAG('q','u','l',' '), HB_TAG('Q','U','H',' ')}, /* North Bolivian Quechua -> Quechua (Bolivia) */ + {HB_TAG('q','u','l',' '), HB_TAG('Q','U','Z',' ')}, /* North Bolivian Quechua -> Quechua */ + {HB_TAG('q','u','m',' '), HB_TAG('M','Y','N',' ')}, /* Sipacapense -> Mayan */ + {HB_TAG('q','u','p',' '), HB_TAG('Q','V','I',' ')}, /* Southern Pastaza Quechua -> Quechua (Ecuador) */ + {HB_TAG('q','u','p',' '), HB_TAG('Q','U','Z',' ')}, /* Southern Pastaza Quechua -> Quechua */ + {HB_TAG('q','u','r',' '), HB_TAG('Q','W','H',' ')}, /* Yanahuanca Pasco Quechua -> Quechua (Peru) */ + {HB_TAG('q','u','r',' '), HB_TAG('Q','U','Z',' ')}, /* Yanahuanca Pasco Quechua -> Quechua */ + {HB_TAG('q','u','s',' '), HB_TAG('Q','U','H',' ')}, /* Santiago del Estero Quichua -> Quechua (Bolivia) */ + {HB_TAG('q','u','s',' '), HB_TAG('Q','U','Z',' ')}, /* Santiago del Estero Quichua -> Quechua */ + {HB_TAG('q','u','v',' '), HB_TAG('M','Y','N',' ')}, /* Sacapulteco -> Mayan */ + {HB_TAG('q','u','w',' '), HB_TAG('Q','V','I',' ')}, /* Tena Lowland Quichua -> Quechua (Ecuador) */ + {HB_TAG('q','u','w',' '), HB_TAG('Q','U','Z',' ')}, /* Tena Lowland Quichua -> Quechua */ + {HB_TAG('q','u','x',' '), HB_TAG('Q','W','H',' ')}, /* Yauyos Quechua -> Quechua (Peru) */ + {HB_TAG('q','u','x',' '), HB_TAG('Q','U','Z',' ')}, /* Yauyos Quechua -> Quechua */ + {HB_TAG('q','u','y',' '), HB_TAG('Q','U','Z',' ')}, /* Ayacucho Quechua -> Quechua */ +/*{HB_TAG('q','u','z',' '), HB_TAG('Q','U','Z',' ')},*/ /* Cusco Quechua -> Quechua */ + {HB_TAG('q','v','a',' '), HB_TAG('Q','W','H',' ')}, /* Ambo-Pasco Quechua -> Quechua (Peru) */ + {HB_TAG('q','v','a',' '), HB_TAG('Q','U','Z',' ')}, /* Ambo-Pasco Quechua -> Quechua */ + {HB_TAG('q','v','c',' '), HB_TAG('Q','U','Z',' ')}, /* Cajamarca Quechua -> Quechua */ + {HB_TAG('q','v','e',' '), HB_TAG('Q','U','Z',' ')}, /* Eastern ApurÃmac Quechua -> Quechua */ + {HB_TAG('q','v','h',' '), HB_TAG('Q','W','H',' ')}, /* HuamalÃes-Dos de Mayo Huánuco Quechua -> Quechua (Peru) */ + {HB_TAG('q','v','h',' '), HB_TAG('Q','U','Z',' ')}, /* HuamalÃes-Dos de Mayo Huánuco Quechua -> Quechua */ + {HB_TAG('q','v','i',' '), HB_TAG('Q','V','I',' ')}, /* Imbabura Highland Quichua -> Quechua (Ecuador) */ + {HB_TAG('q','v','i',' '), HB_TAG('Q','U','Z',' ')}, /* Imbabura Highland Quichua -> Quechua */ + {HB_TAG('q','v','j',' '), HB_TAG('Q','V','I',' ')}, /* Loja Highland Quichua -> Quechua (Ecuador) */ + {HB_TAG('q','v','j',' '), HB_TAG('Q','U','Z',' ')}, /* Loja Highland Quichua -> Quechua */ + {HB_TAG('q','v','l',' '), HB_TAG('Q','W','H',' ')}, /* Cajatambo North Lima Quechua -> Quechua (Peru) */ + {HB_TAG('q','v','l',' '), HB_TAG('Q','U','Z',' ')}, /* Cajatambo North Lima Quechua -> Quechua */ + {HB_TAG('q','v','m',' '), HB_TAG('Q','W','H',' ')}, /* Margos-Yarowilca-Lauricocha Quechua -> Quechua (Peru) */ + {HB_TAG('q','v','m',' '), HB_TAG('Q','U','Z',' ')}, /* Margos-Yarowilca-Lauricocha Quechua -> Quechua */ + {HB_TAG('q','v','n',' '), HB_TAG('Q','W','H',' ')}, /* North JunÃn Quechua -> Quechua (Peru) */ + {HB_TAG('q','v','n',' '), HB_TAG('Q','U','Z',' ')}, /* North JunÃn Quechua -> Quechua */ + {HB_TAG('q','v','o',' '), HB_TAG('Q','V','I',' ')}, /* Napo Lowland Quechua -> Quechua (Ecuador) */ + {HB_TAG('q','v','o',' '), HB_TAG('Q','U','Z',' ')}, /* Napo Lowland Quechua -> Quechua */ + {HB_TAG('q','v','p',' '), HB_TAG('Q','W','H',' ')}, /* Pacaraos Quechua -> Quechua (Peru) */ + {HB_TAG('q','v','p',' '), HB_TAG('Q','U','Z',' ')}, /* Pacaraos Quechua -> Quechua */ + {HB_TAG('q','v','s',' '), HB_TAG('Q','U','Z',' ')}, /* San MartÃn Quechua -> Quechua */ + {HB_TAG('q','v','w',' '), HB_TAG('Q','W','H',' ')}, /* Huaylla Wanca Quechua -> Quechua (Peru) */ + {HB_TAG('q','v','w',' '), HB_TAG('Q','U','Z',' ')}, /* Huaylla Wanca Quechua -> Quechua */ + {HB_TAG('q','v','z',' '), HB_TAG('Q','V','I',' ')}, /* Northern Pastaza Quichua -> Quechua (Ecuador) */ + {HB_TAG('q','v','z',' '), HB_TAG('Q','U','Z',' ')}, /* Northern Pastaza Quichua -> Quechua */ + {HB_TAG('q','w','a',' '), HB_TAG('Q','W','H',' ')}, /* Corongo Ancash Quechua -> Quechua (Peru) */ + {HB_TAG('q','w','a',' '), HB_TAG('Q','U','Z',' ')}, /* Corongo Ancash Quechua -> Quechua */ + {HB_TAG('q','w','c',' '), HB_TAG('Q','U','Z',' ')}, /* Classical Quechua -> Quechua */ + {HB_TAG('q','w','h',' '), HB_TAG('Q','W','H',' ')}, /* Huaylas Ancash Quechua -> Quechua (Peru) */ + {HB_TAG('q','w','h',' '), HB_TAG('Q','U','Z',' ')}, /* Huaylas Ancash Quechua -> Quechua */ + {HB_TAG('q','w','s',' '), HB_TAG('Q','W','H',' ')}, /* Sihuas Ancash Quechua -> Quechua (Peru) */ + {HB_TAG('q','w','s',' '), HB_TAG('Q','U','Z',' ')}, /* Sihuas Ancash Quechua -> Quechua */ + {HB_TAG('q','w','t',' '), HB_TAG('A','T','H',' ')}, /* Kwalhioqua-Tlatskanai -> Athapaskan */ + {HB_TAG('q','x','a',' '), HB_TAG('Q','W','H',' ')}, /* Chiquián Ancash Quechua -> Quechua (Peru) */ + {HB_TAG('q','x','a',' '), HB_TAG('Q','U','Z',' ')}, /* Chiquián Ancash Quechua -> Quechua */ + {HB_TAG('q','x','c',' '), HB_TAG('Q','W','H',' ')}, /* Chincha Quechua -> Quechua (Peru) */ + {HB_TAG('q','x','c',' '), HB_TAG('Q','U','Z',' ')}, /* Chincha Quechua -> Quechua */ + {HB_TAG('q','x','h',' '), HB_TAG('Q','W','H',' ')}, /* Panao Huánuco Quechua -> Quechua (Peru) */ + {HB_TAG('q','x','h',' '), HB_TAG('Q','U','Z',' ')}, /* Panao Huánuco Quechua -> Quechua */ + {HB_TAG('q','x','l',' '), HB_TAG('Q','V','I',' ')}, /* Salasaca Highland Quichua -> Quechua (Ecuador) */ + {HB_TAG('q','x','l',' '), HB_TAG('Q','U','Z',' ')}, /* Salasaca Highland Quichua -> Quechua */ + {HB_TAG('q','x','n',' '), HB_TAG('Q','W','H',' ')}, /* Northern Conchucos Ancash Quechua -> Quechua (Peru) */ + {HB_TAG('q','x','n',' '), HB_TAG('Q','U','Z',' ')}, /* Northern Conchucos Ancash Quechua -> Quechua */ + {HB_TAG('q','x','o',' '), HB_TAG('Q','W','H',' ')}, /* Southern Conchucos Ancash Quechua -> Quechua (Peru) */ + {HB_TAG('q','x','o',' '), HB_TAG('Q','U','Z',' ')}, /* Southern Conchucos Ancash Quechua -> Quechua */ + {HB_TAG('q','x','p',' '), HB_TAG('Q','U','Z',' ')}, /* Puno Quechua -> Quechua */ + {HB_TAG('q','x','r',' '), HB_TAG('Q','V','I',' ')}, /* Cañar Highland Quichua -> Quechua (Ecuador) */ + {HB_TAG('q','x','r',' '), HB_TAG('Q','U','Z',' ')}, /* Cañar Highland Quichua -> Quechua */ + {HB_TAG('q','x','t',' '), HB_TAG('Q','W','H',' ')}, /* Santa Ana de Tusi Pasco Quechua -> Quechua (Peru) */ + {HB_TAG('q','x','t',' '), HB_TAG('Q','U','Z',' ')}, /* Santa Ana de Tusi Pasco Quechua -> Quechua */ + {HB_TAG('q','x','u',' '), HB_TAG('Q','U','Z',' ')}, /* Arequipa-La Unión Quechua -> Quechua */ + {HB_TAG('q','x','w',' '), HB_TAG('Q','W','H',' ')}, /* Jauja Wanca Quechua -> Quechua (Peru) */ + {HB_TAG('q','x','w',' '), HB_TAG('Q','U','Z',' ')}, /* Jauja Wanca Quechua -> Quechua */ + {HB_TAG('r','a','g',' '), HB_TAG('L','U','H',' ')}, /* Logooli -> Luyia */ +/*{HB_TAG('r','a','j',' '), HB_TAG('R','A','J',' ')},*/ /* Rajasthani [macrolanguage] */ + {HB_TAG('r','a','l',' '), HB_TAG('Q','I','N',' ')}, /* Ralte -> Chin */ +/*{HB_TAG('r','a','r',' '), HB_TAG('R','A','R',' ')},*/ /* Rarotongan */ + {HB_TAG('r','b','b',' '), HB_TAG('P','L','G',' ')}, /* Rumai Palaung -> Palaung */ + {HB_TAG('r','b','l',' '), HB_TAG('B','I','K',' ')}, /* Miraya Bikol -> Bikol */ + {HB_TAG('r','c','f',' '), HB_TAG('C','P','P',' ')}, /* Réunion Creole French -> Creoles */ +/*{HB_TAG('r','e','j',' '), HB_TAG('R','E','J',' ')},*/ /* Rejang */ +/*{HB_TAG('r','h','g',' '), HB_TAG('R','H','G',' ')},*/ /* Rohingya */ +/*{HB_TAG('r','i','a',' '), HB_TAG('R','I','A',' ')},*/ /* Riang (India) */ + {HB_TAG('r','i','f',' '), HB_TAG('R','I','F',' ')}, /* Tarifit */ + {HB_TAG('r','i','f',' '), HB_TAG('B','B','R',' ')}, /* Tarifit -> Berber */ +/*{HB_TAG('r','i','t',' '), HB_TAG('R','I','T',' ')},*/ /* Ritharrngu -> Ritarungo */ + {HB_TAG('r','k','i',' '), HB_TAG('A','R','K',' ')}, /* Rakhine */ +/*{HB_TAG('r','k','w',' '), HB_TAG('R','K','W',' ')},*/ /* Arakwal */ + {HB_TAG('r','m','c',' '), HB_TAG('R','O','Y',' ')}, /* Carpathian Romani -> Romany */ + {HB_TAG('r','m','f',' '), HB_TAG('R','O','Y',' ')}, /* Kalo Finnish Romani -> Romany */ + {HB_TAG('r','m','l',' '), HB_TAG('R','O','Y',' ')}, /* Baltic Romani -> Romany */ + {HB_TAG('r','m','n',' '), HB_TAG('R','O','Y',' ')}, /* Balkan Romani -> Romany */ + {HB_TAG('r','m','o',' '), HB_TAG('R','O','Y',' ')}, /* Sinte Romani -> Romany */ + {HB_TAG('r','m','s',' '), HB_TAG_NONE }, /* Romanian Sign Language != Romansh */ + {HB_TAG('r','m','w',' '), HB_TAG('R','O','Y',' ')}, /* Welsh Romani -> Romany */ + {HB_TAG('r','m','y',' '), HB_TAG('R','M','Y',' ')}, /* Vlax Romani */ + {HB_TAG('r','m','y',' '), HB_TAG('R','O','Y',' ')}, /* Vlax Romani -> Romany */ + {HB_TAG('r','m','z',' '), HB_TAG('A','R','K',' ')}, /* Marma -> Rakhine */ + {HB_TAG('r','o','m',' '), HB_TAG('R','O','Y',' ')}, /* Romany [macrolanguage] */ + {HB_TAG('r','o','p',' '), HB_TAG('C','P','P',' ')}, /* Kriol -> Creoles */ + {HB_TAG('r','t','c',' '), HB_TAG('Q','I','N',' ')}, /* Rungtu Chin -> Chin */ +/*{HB_TAG('r','t','m',' '), HB_TAG('R','T','M',' ')},*/ /* Rotuman */ + {HB_TAG('r','u','e',' '), HB_TAG('R','S','Y',' ')}, /* Rusyn */ +/*{HB_TAG('r','u','p',' '), HB_TAG('R','U','P',' ')},*/ /* Aromanian */ + {HB_TAG('r','w','r',' '), HB_TAG('M','A','W',' ')}, /* Marwari (India) */ + {HB_TAG('s','a','d',' '), HB_TAG_NONE }, /* Sandawe != Sadri */ + {HB_TAG('s','a','h',' '), HB_TAG('Y','A','K',' ')}, /* Yakut -> Sakha */ + {HB_TAG('s','a','m',' '), HB_TAG('P','A','A',' ')}, /* Samaritan Aramaic -> Palestinian Aramaic */ +/*{HB_TAG('s','a','s',' '), HB_TAG('S','A','S',' ')},*/ /* Sasak */ +/*{HB_TAG('s','a','t',' '), HB_TAG('S','A','T',' ')},*/ /* Santali */ + {HB_TAG('s','a','y',' '), HB_TAG_NONE }, /* Saya != Sayisi */ + {HB_TAG('s','c','f',' '), HB_TAG('C','P','P',' ')}, /* San Miguel Creole French -> Creoles */ + {HB_TAG('s','c','h',' '), HB_TAG('Q','I','N',' ')}, /* Sakachep -> Chin */ + {HB_TAG('s','c','i',' '), HB_TAG('C','P','P',' ')}, /* Sri Lankan Creole Malay -> Creoles */ + {HB_TAG('s','c','k',' '), HB_TAG('S','A','D',' ')}, /* Sadri */ +/*{HB_TAG('s','c','n',' '), HB_TAG('S','C','N',' ')},*/ /* Sicilian */ +/*{HB_TAG('s','c','o',' '), HB_TAG('S','C','O',' ')},*/ /* Scots */ + {HB_TAG('s','c','s',' '), HB_TAG('S','C','S',' ')}, /* North Slavey */ + {HB_TAG('s','c','s',' '), HB_TAG('S','L','A',' ')}, /* North Slavey -> Slavey */ + {HB_TAG('s','c','s',' '), HB_TAG('A','T','H',' ')}, /* North Slavey -> Athapaskan */ + {HB_TAG('s','d','c',' '), HB_TAG('S','R','D',' ')}, /* Sassarese Sardinian -> Sardinian */ + {HB_TAG('s','d','h',' '), HB_TAG('K','U','R',' ')}, /* Southern Kurdish -> Kurdish */ + {HB_TAG('s','d','n',' '), HB_TAG('S','R','D',' ')}, /* Gallurese Sardinian -> Sardinian */ + {HB_TAG('s','d','s',' '), HB_TAG('B','B','R',' ')}, /* Sened -> Berber */ + {HB_TAG('s','e','h',' '), HB_TAG('S','N','A',' ')}, /* Sena */ + {HB_TAG('s','e','k',' '), HB_TAG('A','T','H',' ')}, /* Sekani -> Athapaskan */ +/*{HB_TAG('s','e','l',' '), HB_TAG('S','E','L',' ')},*/ /* Selkup */ + {HB_TAG('s','e','z',' '), HB_TAG('Q','I','N',' ')}, /* Senthang Chin -> Chin */ + {HB_TAG('s','f','m',' '), HB_TAG('S','F','M',' ')}, /* Small Flowery Miao */ + {HB_TAG('s','f','m',' '), HB_TAG('H','M','N',' ')}, /* Small Flowery Miao -> Hmong */ +/*{HB_TAG('s','g','a',' '), HB_TAG('S','G','A',' ')},*/ /* Old Irish (to 900) */ + {HB_TAG('s','g','c',' '), HB_TAG('K','A','L',' ')}, /* Kipsigis -> Kalenjin */ + {HB_TAG('s','g','o',' '), HB_TAG_NONE }, /* Songa (retired code) != Sango */ +/*{HB_TAG('s','g','s',' '), HB_TAG('S','G','S',' ')},*/ /* Samogitian */ + {HB_TAG('s','g','w',' '), HB_TAG('C','H','G',' ')}, /* Sebat Bet Gurage -> Chaha Gurage */ + {HB_TAG('s','h','i',' '), HB_TAG('S','H','I',' ')}, /* Tachelhit */ + {HB_TAG('s','h','i',' '), HB_TAG('B','B','R',' ')}, /* Tachelhit -> Berber */ + {HB_TAG('s','h','l',' '), HB_TAG('Q','I','N',' ')}, /* Shendu -> Chin */ +/*{HB_TAG('s','h','n',' '), HB_TAG('S','H','N',' ')},*/ /* Shan */ + {HB_TAG('s','h','u',' '), HB_TAG('A','R','A',' ')}, /* Chadian Arabic -> Arabic */ + {HB_TAG('s','h','y',' '), HB_TAG('B','B','R',' ')}, /* Tachawit -> Berber */ + {HB_TAG('s','i','b',' '), HB_TAG_NONE }, /* Sebop != Sibe */ +/*{HB_TAG('s','i','d',' '), HB_TAG('S','I','D',' ')},*/ /* Sidamo */ + {HB_TAG('s','i','g',' '), HB_TAG_NONE }, /* Paasaal != Silte Gurage */ + {HB_TAG('s','i','z',' '), HB_TAG('B','B','R',' ')}, /* Siwi -> Berber */ + {HB_TAG('s','j','d',' '), HB_TAG('K','S','M',' ')}, /* Kildin Sami */ + {HB_TAG('s','j','o',' '), HB_TAG('S','I','B',' ')}, /* Xibe -> Sibe */ + {HB_TAG('s','j','s',' '), HB_TAG('B','B','R',' ')}, /* Senhaja De Srair -> Berber */ + {HB_TAG('s','k','g',' '), HB_TAG('M','L','G',' ')}, /* Sakalava Malagasy -> Malagasy */ + {HB_TAG('s','k','r',' '), HB_TAG('S','R','K',' ')}, /* Saraiki */ + {HB_TAG('s','k','s',' '), HB_TAG_NONE }, /* Maia != Skolt Sami */ + {HB_TAG('s','k','w',' '), HB_TAG('C','P','P',' ')}, /* Skepi Creole Dutch -> Creoles */ + {HB_TAG('s','k','y',' '), HB_TAG_NONE }, /* Sikaiana != Slovak */ + {HB_TAG('s','l','a',' '), HB_TAG_NONE }, /* Slavic [collection] != Slavey */ + {HB_TAG('s','m','a',' '), HB_TAG('S','S','M',' ')}, /* Southern Sami */ + {HB_TAG('s','m','d',' '), HB_TAG('M','B','N',' ')}, /* Sama (retired code) -> Mbundu */ + {HB_TAG('s','m','j',' '), HB_TAG('L','S','M',' ')}, /* Lule Sami */ + {HB_TAG('s','m','l',' '), HB_TAG_NONE }, /* Central Sama != Somali */ + {HB_TAG('s','m','n',' '), HB_TAG('I','S','M',' ')}, /* Inari Sami */ + {HB_TAG('s','m','s',' '), HB_TAG('S','K','S',' ')}, /* Skolt Sami */ + {HB_TAG('s','m','t',' '), HB_TAG('Q','I','N',' ')}, /* Simte -> Chin */ + {HB_TAG('s','n','b',' '), HB_TAG('I','B','A',' ')}, /* Sebuyau (retired code) -> Iban */ + {HB_TAG('s','n','h',' '), HB_TAG_NONE }, /* Shinabo (retired code) != Sinhala (Sinhalese) */ +/*{HB_TAG('s','n','k',' '), HB_TAG('S','N','K',' ')},*/ /* Soninke */ + {HB_TAG('s','o','g',' '), HB_TAG_NONE }, /* Sogdian != Sodo Gurage */ +/*{HB_TAG('s','o','p',' '), HB_TAG('S','O','P',' ')},*/ /* Songe */ + {HB_TAG('s','p','v',' '), HB_TAG('O','R','I',' ')}, /* Sambalpuri -> Odia (formerly Oriya) */ + {HB_TAG('s','p','y',' '), HB_TAG('K','A','L',' ')}, /* Sabaot -> Kalenjin */ + {HB_TAG('s','r','b',' '), HB_TAG_NONE }, /* Sora != Serbian */ + {HB_TAG('s','r','c',' '), HB_TAG('S','R','D',' ')}, /* Logudorese Sardinian -> Sardinian */ + {HB_TAG('s','r','k',' '), HB_TAG_NONE }, /* Serudung Murut != Saraiki */ + {HB_TAG('s','r','m',' '), HB_TAG('C','P','P',' ')}, /* Saramaccan -> Creoles */ + {HB_TAG('s','r','n',' '), HB_TAG('C','P','P',' ')}, /* Sranan Tongo -> Creoles */ + {HB_TAG('s','r','o',' '), HB_TAG('S','R','D',' ')}, /* Campidanese Sardinian -> Sardinian */ +/*{HB_TAG('s','r','r',' '), HB_TAG('S','R','R',' ')},*/ /* Serer */ + {HB_TAG('s','r','s',' '), HB_TAG('A','T','H',' ')}, /* Sarsi -> Athapaskan */ + {HB_TAG('s','s','h',' '), HB_TAG('A','R','A',' ')}, /* Shihhi Arabic -> Arabic */ + {HB_TAG('s','s','l',' '), HB_TAG_NONE }, /* Western Sisaala != South Slavey */ + {HB_TAG('s','s','m',' '), HB_TAG_NONE }, /* Semnam != Southern Sami */ + {HB_TAG('s','t','a',' '), HB_TAG('C','P','P',' ')}, /* Settla -> Creoles */ +/*{HB_TAG('s','t','q',' '), HB_TAG('S','T','Q',' ')},*/ /* Saterfriesisch -> Saterland Frisian */ + {HB_TAG('s','t','v',' '), HB_TAG('S','I','G',' ')}, /* Silt'e -> Silte Gurage */ +/*{HB_TAG('s','u','k',' '), HB_TAG('S','U','K',' ')},*/ /* Sukuma */ + {HB_TAG('s','u','q',' '), HB_TAG('S','U','R',' ')}, /* Suri */ + {HB_TAG('s','u','r',' '), HB_TAG_NONE }, /* Mwaghavul != Suri */ +/*{HB_TAG('s','v','a',' '), HB_TAG('S','V','A',' ')},*/ /* Svan */ + {HB_TAG('s','v','c',' '), HB_TAG('C','P','P',' ')}, /* Vincentian Creole English -> Creoles */ + {HB_TAG('s','v','e',' '), HB_TAG_NONE }, /* Serili != Swedish */ + {HB_TAG('s','w','b',' '), HB_TAG('C','M','R',' ')}, /* Maore Comorian -> Comorian */ + {HB_TAG('s','w','c',' '), HB_TAG('S','W','K',' ')}, /* Congo Swahili -> Swahili */ + {HB_TAG('s','w','h',' '), HB_TAG('S','W','K',' ')}, /* Swahili */ + {HB_TAG('s','w','k',' '), HB_TAG_NONE }, /* Malawi Sena != Swahili */ + {HB_TAG('s','w','n',' '), HB_TAG('B','B','R',' ')}, /* Sawknah -> Berber */ + {HB_TAG('s','w','v',' '), HB_TAG('M','A','W',' ')}, /* Shekhawati -> Marwari */ +/*{HB_TAG('s','x','u',' '), HB_TAG('S','X','U',' ')},*/ /* Upper Saxon */ + {HB_TAG('s','y','c',' '), HB_TAG('S','Y','R',' ')}, /* Classical Syriac -> Syriac */ +/*{HB_TAG('s','y','l',' '), HB_TAG('S','Y','L',' ')},*/ /* Sylheti */ +/*{HB_TAG('s','y','r',' '), HB_TAG('S','Y','R',' ')},*/ /* Syriac [macrolanguage] */ +/*{HB_TAG('s','z','l',' '), HB_TAG('S','Z','L',' ')},*/ /* Silesian */ + {HB_TAG('t','a','a',' '), HB_TAG('A','T','H',' ')}, /* Lower Tanana -> Athapaskan */ +/*{HB_TAG('t','a','b',' '), HB_TAG('T','A','B',' ')},*/ /* Tabassaran -> Tabasaran */ + {HB_TAG('t','a','j',' '), HB_TAG_NONE }, /* Eastern Tamang != Tajiki */ + {HB_TAG('t','a','q',' '), HB_TAG('T','M','H',' ')}, /* Tamasheq -> Tamashek */ + {HB_TAG('t','a','q',' '), HB_TAG('B','B','R',' ')}, /* Tamasheq -> Berber */ + {HB_TAG('t','a','s',' '), HB_TAG('C','P','P',' ')}, /* Tay Boi -> Creoles */ + {HB_TAG('t','a','u',' '), HB_TAG('A','T','H',' ')}, /* Upper Tanana -> Athapaskan */ + {HB_TAG('t','c','b',' '), HB_TAG('A','T','H',' ')}, /* Tanacross -> Athapaskan */ + {HB_TAG('t','c','e',' '), HB_TAG('A','T','H',' ')}, /* Southern Tutchone -> Athapaskan */ + {HB_TAG('t','c','h',' '), HB_TAG('C','P','P',' ')}, /* Turks And Caicos Creole English -> Creoles */ + {HB_TAG('t','c','p',' '), HB_TAG('Q','I','N',' ')}, /* Tawr Chin -> Chin */ + {HB_TAG('t','c','s',' '), HB_TAG('C','P','P',' ')}, /* Torres Strait Creole -> Creoles */ + {HB_TAG('t','c','y',' '), HB_TAG('T','U','L',' ')}, /* Tulu -> Tumbuka */ + {HB_TAG('t','c','z',' '), HB_TAG('Q','I','N',' ')}, /* Thado Chin -> Chin */ +/*{HB_TAG('t','d','d',' '), HB_TAG('T','D','D',' ')},*/ /* Tai Nüa -> Dehong Dai */ + {HB_TAG('t','d','x',' '), HB_TAG('M','L','G',' ')}, /* Tandroy-Mahafaly Malagasy -> Malagasy */ + {HB_TAG('t','e','c',' '), HB_TAG('K','A','L',' ')}, /* Terik -> Kalenjin */ + {HB_TAG('t','e','m',' '), HB_TAG('T','M','N',' ')}, /* Timne -> Temne */ +/*{HB_TAG('t','e','t',' '), HB_TAG('T','E','T',' ')},*/ /* Tetum */ + {HB_TAG('t','e','z',' '), HB_TAG('B','B','R',' ')}, /* Tetserret -> Berber */ + {HB_TAG('t','f','n',' '), HB_TAG('A','T','H',' ')}, /* Tanaina -> Athapaskan */ + {HB_TAG('t','g','h',' '), HB_TAG('C','P','P',' ')}, /* Tobagonian Creole English -> Creoles */ + {HB_TAG('t','g','j',' '), HB_TAG('N','I','S',' ')}, /* Tagin -> Nisi */ + {HB_TAG('t','g','n',' '), HB_TAG_NONE }, /* Tandaganon != Tongan */ + {HB_TAG('t','g','r',' '), HB_TAG_NONE }, /* Tareng != Tigre */ + {HB_TAG('t','g','x',' '), HB_TAG('A','T','H',' ')}, /* Tagish -> Athapaskan */ + {HB_TAG('t','g','y',' '), HB_TAG_NONE }, /* Togoyo != Tigrinya */ + {HB_TAG('t','h','t',' '), HB_TAG('A','T','H',' ')}, /* Tahltan -> Athapaskan */ + {HB_TAG('t','h','v',' '), HB_TAG('T','M','H',' ')}, /* Tahaggart Tamahaq -> Tamashek */ + {HB_TAG('t','h','v',' '), HB_TAG('B','B','R',' ')}, /* Tahaggart Tamahaq -> Berber */ + {HB_TAG('t','h','z',' '), HB_TAG('T','M','H',' ')}, /* Tayart Tamajeq -> Tamashek */ + {HB_TAG('t','h','z',' '), HB_TAG('B','B','R',' ')}, /* Tayart Tamajeq -> Berber */ + {HB_TAG('t','i','a',' '), HB_TAG('B','B','R',' ')}, /* Tidikelt Tamazight -> Berber */ + {HB_TAG('t','i','g',' '), HB_TAG('T','G','R',' ')}, /* Tigre */ +/*{HB_TAG('t','i','v',' '), HB_TAG('T','I','V',' ')},*/ /* Tiv */ +/*{HB_TAG('t','j','l',' '), HB_TAG('T','J','L',' ')},*/ /* Tai Laing */ + {HB_TAG('t','j','o',' '), HB_TAG('B','B','R',' ')}, /* Temacine Tamazight -> Berber */ + {HB_TAG('t','k','g',' '), HB_TAG('M','L','G',' ')}, /* Tesaka Malagasy -> Malagasy */ + {HB_TAG('t','k','m',' '), HB_TAG_NONE }, /* Takelma != Turkmen */ +/*{HB_TAG('t','l','i',' '), HB_TAG('T','L','I',' ')},*/ /* Tlingit */ + {HB_TAG('t','m','g',' '), HB_TAG('C','P','P',' ')}, /* Ternateño -> Creoles */ + {HB_TAG('t','m','h',' '), HB_TAG('T','M','H',' ')}, /* Tamashek [macrolanguage] */ + {HB_TAG('t','m','h',' '), HB_TAG('B','B','R',' ')}, /* Tamashek [macrolanguage] -> Berber */ + {HB_TAG('t','m','n',' '), HB_TAG_NONE }, /* Taman (Indonesia) != Temne */ + {HB_TAG('t','m','w',' '), HB_TAG('M','L','Y',' ')}, /* Temuan -> Malay */ + {HB_TAG('t','n','a',' '), HB_TAG_NONE }, /* Tacana != Tswana */ + {HB_TAG('t','n','e',' '), HB_TAG_NONE }, /* Tinoc Kallahan (retired code) != Tundra Enets */ + {HB_TAG('t','n','f',' '), HB_TAG('D','R','I',' ')}, /* Tangshewi (retired code) -> Dari */ + {HB_TAG('t','n','f',' '), HB_TAG('F','A','R',' ')}, /* Tangshewi (retired code) -> Persian */ + {HB_TAG('t','n','g',' '), HB_TAG_NONE }, /* Tobanga != Tonga */ + {HB_TAG('t','o','d',' '), HB_TAG('T','O','D','0')}, /* Toma */ + {HB_TAG('t','o','i',' '), HB_TAG('T','N','G',' ')}, /* Tonga (Zambia) */ + {HB_TAG('t','o','j',' '), HB_TAG('M','Y','N',' ')}, /* Tojolabal -> Mayan */ + {HB_TAG('t','o','l',' '), HB_TAG('A','T','H',' ')}, /* Tolowa -> Athapaskan */ + {HB_TAG('t','o','r',' '), HB_TAG('B','A','D','0')}, /* Togbo-Vara Banda -> Banda */ + {HB_TAG('t','p','i',' '), HB_TAG('T','P','I',' ')}, /* Tok Pisin */ + {HB_TAG('t','p','i',' '), HB_TAG('C','P','P',' ')}, /* Tok Pisin -> Creoles */ + {HB_TAG('t','r','f',' '), HB_TAG('C','P','P',' ')}, /* Trinidadian Creole English -> Creoles */ + {HB_TAG('t','r','k',' '), HB_TAG_NONE }, /* Turkic [collection] != Turkish */ + {HB_TAG('t','r','u',' '), HB_TAG('T','U','A',' ')}, /* Turoyo -> Turoyo Aramaic */ + {HB_TAG('t','r','u',' '), HB_TAG('S','Y','R',' ')}, /* Turoyo -> Syriac */ + {HB_TAG('t','s','g',' '), HB_TAG_NONE }, /* Tausug != Tsonga */ +/*{HB_TAG('t','s','j',' '), HB_TAG('T','S','J',' ')},*/ /* Tshangla */ + {HB_TAG('t','t','c',' '), HB_TAG('M','Y','N',' ')}, /* Tektiteko -> Mayan */ + {HB_TAG('t','t','m',' '), HB_TAG('A','T','H',' ')}, /* Northern Tutchone -> Athapaskan */ + {HB_TAG('t','t','q',' '), HB_TAG('T','M','H',' ')}, /* Tawallammat Tamajaq -> Tamashek */ + {HB_TAG('t','t','q',' '), HB_TAG('B','B','R',' ')}, /* Tawallammat Tamajaq -> Berber */ + {HB_TAG('t','u','a',' '), HB_TAG_NONE }, /* Wiarumus != Turoyo Aramaic */ + {HB_TAG('t','u','l',' '), HB_TAG_NONE }, /* Tula != Tumbuka */ +/*{HB_TAG('t','u','m',' '), HB_TAG('T','U','M',' ')},*/ /* Tumbuka -> Tulu */ + {HB_TAG('t','u','u',' '), HB_TAG('A','T','H',' ')}, /* Tututni -> Athapaskan */ + {HB_TAG('t','u','v',' '), HB_TAG_NONE }, /* Turkana != Tuvin */ + {HB_TAG('t','u','y',' '), HB_TAG('K','A','L',' ')}, /* Tugen -> Kalenjin */ +/*{HB_TAG('t','v','l',' '), HB_TAG('T','V','L',' ')},*/ /* Tuvalu */ + {HB_TAG('t','v','y',' '), HB_TAG('C','P','P',' ')}, /* Timor Pidgin -> Creoles */ + {HB_TAG('t','x','c',' '), HB_TAG('A','T','H',' ')}, /* Tsetsaut -> Athapaskan */ + {HB_TAG('t','x','y',' '), HB_TAG('M','L','G',' ')}, /* Tanosy Malagasy -> Malagasy */ + {HB_TAG('t','y','v',' '), HB_TAG('T','U','V',' ')}, /* Tuvinian -> Tuvin */ +/*{HB_TAG('t','y','z',' '), HB_TAG('T','Y','Z',' ')},*/ /* Tà y */ + {HB_TAG('t','z','h',' '), HB_TAG('M','Y','N',' ')}, /* Tzeltal -> Mayan */ + {HB_TAG('t','z','j',' '), HB_TAG('M','Y','N',' ')}, /* Tz'utujil -> Mayan */ + {HB_TAG('t','z','m',' '), HB_TAG('T','Z','M',' ')}, /* Central Atlas Tamazight -> Tamazight */ + {HB_TAG('t','z','m',' '), HB_TAG('B','B','R',' ')}, /* Central Atlas Tamazight -> Berber */ + {HB_TAG('t','z','o',' '), HB_TAG('T','Z','O',' ')}, /* Tzotzil */ + {HB_TAG('t','z','o',' '), HB_TAG('M','Y','N',' ')}, /* Tzotzil -> Mayan */ + {HB_TAG('u','b','l',' '), HB_TAG('B','I','K',' ')}, /* Buhi'non Bikol -> Bikol */ +/*{HB_TAG('u','d','m',' '), HB_TAG('U','D','M',' ')},*/ /* Udmurt */ + {HB_TAG('u','k','i',' '), HB_TAG('K','U','I',' ')}, /* Kui (India) */ + {HB_TAG('u','l','n',' '), HB_TAG('C','P','P',' ')}, /* Unserdeutsch -> Creoles */ +/*{HB_TAG('u','m','b',' '), HB_TAG('U','M','B',' ')},*/ /* Umbundu */ + {HB_TAG('u','n','r',' '), HB_TAG('M','U','N',' ')}, /* Mundari */ + {HB_TAG('u','r','k',' '), HB_TAG('M','L','Y',' ')}, /* Urak Lawoi' -> Malay */ + {HB_TAG('u','s','p',' '), HB_TAG('M','Y','N',' ')}, /* Uspanteco -> Mayan */ + {HB_TAG('u','z','n',' '), HB_TAG('U','Z','B',' ')}, /* Northern Uzbek -> Uzbek */ + {HB_TAG('u','z','s',' '), HB_TAG('U','Z','B',' ')}, /* Southern Uzbek -> Uzbek */ + {HB_TAG('v','a','p',' '), HB_TAG('Q','I','N',' ')}, /* Vaiphei -> Chin */ +/*{HB_TAG('v','e','c',' '), HB_TAG('V','E','C',' ')},*/ /* Venetian */ + {HB_TAG('v','i','c',' '), HB_TAG('C','P','P',' ')}, /* Virgin Islands Creole English -> Creoles */ + {HB_TAG('v','i','t',' '), HB_TAG_NONE }, /* Viti != Vietnamese */ + {HB_TAG('v','k','k',' '), HB_TAG('M','L','Y',' ')}, /* Kaur -> Malay */ + {HB_TAG('v','k','p',' '), HB_TAG('C','P','P',' ')}, /* Korlai Creole Portuguese -> Creoles */ + {HB_TAG('v','k','t',' '), HB_TAG('M','L','Y',' ')}, /* Tenggarong Kutai Malay -> Malay */ + {HB_TAG('v','l','s',' '), HB_TAG('F','L','E',' ')}, /* Vlaams -> Dutch (Flemish) */ + {HB_TAG('v','m','w',' '), HB_TAG('M','A','K',' ')}, /* Makhuwa */ +/*{HB_TAG('v','r','o',' '), HB_TAG('V','R','O',' ')},*/ /* Võro */ + {HB_TAG('w','a','g',' '), HB_TAG_NONE }, /* Wa'ema != Wagdi */ +/*{HB_TAG('w','a','r',' '), HB_TAG('W','A','R',' ')},*/ /* Waray (Philippines) -> Waray-Waray */ + {HB_TAG('w','b','m',' '), HB_TAG('W','A',' ',' ')}, /* Wa */ + {HB_TAG('w','b','r',' '), HB_TAG('W','A','G',' ')}, /* Wagdi */ + {HB_TAG('w','b','r',' '), HB_TAG('R','A','J',' ')}, /* Wagdi -> Rajasthani */ +/*{HB_TAG('w','c','i',' '), HB_TAG('W','C','I',' ')},*/ /* Waci Gbe */ + {HB_TAG('w','e','a',' '), HB_TAG('K','R','N',' ')}, /* Wewaw -> Karen */ + {HB_TAG('w','e','s',' '), HB_TAG('C','P','P',' ')}, /* Cameroon Pidgin -> Creoles */ + {HB_TAG('w','e','u',' '), HB_TAG('Q','I','N',' ')}, /* Rawngtu Chin -> Chin */ + {HB_TAG('w','l','c',' '), HB_TAG('C','M','R',' ')}, /* Mwali Comorian -> Comorian */ + {HB_TAG('w','l','e',' '), HB_TAG('S','I','G',' ')}, /* Wolane -> Silte Gurage */ + {HB_TAG('w','l','k',' '), HB_TAG('A','T','H',' ')}, /* Wailaki -> Athapaskan */ + {HB_TAG('w','n','i',' '), HB_TAG('C','M','R',' ')}, /* Ndzwani Comorian -> Comorian */ + {HB_TAG('w','r','y',' '), HB_TAG('M','A','W',' ')}, /* Merwari -> Marwari */ + {HB_TAG('w','s','g',' '), HB_TAG('G','O','N',' ')}, /* Adilabad Gondi -> Gondi */ +/*{HB_TAG('w','t','m',' '), HB_TAG('W','T','M',' ')},*/ /* Mewati */ + {HB_TAG('w','u','u',' '), HB_TAG('Z','H','S',' ')}, /* Wu Chinese -> Chinese, Simplified */ + {HB_TAG('x','a','l',' '), HB_TAG('K','L','M',' ')}, /* Kalmyk */ + {HB_TAG('x','a','l',' '), HB_TAG('T','O','D',' ')}, /* Kalmyk -> Todo */ + {HB_TAG('x','a','n',' '), HB_TAG('S','E','K',' ')}, /* Xamtanga -> Sekota */ + {HB_TAG('x','b','d',' '), HB_TAG_NONE }, /* Bindal != Lü */ +/*{HB_TAG('x','j','b',' '), HB_TAG('X','J','B',' ')},*/ /* Minjungbal -> Minjangbal */ +/*{HB_TAG('x','k','f',' '), HB_TAG('X','K','F',' ')},*/ /* Khengkha */ + {HB_TAG('x','m','g',' '), HB_TAG('B','M','L',' ')}, /* Mengaka -> Bamileke */ + {HB_TAG('x','m','m',' '), HB_TAG('M','L','Y',' ')}, /* Manado Malay -> Malay */ + {HB_TAG('x','m','m',' '), HB_TAG('C','P','P',' ')}, /* Manado Malay -> Creoles */ + {HB_TAG('x','m','v',' '), HB_TAG('M','L','G',' ')}, /* Antankarana Malagasy -> Malagasy */ + {HB_TAG('x','m','w',' '), HB_TAG('M','L','G',' ')}, /* Tsimihety Malagasy -> Malagasy */ + {HB_TAG('x','n','j',' '), HB_TAG('S','X','T',' ')}, /* Ngoni (Tanzania) -> Sutu */ + {HB_TAG('x','n','q',' '), HB_TAG('S','X','T',' ')}, /* Ngoni (Mozambique) -> Sutu */ + {HB_TAG('x','n','r',' '), HB_TAG('D','G','R',' ')}, /* Kangri -> Dogri (macrolanguage) */ +/*{HB_TAG('x','o','g',' '), HB_TAG('X','O','G',' ')},*/ /* Soga */ + {HB_TAG('x','p','e',' '), HB_TAG('X','P','E',' ')}, /* Liberia Kpelle -> Kpelle (Liberia) */ + {HB_TAG('x','p','e',' '), HB_TAG('K','P','L',' ')}, /* Liberia Kpelle -> Kpelle */ + {HB_TAG('x','s','l',' '), HB_TAG('S','S','L',' ')}, /* South Slavey */ + {HB_TAG('x','s','l',' '), HB_TAG('S','L','A',' ')}, /* South Slavey -> Slavey */ + {HB_TAG('x','s','l',' '), HB_TAG('A','T','H',' ')}, /* South Slavey -> Athapaskan */ + {HB_TAG('x','s','t',' '), HB_TAG('S','I','G',' ')}, /* Silt'e (retired code) -> Silte Gurage */ +/*{HB_TAG('x','u','b',' '), HB_TAG('X','U','B',' ')},*/ /* Betta Kurumba -> Bette Kuruma */ +/*{HB_TAG('x','u','j',' '), HB_TAG('X','U','J',' ')},*/ /* Jennu Kurumba -> Jennu Kuruma */ + {HB_TAG('x','u','p',' '), HB_TAG('A','T','H',' ')}, /* Upper Umpqua -> Athapaskan */ + {HB_TAG('x','w','o',' '), HB_TAG('T','O','D',' ')}, /* Written Oirat -> Todo */ + {HB_TAG('y','a','j',' '), HB_TAG('B','A','D','0')}, /* Banda-Yangere -> Banda */ + {HB_TAG('y','a','k',' '), HB_TAG_NONE }, /* Yakama != Sakha */ +/*{HB_TAG('y','a','o',' '), HB_TAG('Y','A','O',' ')},*/ /* Yao */ +/*{HB_TAG('y','a','p',' '), HB_TAG('Y','A','P',' ')},*/ /* Yapese */ + {HB_TAG('y','b','a',' '), HB_TAG_NONE }, /* Yala != Yoruba */ + {HB_TAG('y','b','b',' '), HB_TAG('B','M','L',' ')}, /* Yemba -> Bamileke */ + {HB_TAG('y','b','d',' '), HB_TAG('A','R','K',' ')}, /* Yangbye (retired code) -> Rakhine */ + {HB_TAG('y','d','d',' '), HB_TAG('J','I','I',' ')}, /* Eastern Yiddish -> Yiddish */ +/*{HB_TAG('y','g','p',' '), HB_TAG('Y','G','P',' ')},*/ /* Gepo */ + {HB_TAG('y','i','h',' '), HB_TAG('J','I','I',' ')}, /* Western Yiddish -> Yiddish */ + {HB_TAG('y','i','m',' '), HB_TAG_NONE }, /* Yimchungru Naga != Yi Modern */ +/*{HB_TAG('y','n','a',' '), HB_TAG('Y','N','A',' ')},*/ /* Aluo */ + {HB_TAG('y','o','s',' '), HB_TAG('Q','I','N',' ')}, /* Yos (retired code) -> Chin */ + {HB_TAG('y','u','a',' '), HB_TAG('M','Y','N',' ')}, /* Yucateco -> Mayan */ + {HB_TAG('y','u','e',' '), HB_TAG('Z','H','H',' ')}, /* Yue Chinese -> Chinese, Traditional, Hong Kong SAR */ +/*{HB_TAG('y','w','q',' '), HB_TAG('Y','W','Q',' ')},*/ /* Wuding-Luquan Yi */ + {HB_TAG('z','c','h',' '), HB_TAG('Z','H','A',' ')}, /* Central Hongshuihe Zhuang -> Zhuang */ + {HB_TAG('z','d','j',' '), HB_TAG('C','M','R',' ')}, /* Ngazidja Comorian -> Comorian */ +/*{HB_TAG('z','e','a',' '), HB_TAG('Z','E','A',' ')},*/ /* Zeeuws -> Zealandic */ + {HB_TAG('z','e','h',' '), HB_TAG('Z','H','A',' ')}, /* Eastern Hongshuihe Zhuang -> Zhuang */ + {HB_TAG('z','e','n',' '), HB_TAG('B','B','R',' ')}, /* Zenaga -> Berber */ + {HB_TAG('z','g','b',' '), HB_TAG('Z','H','A',' ')}, /* Guibei Zhuang -> Zhuang */ + {HB_TAG('z','g','h',' '), HB_TAG('Z','G','H',' ')}, /* Standard Moroccan Tamazight */ + {HB_TAG('z','g','h',' '), HB_TAG('B','B','R',' ')}, /* Standard Moroccan Tamazight -> Berber */ + {HB_TAG('z','g','m',' '), HB_TAG('Z','H','A',' ')}, /* Minz Zhuang -> Zhuang */ + {HB_TAG('z','g','n',' '), HB_TAG('Z','H','A',' ')}, /* Guibian Zhuang -> Zhuang */ + {HB_TAG('z','h','d',' '), HB_TAG('Z','H','A',' ')}, /* Dai Zhuang -> Zhuang */ + {HB_TAG('z','h','n',' '), HB_TAG('Z','H','A',' ')}, /* Nong Zhuang -> Zhuang */ + {HB_TAG('z','l','j',' '), HB_TAG('Z','H','A',' ')}, /* Liujiang Zhuang -> Zhuang */ + {HB_TAG('z','l','m',' '), HB_TAG('M','L','Y',' ')}, /* Malay */ + {HB_TAG('z','l','n',' '), HB_TAG('Z','H','A',' ')}, /* Lianshan Zhuang -> Zhuang */ + {HB_TAG('z','l','q',' '), HB_TAG('Z','H','A',' ')}, /* Liuqian Zhuang -> Zhuang */ + {HB_TAG('z','m','i',' '), HB_TAG('M','L','Y',' ')}, /* Negeri Sembilan Malay -> Malay */ + {HB_TAG('z','m','z',' '), HB_TAG('B','A','D','0')}, /* Mbandja -> Banda */ + {HB_TAG('z','n','d',' '), HB_TAG_NONE }, /* Zande [collection] != Zande */ + {HB_TAG('z','n','e',' '), HB_TAG('Z','N','D',' ')}, /* Zande */ + {HB_TAG('z','o','m',' '), HB_TAG('Q','I','N',' ')}, /* Zou -> Chin */ + {HB_TAG('z','q','e',' '), HB_TAG('Z','H','A',' ')}, /* Qiubei Zhuang -> Zhuang */ + {HB_TAG('z','s','m',' '), HB_TAG('M','L','Y',' ')}, /* Standard Malay -> Malay */ + {HB_TAG('z','u','m',' '), HB_TAG('L','R','C',' ')}, /* Kumzari -> Luri */ + {HB_TAG('z','y','b',' '), HB_TAG('Z','H','A',' ')}, /* Yongbei Zhuang -> Zhuang */ + {HB_TAG('z','y','g',' '), HB_TAG('Z','H','A',' ')}, /* Yang Zhuang -> Zhuang */ + {HB_TAG('z','y','j',' '), HB_TAG('Z','H','A',' ')}, /* Youjiang Zhuang -> Zhuang */ + {HB_TAG('z','y','n',' '), HB_TAG('Z','H','A',' ')}, /* Yongnan Zhuang -> Zhuang */ + {HB_TAG('z','y','p',' '), HB_TAG('Q','I','N',' ')}, /* Zyphe Chin -> Chin */ +/*{HB_TAG('z','z','a',' '), HB_TAG('Z','Z','A',' ')},*/ /* Zazaki [macrolanguage] */ + {HB_TAG('z','z','j',' '), HB_TAG('Z','H','A',' ')}, /* Zuojiang Zhuang -> Zhuang */ +}; +#endif + /** * hb_ot_tags_from_complex_language: * @lang_str: a BCP 47 language tag to convert. @@ -1633,75 +1638,81 @@ static const LangTag ot_languages[] = { * * Return value: Whether any language systems were retrieved. **/ -static bool +static inline bool hb_ot_tags_from_complex_language (const char *lang_str, const char *limit, unsigned int *count /* IN/OUT */, hb_tag_t *tags /* OUT */) { - if (subtag_matches (lang_str, limit, "-fonnapa")) - { - /* Undetermined; North American Phonetic Alphabet */ - tags[0] = HB_TAG('A','P','P','H'); /* Phonetic transcription—Americanist conventions */ - *count = 1; - return true; - } - if (subtag_matches (lang_str, limit, "-polyton")) - { - /* Modern Greek (1453-); Polytonic Greek */ - tags[0] = HB_TAG('P','G','R',' '); /* Polytonic Greek */ - *count = 1; - return true; - } - if (subtag_matches (lang_str, limit, "-arevmda")) - { - /* Armenian; Western Armenian (retired code) */ - tags[0] = HB_TAG('H','Y','E',' '); /* Armenian */ - *count = 1; - return true; - } - if (subtag_matches (lang_str, limit, "-provenc")) - { - /* Occitan (post 1500); Provençal */ - tags[0] = HB_TAG('P','R','O',' '); /* Provençal / Old Provençal */ - *count = 1; - return true; - } - if (subtag_matches (lang_str, limit, "-fonipa")) - { - /* Undetermined; International Phonetic Alphabet */ - tags[0] = HB_TAG('I','P','P','H'); /* Phonetic transcription—IPA conventions */ - *count = 1; - return true; - } - if (subtag_matches (lang_str, limit, "-geok")) - { - /* Undetermined; Khutsuri (Asomtavruli and Nuskhuri) */ - tags[0] = HB_TAG('K','G','E',' '); /* Khutsuri Georgian */ - *count = 1; - return true; - } - if (subtag_matches (lang_str, limit, "-syre")) + if (limit - lang_str >= 7) { - /* Undetermined; Syriac (Estrangelo variant) */ - tags[0] = HB_TAG('S','Y','R','E'); /* Syriac, Estrangela script-variant (equivalent to ISO 15924 'Syre') */ - *count = 1; - return true; - } - if (subtag_matches (lang_str, limit, "-syrj")) - { - /* Undetermined; Syriac (Western variant) */ - tags[0] = HB_TAG('S','Y','R','J'); /* Syriac, Western script-variant (equivalent to ISO 15924 'Syrj') */ - *count = 1; - return true; - } - if (subtag_matches (lang_str, limit, "-syrn")) - { - /* Undetermined; Syriac (Eastern variant) */ - tags[0] = HB_TAG('S','Y','R','N'); /* Syriac, Eastern script-variant (equivalent to ISO 15924 'Syrn') */ - *count = 1; - return true; + const char *p = strchr (lang_str, '-'); + if (!p || p >= limit || limit - p < 5) goto out; + if (subtag_matches (p, limit, "-fonnapa", 8)) + { + /* Undetermined; North American Phonetic Alphabet */ + tags[0] = HB_TAG('A','P','P','H'); /* Phonetic transcription—Americanist conventions */ + *count = 1; + return true; + } + if (subtag_matches (p, limit, "-polyton", 8)) + { + /* Modern Greek (1453-); Polytonic Greek */ + tags[0] = HB_TAG('P','G','R',' '); /* Polytonic Greek */ + *count = 1; + return true; + } + if (subtag_matches (p, limit, "-arevmda", 8)) + { + /* Armenian; Western Armenian (retired code) */ + tags[0] = HB_TAG('H','Y','E',' '); /* Armenian */ + *count = 1; + return true; + } + if (subtag_matches (p, limit, "-provenc", 8)) + { + /* Occitan (post 1500); Provençal */ + tags[0] = HB_TAG('P','R','O',' '); /* Provençal / Old Provençal */ + *count = 1; + return true; + } + if (subtag_matches (p, limit, "-fonipa", 7)) + { + /* Undetermined; International Phonetic Alphabet */ + tags[0] = HB_TAG('I','P','P','H'); /* Phonetic transcription—IPA conventions */ + *count = 1; + return true; + } + if (subtag_matches (p, limit, "-geok", 5)) + { + /* Undetermined; Khutsuri (Asomtavruli and Nuskhuri) */ + tags[0] = HB_TAG('K','G','E',' '); /* Khutsuri Georgian */ + *count = 1; + return true; + } + if (subtag_matches (p, limit, "-syre", 5)) + { + /* Undetermined; Syriac (Estrangelo variant) */ + tags[0] = HB_TAG('S','Y','R','E'); /* Syriac, Estrangela script-variant (equivalent to ISO 15924 'Syre') */ + *count = 1; + return true; + } + if (subtag_matches (p, limit, "-syrj", 5)) + { + /* Undetermined; Syriac (Western variant) */ + tags[0] = HB_TAG('S','Y','R','J'); /* Syriac, Western script-variant (equivalent to ISO 15924 'Syrj') */ + *count = 1; + return true; + } + if (subtag_matches (p, limit, "-syrn", 5)) + { + /* Undetermined; Syriac (Eastern variant) */ + tags[0] = HB_TAG('S','Y','R','N'); /* Syriac, Eastern script-variant (equivalent to ISO 15924 'Syrn') */ + *count = 1; + return true; + } } +out: switch (lang_str[0]) { case 'a': @@ -1714,14 +1725,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, } break; case 'c': - if (lang_matches (&lang_str[1], "do-hant-hk")) + if (lang_matches (&lang_str[1], limit, "do-hant-hk", 10)) { /* Min Dong Chinese; Han (Traditional variant); Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "do-hant-mo")) + if (lang_matches (&lang_str[1], limit, "do-hant-mo", 10)) { /* Min Dong Chinese; Han (Traditional variant); Macao */ unsigned int i; @@ -1734,14 +1745,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = i; return true; } - if (lang_matches (&lang_str[1], "jy-hant-hk")) + if (lang_matches (&lang_str[1], limit, "jy-hant-hk", 10)) { /* Jinyu Chinese; Han (Traditional variant); Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "jy-hant-mo")) + if (lang_matches (&lang_str[1], limit, "jy-hant-mo", 10)) { /* Jinyu Chinese; Han (Traditional variant); Macao */ unsigned int i; @@ -1754,14 +1765,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = i; return true; } - if (lang_matches (&lang_str[1], "mn-hant-hk")) + if (lang_matches (&lang_str[1], limit, "mn-hant-hk", 10)) { /* Mandarin Chinese; Han (Traditional variant); Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "mn-hant-mo")) + if (lang_matches (&lang_str[1], limit, "mn-hant-mo", 10)) { /* Mandarin Chinese; Han (Traditional variant); Macao */ unsigned int i; @@ -1774,14 +1785,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = i; return true; } - if (lang_matches (&lang_str[1], "np-hant-hk")) + if (lang_matches (&lang_str[1], limit, "np-hant-hk", 10)) { /* Northern Ping Chinese; Han (Traditional variant); Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "np-hant-mo")) + if (lang_matches (&lang_str[1], limit, "np-hant-mo", 10)) { /* Northern Ping Chinese; Han (Traditional variant); Macao */ unsigned int i; @@ -1794,14 +1805,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = i; return true; } - if (lang_matches (&lang_str[1], "px-hant-hk")) + if (lang_matches (&lang_str[1], limit, "px-hant-hk", 10)) { /* Pu-Xian Chinese; Han (Traditional variant); Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "px-hant-mo")) + if (lang_matches (&lang_str[1], limit, "px-hant-mo", 10)) { /* Pu-Xian Chinese; Han (Traditional variant); Macao */ unsigned int i; @@ -1814,14 +1825,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = i; return true; } - if (lang_matches (&lang_str[1], "sp-hant-hk")) + if (lang_matches (&lang_str[1], limit, "sp-hant-hk", 10)) { /* Southern Ping Chinese; Han (Traditional variant); Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "sp-hant-mo")) + if (lang_matches (&lang_str[1], limit, "sp-hant-mo", 10)) { /* Southern Ping Chinese; Han (Traditional variant); Macao */ unsigned int i; @@ -1834,14 +1845,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = i; return true; } - if (lang_matches (&lang_str[1], "zh-hant-hk")) + if (lang_matches (&lang_str[1], limit, "zh-hant-hk", 10)) { /* Huizhou Chinese; Han (Traditional variant); Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "zh-hant-mo")) + if (lang_matches (&lang_str[1], limit, "zh-hant-mo", 10)) { /* Huizhou Chinese; Han (Traditional variant); Macao */ unsigned int i; @@ -1854,14 +1865,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = i; return true; } - if (lang_matches (&lang_str[1], "zo-hant-hk")) + if (lang_matches (&lang_str[1], limit, "zo-hant-hk", 10)) { /* Min Zhong Chinese; Han (Traditional variant); Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "zo-hant-mo")) + if (lang_matches (&lang_str[1], limit, "zo-hant-mo", 10)) { /* Min Zhong Chinese; Han (Traditional variant); Macao */ unsigned int i; @@ -1874,112 +1885,112 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = i; return true; } - if (lang_matches (&lang_str[1], "do-hans")) + if (lang_matches (&lang_str[1], limit, "do-hans", 7)) { /* Min Dong Chinese; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "do-hant")) + if (lang_matches (&lang_str[1], limit, "do-hant", 7)) { /* Min Dong Chinese; Han (Traditional variant) */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "jy-hans")) + if (lang_matches (&lang_str[1], limit, "jy-hans", 7)) { /* Jinyu Chinese; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "jy-hant")) + if (lang_matches (&lang_str[1], limit, "jy-hant", 7)) { /* Jinyu Chinese; Han (Traditional variant) */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "mn-hans")) + if (lang_matches (&lang_str[1], limit, "mn-hans", 7)) { /* Mandarin Chinese; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "mn-hant")) + if (lang_matches (&lang_str[1], limit, "mn-hant", 7)) { /* Mandarin Chinese; Han (Traditional variant) */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "np-hans")) + if (lang_matches (&lang_str[1], limit, "np-hans", 7)) { /* Northern Ping Chinese; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "np-hant")) + if (lang_matches (&lang_str[1], limit, "np-hant", 7)) { /* Northern Ping Chinese; Han (Traditional variant) */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "px-hans")) + if (lang_matches (&lang_str[1], limit, "px-hans", 7)) { /* Pu-Xian Chinese; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "px-hant")) + if (lang_matches (&lang_str[1], limit, "px-hant", 7)) { /* Pu-Xian Chinese; Han (Traditional variant) */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "sp-hans")) + if (lang_matches (&lang_str[1], limit, "sp-hans", 7)) { /* Southern Ping Chinese; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "sp-hant")) + if (lang_matches (&lang_str[1], limit, "sp-hant", 7)) { /* Southern Ping Chinese; Han (Traditional variant) */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "zh-hans")) + if (lang_matches (&lang_str[1], limit, "zh-hans", 7)) { /* Huizhou Chinese; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "zh-hant")) + if (lang_matches (&lang_str[1], limit, "zh-hant", 7)) { /* Huizhou Chinese; Han (Traditional variant) */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "zo-hans")) + if (lang_matches (&lang_str[1], limit, "zo-hans", 7)) { /* Min Zhong Chinese; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "zo-hant")) + if (lang_matches (&lang_str[1], limit, "zo-hant", 7)) { /* Min Zhong Chinese; Han (Traditional variant) */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -1987,7 +1998,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "do-", 3) - && subtag_matches (lang_str, limit, "-hk")) + && subtag_matches (lang_str, limit, "-hk", 3)) { /* Min Dong Chinese; Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ @@ -1995,7 +2006,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "do-", 3) - && subtag_matches (lang_str, limit, "-mo")) + && subtag_matches (lang_str, limit, "-mo", 3)) { /* Min Dong Chinese; Macao */ unsigned int i; @@ -2009,7 +2020,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "do-", 3) - && subtag_matches (lang_str, limit, "-tw")) + && subtag_matches (lang_str, limit, "-tw", 3)) { /* Min Dong Chinese; Taiwan, Province of China */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2017,7 +2028,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "jy-", 3) - && subtag_matches (lang_str, limit, "-hk")) + && subtag_matches (lang_str, limit, "-hk", 3)) { /* Jinyu Chinese; Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ @@ -2025,7 +2036,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "jy-", 3) - && subtag_matches (lang_str, limit, "-mo")) + && subtag_matches (lang_str, limit, "-mo", 3)) { /* Jinyu Chinese; Macao */ unsigned int i; @@ -2039,7 +2050,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "jy-", 3) - && subtag_matches (lang_str, limit, "-tw")) + && subtag_matches (lang_str, limit, "-tw", 3)) { /* Jinyu Chinese; Taiwan, Province of China */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2047,7 +2058,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "mn-", 3) - && subtag_matches (lang_str, limit, "-hk")) + && subtag_matches (lang_str, limit, "-hk", 3)) { /* Mandarin Chinese; Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ @@ -2055,7 +2066,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "mn-", 3) - && subtag_matches (lang_str, limit, "-mo")) + && subtag_matches (lang_str, limit, "-mo", 3)) { /* Mandarin Chinese; Macao */ unsigned int i; @@ -2069,7 +2080,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "mn-", 3) - && subtag_matches (lang_str, limit, "-tw")) + && subtag_matches (lang_str, limit, "-tw", 3)) { /* Mandarin Chinese; Taiwan, Province of China */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2077,7 +2088,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "np-", 3) - && subtag_matches (lang_str, limit, "-hk")) + && subtag_matches (lang_str, limit, "-hk", 3)) { /* Northern Ping Chinese; Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ @@ -2085,7 +2096,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "np-", 3) - && subtag_matches (lang_str, limit, "-mo")) + && subtag_matches (lang_str, limit, "-mo", 3)) { /* Northern Ping Chinese; Macao */ unsigned int i; @@ -2099,7 +2110,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "np-", 3) - && subtag_matches (lang_str, limit, "-tw")) + && subtag_matches (lang_str, limit, "-tw", 3)) { /* Northern Ping Chinese; Taiwan, Province of China */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2107,7 +2118,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "px-", 3) - && subtag_matches (lang_str, limit, "-hk")) + && subtag_matches (lang_str, limit, "-hk", 3)) { /* Pu-Xian Chinese; Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ @@ -2115,7 +2126,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "px-", 3) - && subtag_matches (lang_str, limit, "-mo")) + && subtag_matches (lang_str, limit, "-mo", 3)) { /* Pu-Xian Chinese; Macao */ unsigned int i; @@ -2129,7 +2140,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "px-", 3) - && subtag_matches (lang_str, limit, "-tw")) + && subtag_matches (lang_str, limit, "-tw", 3)) { /* Pu-Xian Chinese; Taiwan, Province of China */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2137,7 +2148,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "sp-", 3) - && subtag_matches (lang_str, limit, "-hk")) + && subtag_matches (lang_str, limit, "-hk", 3)) { /* Southern Ping Chinese; Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ @@ -2145,7 +2156,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "sp-", 3) - && subtag_matches (lang_str, limit, "-mo")) + && subtag_matches (lang_str, limit, "-mo", 3)) { /* Southern Ping Chinese; Macao */ unsigned int i; @@ -2159,7 +2170,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "sp-", 3) - && subtag_matches (lang_str, limit, "-tw")) + && subtag_matches (lang_str, limit, "-tw", 3)) { /* Southern Ping Chinese; Taiwan, Province of China */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2167,7 +2178,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "zh-", 3) - && subtag_matches (lang_str, limit, "-hk")) + && subtag_matches (lang_str, limit, "-hk", 3)) { /* Huizhou Chinese; Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ @@ -2175,7 +2186,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "zh-", 3) - && subtag_matches (lang_str, limit, "-mo")) + && subtag_matches (lang_str, limit, "-mo", 3)) { /* Huizhou Chinese; Macao */ unsigned int i; @@ -2189,7 +2200,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "zh-", 3) - && subtag_matches (lang_str, limit, "-tw")) + && subtag_matches (lang_str, limit, "-tw", 3)) { /* Huizhou Chinese; Taiwan, Province of China */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2197,7 +2208,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "zo-", 3) - && subtag_matches (lang_str, limit, "-hk")) + && subtag_matches (lang_str, limit, "-hk", 3)) { /* Min Zhong Chinese; Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ @@ -2205,7 +2216,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "zo-", 3) - && subtag_matches (lang_str, limit, "-mo")) + && subtag_matches (lang_str, limit, "-mo", 3)) { /* Min Zhong Chinese; Macao */ unsigned int i; @@ -2219,7 +2230,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "zo-", 3) - && subtag_matches (lang_str, limit, "-tw")) + && subtag_matches (lang_str, limit, "-tw", 3)) { /* Min Zhong Chinese; Taiwan, Province of China */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2228,14 +2239,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, } break; case 'g': - if (lang_matches (&lang_str[1], "an-hant-hk")) + if (lang_matches (&lang_str[1], limit, "an-hant-hk", 10)) { /* Gan Chinese; Han (Traditional variant); Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "an-hant-mo")) + if (lang_matches (&lang_str[1], limit, "an-hant-mo", 10)) { /* Gan Chinese; Han (Traditional variant); Macao */ unsigned int i; @@ -2248,21 +2259,21 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = i; return true; } - if (lang_matches (&lang_str[1], "an-hans")) + if (lang_matches (&lang_str[1], limit, "an-hans", 7)) { /* Gan Chinese; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "an-hant")) + if (lang_matches (&lang_str[1], limit, "an-hant", 7)) { /* Gan Chinese; Han (Traditional variant) */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "a-latg")) + if (lang_matches (&lang_str[1], limit, "a-latg", 6)) { /* Irish; Latin (Gaelic variant) */ tags[0] = HB_TAG('I','R','T',' '); /* Irish Traditional */ @@ -2270,7 +2281,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "an-", 3) - && subtag_matches (lang_str, limit, "-hk")) + && subtag_matches (lang_str, limit, "-hk", 3)) { /* Gan Chinese; Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ @@ -2278,7 +2289,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "an-", 3) - && subtag_matches (lang_str, limit, "-mo")) + && subtag_matches (lang_str, limit, "-mo", 3)) { /* Gan Chinese; Macao */ unsigned int i; @@ -2292,7 +2303,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "an-", 3) - && subtag_matches (lang_str, limit, "-tw")) + && subtag_matches (lang_str, limit, "-tw", 3)) { /* Gan Chinese; Taiwan, Province of China */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2301,14 +2312,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, } break; case 'h': - if (lang_matches (&lang_str[1], "ak-hant-hk")) + if (lang_matches (&lang_str[1], limit, "ak-hant-hk", 10)) { /* Hakka Chinese; Han (Traditional variant); Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "ak-hant-mo")) + if (lang_matches (&lang_str[1], limit, "ak-hant-mo", 10)) { /* Hakka Chinese; Han (Traditional variant); Macao */ unsigned int i; @@ -2321,14 +2332,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = i; return true; } - if (lang_matches (&lang_str[1], "sn-hant-hk")) + if (lang_matches (&lang_str[1], limit, "sn-hant-hk", 10)) { /* Xiang Chinese; Han (Traditional variant); Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "sn-hant-mo")) + if (lang_matches (&lang_str[1], limit, "sn-hant-mo", 10)) { /* Xiang Chinese; Han (Traditional variant); Macao */ unsigned int i; @@ -2341,28 +2352,28 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = i; return true; } - if (lang_matches (&lang_str[1], "ak-hans")) + if (lang_matches (&lang_str[1], limit, "ak-hans", 7)) { /* Hakka Chinese; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "ak-hant")) + if (lang_matches (&lang_str[1], limit, "ak-hant", 7)) { /* Hakka Chinese; Han (Traditional variant) */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "sn-hans")) + if (lang_matches (&lang_str[1], limit, "sn-hans", 7)) { /* Xiang Chinese; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "sn-hant")) + if (lang_matches (&lang_str[1], limit, "sn-hant", 7)) { /* Xiang Chinese; Han (Traditional variant) */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2370,7 +2381,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "ak-", 3) - && subtag_matches (lang_str, limit, "-hk")) + && subtag_matches (lang_str, limit, "-hk", 3)) { /* Hakka Chinese; Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ @@ -2378,7 +2389,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "ak-", 3) - && subtag_matches (lang_str, limit, "-mo")) + && subtag_matches (lang_str, limit, "-mo", 3)) { /* Hakka Chinese; Macao */ unsigned int i; @@ -2392,7 +2403,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "ak-", 3) - && subtag_matches (lang_str, limit, "-tw")) + && subtag_matches (lang_str, limit, "-tw", 3)) { /* Hakka Chinese; Taiwan, Province of China */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2400,7 +2411,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "sn-", 3) - && subtag_matches (lang_str, limit, "-hk")) + && subtag_matches (lang_str, limit, "-hk", 3)) { /* Xiang Chinese; Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ @@ -2408,7 +2419,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "sn-", 3) - && subtag_matches (lang_str, limit, "-mo")) + && subtag_matches (lang_str, limit, "-mo", 3)) { /* Xiang Chinese; Macao */ unsigned int i; @@ -2422,7 +2433,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "sn-", 3) - && subtag_matches (lang_str, limit, "-tw")) + && subtag_matches (lang_str, limit, "-tw", 3)) { /* Xiang Chinese; Taiwan, Province of China */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2460,7 +2471,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, } break; case 'l': - if (lang_matches (&lang_str[1], "zh-hans")) + if (lang_matches (&lang_str[1], limit, "zh-hans", 7)) { /* Literary Chinese; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ @@ -2469,14 +2480,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, } break; case 'm': - if (lang_matches (&lang_str[1], "np-hant-hk")) + if (lang_matches (&lang_str[1], limit, "np-hant-hk", 10)) { /* Min Bei Chinese; Han (Traditional variant); Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "np-hant-mo")) + if (lang_matches (&lang_str[1], limit, "np-hant-mo", 10)) { /* Min Bei Chinese; Han (Traditional variant); Macao */ unsigned int i; @@ -2489,14 +2500,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = i; return true; } - if (lang_matches (&lang_str[1], "np-hans")) + if (lang_matches (&lang_str[1], limit, "np-hans", 7)) { /* Min Bei Chinese; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "np-hant")) + if (lang_matches (&lang_str[1], limit, "np-hant", 7)) { /* Min Bei Chinese; Han (Traditional variant) */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2504,7 +2515,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "np-", 3) - && subtag_matches (lang_str, limit, "-hk")) + && subtag_matches (lang_str, limit, "-hk", 3)) { /* Min Bei Chinese; Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ @@ -2512,7 +2523,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "np-", 3) - && subtag_matches (lang_str, limit, "-mo")) + && subtag_matches (lang_str, limit, "-mo", 3)) { /* Min Bei Chinese; Macao */ unsigned int i; @@ -2526,7 +2537,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "np-", 3) - && subtag_matches (lang_str, limit, "-tw")) + && subtag_matches (lang_str, limit, "-tw", 3)) { /* Min Bei Chinese; Taiwan, Province of China */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2534,7 +2545,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "nw-", 3) - && subtag_matches (lang_str, limit, "-th")) + && subtag_matches (lang_str, limit, "-th", 3)) { /* Mon; Thailand */ tags[0] = HB_TAG('M','O','N','T'); /* Thailand Mon */ @@ -2543,14 +2554,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, } break; case 'n': - if (lang_matches (&lang_str[1], "an-hant-hk")) + if (lang_matches (&lang_str[1], limit, "an-hant-hk", 10)) { /* Min Nan Chinese; Han (Traditional variant); Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "an-hant-mo")) + if (lang_matches (&lang_str[1], limit, "an-hant-mo", 10)) { /* Min Nan Chinese; Han (Traditional variant); Macao */ unsigned int i; @@ -2563,14 +2574,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = i; return true; } - if (lang_matches (&lang_str[1], "an-hans")) + if (lang_matches (&lang_str[1], limit, "an-hans", 7)) { /* Min Nan Chinese; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "an-hant")) + if (lang_matches (&lang_str[1], limit, "an-hant", 7)) { /* Min Nan Chinese; Han (Traditional variant) */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2578,7 +2589,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "an-", 3) - && subtag_matches (lang_str, limit, "-hk")) + && subtag_matches (lang_str, limit, "-hk", 3)) { /* Min Nan Chinese; Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ @@ -2586,7 +2597,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "an-", 3) - && subtag_matches (lang_str, limit, "-mo")) + && subtag_matches (lang_str, limit, "-mo", 3)) { /* Min Nan Chinese; Macao */ unsigned int i; @@ -2600,7 +2611,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "an-", 3) - && subtag_matches (lang_str, limit, "-tw")) + && subtag_matches (lang_str, limit, "-tw", 3)) { /* Min Nan Chinese; Taiwan, Province of China */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2624,7 +2635,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, break; case 'r': if (0 == strncmp (&lang_str[1], "o-", 2) - && subtag_matches (lang_str, limit, "-md")) + && subtag_matches (lang_str, limit, "-md", 3)) { /* Romanian; Moldova */ unsigned int i; @@ -2639,14 +2650,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, } break; case 'w': - if (lang_matches (&lang_str[1], "uu-hant-hk")) + if (lang_matches (&lang_str[1], limit, "uu-hant-hk", 10)) { /* Wu Chinese; Han (Traditional variant); Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "uu-hant-mo")) + if (lang_matches (&lang_str[1], limit, "uu-hant-mo", 10)) { /* Wu Chinese; Han (Traditional variant); Macao */ unsigned int i; @@ -2659,14 +2670,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = i; return true; } - if (lang_matches (&lang_str[1], "uu-hans")) + if (lang_matches (&lang_str[1], limit, "uu-hans", 7)) { /* Wu Chinese; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "uu-hant")) + if (lang_matches (&lang_str[1], limit, "uu-hant", 7)) { /* Wu Chinese; Han (Traditional variant) */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2674,7 +2685,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "uu-", 3) - && subtag_matches (lang_str, limit, "-hk")) + && subtag_matches (lang_str, limit, "-hk", 3)) { /* Wu Chinese; Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ @@ -2682,7 +2693,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "uu-", 3) - && subtag_matches (lang_str, limit, "-mo")) + && subtag_matches (lang_str, limit, "-mo", 3)) { /* Wu Chinese; Macao */ unsigned int i; @@ -2696,7 +2707,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "uu-", 3) - && subtag_matches (lang_str, limit, "-tw")) + && subtag_matches (lang_str, limit, "-tw", 3)) { /* Wu Chinese; Taiwan, Province of China */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2705,7 +2716,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, } break; case 'y': - if (lang_matches (&lang_str[1], "ue-hans")) + if (lang_matches (&lang_str[1], limit, "ue-hans", 7)) { /* Yue Chinese; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ @@ -2714,14 +2725,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, } break; case 'z': - if (lang_matches (&lang_str[1], "h-hant-hk")) + if (lang_matches (&lang_str[1], limit, "h-hant-hk", 9)) { /* Chinese [macrolanguage]; Han (Traditional variant); Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "h-hant-mo")) + if (lang_matches (&lang_str[1], limit, "h-hant-mo", 9)) { /* Chinese [macrolanguage]; Han (Traditional variant); Macao */ unsigned int i; @@ -2741,14 +2752,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = 1; return true; } - if (lang_matches (&lang_str[1], "h-hans")) + if (lang_matches (&lang_str[1], limit, "h-hans", 6)) { /* Chinese [macrolanguage]; Han (Simplified variant) */ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } - if (lang_matches (&lang_str[1], "h-hant")) + if (lang_matches (&lang_str[1], limit, "h-hant", 6)) { /* Chinese [macrolanguage]; Han (Traditional variant) */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2763,7 +2774,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "h-", 2) - && subtag_matches (lang_str, limit, "-hk")) + && subtag_matches (lang_str, limit, "-hk", 3)) { /* Chinese [macrolanguage]; Hong Kong */ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ @@ -2771,7 +2782,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "h-", 2) - && subtag_matches (lang_str, limit, "-mo")) + && subtag_matches (lang_str, limit, "-mo", 3)) { /* Chinese [macrolanguage]; Macao */ unsigned int i; @@ -2785,7 +2796,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, return true; } if (0 == strncmp (&lang_str[1], "h-", 2) - && subtag_matches (lang_str, limit, "-tw")) + && subtag_matches (lang_str, limit, "-tw", 3)) { /* Chinese [macrolanguage]; Taiwan, Province of China */ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ @@ -2809,7 +2820,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, * Return value: The #hb_language_t corresponding to the BCP 47 language tag, * or #HB_LANGUAGE_INVALID if @tag is not ambiguous. **/ -static hb_language_t +static inline hb_language_t hb_ot_ambiguous_tag_to_language (hb_tag_t tag) { switch (tag) diff --git a/thirdparty/harfbuzz/src/hb-ot-tag.cc b/thirdparty/harfbuzz/src/hb-ot-tag.cc index f50be97ad3..ce5cdce98b 100644 --- a/thirdparty/harfbuzz/src/hb-ot-tag.cc +++ b/thirdparty/harfbuzz/src/hb-ot-tag.cc @@ -189,48 +189,46 @@ hb_ot_tag_to_script (hb_tag_t tag) /* hb_language_t */ -static bool +static inline bool subtag_matches (const char *lang_str, const char *limit, - const char *subtag) + const char *subtag, + unsigned subtag_len) { + if (likely ((unsigned) (limit - lang_str) < subtag_len)) + return false; + do { const char *s = strstr (lang_str, subtag); if (!s || s >= limit) return false; - if (!ISALNUM (s[strlen (subtag)])) + if (!ISALNUM (s[subtag_len])) return true; - lang_str = s + strlen (subtag); + lang_str = s + subtag_len; } while (true); } -static hb_bool_t -lang_matches (const char *lang_str, const char *spec) +static bool +lang_matches (const char *lang_str, + const char *limit, + const char *spec, + unsigned spec_len) { - unsigned int len = strlen (spec); + if (likely ((unsigned) (limit - lang_str) < spec_len)) + return false; - return strncmp (lang_str, spec, len) == 0 && - (lang_str[len] == '\0' || lang_str[len] == '-'); + return strncmp (lang_str, spec, spec_len) == 0 && + (lang_str[spec_len] == '\0' || lang_str[spec_len] == '-'); } struct LangTag { - char language[4]; + hb_tag_t language; hb_tag_t tag; - int cmp (const char *a) const + int cmp (hb_tag_t a) const { - const char *b = this->language; - unsigned int da, db; - const char *p; - - p = strchr (a, '-'); - da = p ? (unsigned int) (p - a) : strlen (a); - - p = strchr (b, '-'); - db = p ? (unsigned int) (p - b) : strlen (b); - - return strncmp (a, b, hb_max (da, db)); + return a < this->language ? -1 : a > this->language ? +1 : 0; } int cmp (const LangTag *that) const { return cmp (that->language); } @@ -265,16 +263,19 @@ hb_ot_tags_from_language (const char *lang_str, unsigned int *count, hb_tag_t *tags) { - const char *s; - unsigned int tag_idx; +#ifndef HB_NO_LANGUAGE_LONG /* Check for matches of multiple subtags. */ if (hb_ot_tags_from_complex_language (lang_str, limit, count, tags)) return; +#endif /* Find a language matching in the first component. */ - s = strchr (lang_str, '-'); +#ifndef HB_NO_LANGUAGE_LONG + const char *s; s = strchr (lang_str, '-'); +#endif { +#ifndef HB_NO_LANGUAGE_LONG if (s && limit - lang_str >= 6) { const char *extlang_end = strchr (s + 1, '-'); @@ -283,17 +284,42 @@ hb_ot_tags_from_language (const char *lang_str, ISALPHA (s[1])) lang_str = s + 1; } - if (hb_sorted_array (ot_languages).bfind (lang_str, &tag_idx)) +#endif + const LangTag *ot_languages = nullptr; + unsigned ot_languages_len = 0; + const char *dash = strchr (lang_str, '-'); + unsigned first_len = dash ? dash - lang_str : limit - lang_str; + if (first_len == 2) + { + ot_languages = ot_languages2; + ot_languages_len = ARRAY_LENGTH (ot_languages2); + } +#ifndef HB_NO_LANGUAGE_LONG + else if (first_len == 3) { + ot_languages = ot_languages3; + ot_languages_len = ARRAY_LENGTH (ot_languages3); + } +#endif + + hb_tag_t lang_tag = hb_tag_from_string (lang_str, first_len); + + static hb_atomic_int_t last_tag_idx; /* Poor man's cache. */ + unsigned tag_idx = last_tag_idx.get_relaxed (); + + if (likely (tag_idx < ot_languages_len && ot_languages[tag_idx].language == lang_tag) || + hb_sorted_array (ot_languages, ot_languages_len).bfind (lang_tag, &tag_idx)) + { + last_tag_idx.set_relaxed (tag_idx); unsigned int i; while (tag_idx != 0 && - 0 == strcmp (ot_languages[tag_idx].language, ot_languages[tag_idx - 1].language)) + ot_languages[tag_idx].language == ot_languages[tag_idx - 1].language) tag_idx--; for (i = 0; i < *count && - tag_idx + i < ARRAY_LENGTH (ot_languages) && + tag_idx + i < ot_languages_len && ot_languages[tag_idx + i].tag != HB_TAG_NONE && - 0 == strcmp (ot_languages[tag_idx + i].language, ot_languages[tag_idx].language); + ot_languages[tag_idx + i].language == ot_languages[tag_idx].language; i++) tags[i] = ot_languages[tag_idx + i].tag; *count = i; @@ -301,6 +327,7 @@ hb_ot_tags_from_language (const char *lang_str, } } +#ifndef HB_NO_LANGUAGE_LONG if (!s) s = lang_str + strlen (lang_str); if (s - lang_str == 3) { @@ -309,6 +336,7 @@ hb_ot_tags_from_language (const char *lang_str, *count = 1; return; } +#endif *count = 0; } @@ -453,15 +481,29 @@ hb_ot_tag_to_language (hb_tag_t tag) if (tag == HB_OT_TAG_DEFAULT_LANGUAGE) return nullptr; +#ifndef HB_NO_LANGUAGE_LONG { hb_language_t disambiguated_tag = hb_ot_ambiguous_tag_to_language (tag); if (disambiguated_tag != HB_LANGUAGE_INVALID) return disambiguated_tag; } +#endif - for (i = 0; i < ARRAY_LENGTH (ot_languages); i++) - if (ot_languages[i].tag == tag) - return hb_language_from_string (ot_languages[i].language, -1); + char buf[4]; + for (i = 0; i < ARRAY_LENGTH (ot_languages2); i++) + if (ot_languages2[i].tag == tag) + { + hb_tag_to_string (ot_languages2[i].language, buf); + return hb_language_from_string (buf, 2); + } +#ifndef HB_NO_LANGUAGE_LONG + for (i = 0; i < ARRAY_LENGTH (ot_languages3); i++) + if (ot_languages3[i].tag == tag) + { + hb_tag_to_string (ot_languages3[i].language, buf); + return hb_language_from_string (buf, 3); + } +#endif /* Return a custom language in the form of "x-hbot-AABBCCDD". * If it's three letters long, also guess it's ISO 639-3 and lower-case and @@ -557,16 +599,28 @@ hb_ot_tags_to_script_and_language (hb_tag_t script_tag, static inline void test_langs_sorted () { - for (unsigned int i = 1; i < ARRAY_LENGTH (ot_languages); i++) + for (unsigned int i = 1; i < ARRAY_LENGTH (ot_languages2); i++) { - int c = ot_languages[i].cmp (&ot_languages[i - 1]); + int c = ot_languages2[i].cmp (&ot_languages2[i - 1]); if (c > 0) { - fprintf (stderr, "ot_languages not sorted at index %d: %s %d %s\n", - i, ot_languages[i-1].language, c, ot_languages[i].language); + fprintf (stderr, "ot_languages2 not sorted at index %d: %08x %d %08x\n", + i, ot_languages2[i-1].language, c, ot_languages2[i].language); abort(); } } +#ifndef HB_NO_LANGUAGE_LONG + for (unsigned int i = 1; i < ARRAY_LENGTH (ot_languages3); i++) + { + int c = ot_languages3[i].cmp (&ot_languages3[i - 1]); + if (c > 0) + { + fprintf (stderr, "ot_languages3 not sorted at index %d: %08x %d %08x\n", + i, ot_languages3[i-1].language, c, ot_languages3[i].language); + abort(); + } + } +#endif } int diff --git a/thirdparty/harfbuzz/src/hb-ot-var-fvar-table.hh b/thirdparty/harfbuzz/src/hb-ot-var-fvar-table.hh index e066558683..c5c476bc0e 100644 --- a/thirdparty/harfbuzz/src/hb-ot-var-fvar-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-var-fvar-table.hh @@ -213,7 +213,7 @@ struct fvar if (!axis_index) axis_index = &i; *axis_index = HB_OT_VAR_NO_AXIS_INDEX; auto axes = get_axes (); - return axes.lfind (tag, axis_index) && (axes[*axis_index].get_axis_deprecated (info), true); + return axes.lfind (tag, axis_index) && ((void) axes[*axis_index].get_axis_deprecated (info), true); } #endif bool @@ -221,7 +221,7 @@ struct fvar { unsigned i; auto axes = get_axes (); - return axes.lfind (tag, &i) && (axes[i].get_axis_info (i, info), true); + return axes.lfind (tag, &i) && ((void) axes[i].get_axis_info (i, info), true); } int normalize_axis_value (unsigned int axis_index, float v) const diff --git a/thirdparty/harfbuzz/src/hb-ot-var-gvar-table.hh b/thirdparty/harfbuzz/src/hb-ot-var-gvar-table.hh index 618cec08fb..bf1039d1d6 100644 --- a/thirdparty/harfbuzz/src/hb-ot-var-gvar-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-var-gvar-table.hh @@ -45,9 +45,10 @@ struct contour_point_t void translate (const contour_point_t &p) { x += p.x; y += p.y; } - uint8_t flag; - float x, y; - bool is_end_point; + float x = 0.f; + float y = 0.f; + uint8_t flag = 0; + bool is_end_point = false; }; struct contour_point_vector_t : hb_vector_t<contour_point_t> @@ -55,16 +56,24 @@ struct contour_point_vector_t : hb_vector_t<contour_point_t> void extend (const hb_array_t<contour_point_t> &a) { unsigned int old_len = length; - resize (old_len + a.length); - for (unsigned int i = 0; i < a.length; i++) - (*this)[old_len + i] = a[i]; + if (unlikely (!resize (old_len + a.length))) + return; + auto arrayZ = this->arrayZ + old_len; + unsigned count = a.length; + for (unsigned int i = 0; i < count; i++) + arrayZ[i] = a.arrayZ[i]; } void transform (const float (&matrix)[4]) { - for (unsigned int i = 0; i < length; i++) + if (matrix[0] == 1.f && matrix[1] == 0.f && + matrix[2] == 0.f && matrix[3] == 1.f) + return; + auto arrayZ = this->arrayZ; + unsigned count = length; + for (unsigned i = 0; i < count; i++) { - contour_point_t &p = (*this)[i]; + contour_point_t &p = arrayZ[i]; float x_ = p.x * matrix[0] + p.y * matrix[2]; p.y = p.x * matrix[1] + p.y * matrix[3]; p.x = x_; @@ -73,8 +82,12 @@ struct contour_point_vector_t : hb_vector_t<contour_point_t> void translate (const contour_point_t& delta) { - for (unsigned int i = 0; i < length; i++) - (*this)[i].translate (delta); + if (delta.x == 0.f && delta.y == 0.f) + return; + auto arrayZ = this->arrayZ; + unsigned count = length; + for (unsigned i = 0; i < count; i++) + arrayZ[i].translate (delta); } }; @@ -89,7 +102,7 @@ struct TupleVariationHeader const TupleVariationHeader &get_next (unsigned axis_count) const { return StructAtOffset<TupleVariationHeader> (this, get_size (axis_count)); } - float calculate_scalar (const int *coords, unsigned int coord_count, + float calculate_scalar (hb_array_t<int> coords, unsigned int coord_count, const hb_array_t<const F2DOT14> shared_tuples) const { hb_array_t<const F2DOT14> peak_tuple; @@ -208,7 +221,7 @@ struct GlyphVariationData { const HBUINT8 *base = &(var_data+var_data->data); const HBUINT8 *p = base; - if (!unpack_points (p, shared_indices, var_data_bytes)) return false; + if (!unpack_points (p, shared_indices, (const HBUINT8 *) (var_data_bytes.arrayZ + var_data_bytes.length))) return false; data_offset = p - base; } return true; @@ -258,7 +271,7 @@ struct GlyphVariationData static bool unpack_points (const HBUINT8 *&p /* IN/OUT */, hb_vector_t<unsigned int> &points /* OUT */, - const hb_bytes_t &bytes) + const HBUINT8 *end) { enum packed_point_flag_t { @@ -266,21 +279,21 @@ struct GlyphVariationData POINT_RUN_COUNT_MASK = 0x7F }; - if (unlikely (!bytes.check_range (p))) return false; + if (unlikely (p + 1 > end)) return false; uint16_t count = *p++; if (count & POINTS_ARE_WORDS) { - if (unlikely (!bytes.check_range (p))) return false; + if (unlikely (p + 1 > end)) return false; count = ((count & POINT_RUN_COUNT_MASK) << 8) | *p++; } - points.resize (count); + if (unlikely (!points.resize (count))) return false; unsigned int n = 0; uint16_t i = 0; while (i < count) { - if (unlikely (!bytes.check_range (p))) return false; + if (unlikely (p + 1 > end)) return false; uint16_t j; uint8_t control = *p++; uint16_t run_count = (control & POINT_RUN_COUNT_MASK) + 1; @@ -288,8 +301,7 @@ struct GlyphVariationData { for (j = 0; j < run_count && i < count; j++, i++) { - if (unlikely (!bytes.check_range ((const HBUINT16 *) p))) - return false; + if (unlikely (p + HBUINT16::static_size > end)) return false; n += *(const HBUINT16 *)p; points[i] = n; p += HBUINT16::static_size; @@ -299,7 +311,7 @@ struct GlyphVariationData { for (j = 0; j < run_count && i < count; j++, i++) { - if (unlikely (!bytes.check_range (p))) return false; + if (unlikely (p + 1 > end)) return false; n += *p++; points[i] = n; } @@ -311,7 +323,7 @@ struct GlyphVariationData static bool unpack_deltas (const HBUINT8 *&p /* IN/OUT */, hb_vector_t<int> &deltas /* IN/OUT */, - const hb_bytes_t &bytes) + const HBUINT8 *end) { enum packed_delta_flag_t { @@ -324,7 +336,7 @@ struct GlyphVariationData unsigned int count = deltas.length; while (i < count) { - if (unlikely (!bytes.check_range (p))) return false; + if (unlikely (p + 1 > end)) return false; uint8_t control = *p++; unsigned int run_count = (control & DELTA_RUN_COUNT_MASK) + 1; unsigned int j; @@ -334,16 +346,14 @@ struct GlyphVariationData else if (control & DELTAS_ARE_WORDS) for (j = 0; j < run_count && i < count; j++, i++) { - if (unlikely (!bytes.check_range ((const HBUINT16 *) p))) - return false; + if (unlikely (p + HBUINT16::static_size > end)) return false; deltas[i] = *(const HBINT16 *) p; p += HBUINT16::static_size; } else for (j = 0; j < run_count && i < count; j++, i++) { - if (unlikely (!bytes.check_range (p))) - return false; + if (unlikely (p + 1 > end)) return false; deltas[i] = *(const HBINT8 *) p++; } if (j < run_count) @@ -390,13 +400,10 @@ struct gvar { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && (version.major == 1) && - (glyphCount == c->get_num_glyphs ()) && sharedTuples.sanitize (c, this, axisCount * sharedTupleCount) && (is_long_offset () ? c->check_array (get_long_offset_array (), glyphCount+1) : - c->check_array (get_short_offset_array (), glyphCount+1)) && - c->check_array (((const HBUINT8*)&(this+dataZ)) + get_offset (0), - get_offset (glyphCount) - get_offset (0))); + c->check_array (get_short_offset_array (), glyphCount+1))); } /* GlyphVariationData not sanitized here; must be checked while accessing each glyph variation data */ @@ -482,7 +489,9 @@ struct gvar const hb_bytes_t get_glyph_var_data_bytes (hb_blob_t *blob, hb_codepoint_t glyph) const { unsigned start_offset = get_offset (glyph); - unsigned length = get_offset (glyph+1) - start_offset; + unsigned end_offset = get_offset (glyph+1); + if (unlikely (end_offset < start_offset)) return hb_bytes_t (); + unsigned length = end_offset - start_offset; hb_bytes_t var_data = blob->as_bytes ().sub_array (((unsigned) dataZ) + start_offset, length); return likely (var_data.length >= GlyphVariationData::min_size) ? var_data : hb_bytes_t (); } @@ -490,7 +499,10 @@ struct gvar bool is_long_offset () const { return flags & 1; } unsigned get_offset (unsigned i) const - { return is_long_offset () ? get_long_offset_array ()[i] : get_short_offset_array ()[i] * 2; } + { + if (unlikely (i > glyphCount)) return 0; + return is_long_offset () ? get_long_offset_array ()[i] : get_short_offset_array ()[i] * 2; + } const HBUINT32 * get_long_offset_array () const { return (const HBUINT32 *) &offsetZ; } const HBUINT16 *get_short_offset_array () const { return (const HBUINT16 *) &offsetZ; } @@ -503,19 +515,17 @@ struct gvar ~accelerator_t () { table.destroy (); } private: - struct x_getter { static float get (const contour_point_t &p) { return p.x; } }; - struct y_getter { static float get (const contour_point_t &p) { return p.y; } }; - template <typename T> static float infer_delta (const hb_array_t<contour_point_t> points, const hb_array_t<contour_point_t> deltas, - unsigned int target, unsigned int prev, unsigned int next) + unsigned int target, unsigned int prev, unsigned int next, + float contour_point_t::*m) { - float target_val = T::get (points[target]); - float prev_val = T::get (points[prev]); - float next_val = T::get (points[next]); - float prev_delta = T::get (deltas[prev]); - float next_delta = T::get (deltas[next]); + float target_val = points[target].*m; + float prev_val = points[prev].*m; + float next_val = points[next].*m; + float prev_delta = deltas[prev].*m; + float next_delta = deltas[next].*m; if (prev_val == next_val) return (prev_delta == next_delta) ? prev_delta : 0.f; @@ -526,7 +536,7 @@ struct gvar /* linear interpolation */ float r = (target_val - prev_val) / (next_val - prev_val); - return (1.f - r) * prev_delta + r * next_delta; + return prev_delta + r * (next_delta - prev_delta); } static unsigned int next_index (unsigned int i, unsigned int start, unsigned int end) @@ -536,8 +546,7 @@ struct gvar bool apply_deltas_to_points (hb_codepoint_t glyph, hb_font_t *font, const hb_array_t<contour_point_t> points) const { - /* num_coords should exactly match gvar's axisCount due to how GlyphVariationData tuples are aligned */ - if (!font->num_coords || font->num_coords != table->axisCount) return true; + if (!font->num_coords) return true; if (unlikely (glyph >= table->glyphCount)) return true; @@ -551,21 +560,25 @@ struct gvar /* Save original points for inferred delta calculation */ contour_point_vector_t orig_points; - orig_points.resize (points.length); + if (unlikely (!orig_points.resize (points.length))) return false; for (unsigned int i = 0; i < orig_points.length; i++) - orig_points[i] = points[i]; + orig_points.arrayZ[i] = points.arrayZ[i]; contour_point_vector_t deltas; /* flag is used to indicate referenced point */ - deltas.resize (points.length); + if (unlikely (!deltas.resize (points.length))) return false; hb_vector_t<unsigned> end_points; for (unsigned i = 0; i < points.length; ++i) if (points[i].is_end_point) end_points.push (i); - int *coords = font->coords; - unsigned num_coords = font->num_coords; + auto coords = hb_array (font->coords, font->num_coords); + unsigned num_coords = table->axisCount; hb_array_t<const F2DOT14> shared_tuples = (table+table->sharedTuples).as_array (table->sharedTupleCount * table->axisCount); + + hb_vector_t<unsigned int> private_indices; + hb_vector_t<int> x_deltas; + hb_vector_t<int> y_deltas; do { float scalar = iterator.current_tuple->calculate_scalar (coords, num_coords, shared_tuples); @@ -575,33 +588,30 @@ struct gvar if (unlikely (!iterator.var_data_bytes.check_range (p, length))) return false; - hb_bytes_t bytes ((const char *) p, length); - hb_vector_t<unsigned int> private_indices; + const HBUINT8 *end = p + length; + bool has_private_points = iterator.current_tuple->has_private_points (); if (has_private_points && - !GlyphVariationData::unpack_points (p, private_indices, bytes)) + !GlyphVariationData::unpack_points (p, private_indices, end)) return false; const hb_array_t<unsigned int> &indices = has_private_points ? private_indices : shared_indices; bool apply_to_all = (indices.length == 0); unsigned int num_deltas = apply_to_all ? points.length : indices.length; - hb_vector_t<int> x_deltas; - x_deltas.resize (num_deltas); - if (!GlyphVariationData::unpack_deltas (p, x_deltas, bytes)) - return false; - hb_vector_t<int> y_deltas; - y_deltas.resize (num_deltas); - if (!GlyphVariationData::unpack_deltas (p, y_deltas, bytes)) - return false; + if (unlikely (!x_deltas.resize (num_deltas))) return false; + if (unlikely (!GlyphVariationData::unpack_deltas (p, x_deltas, end))) return false; + if (unlikely (!y_deltas.resize (num_deltas))) return false; + if (unlikely (!GlyphVariationData::unpack_deltas (p, y_deltas, end))) return false; for (unsigned int i = 0; i < deltas.length; i++) deltas[i].init (); for (unsigned int i = 0; i < num_deltas; i++) { unsigned int pt_index = apply_to_all ? i : indices[i]; - deltas[pt_index].flag = 1; /* this point is referenced, i.e., explicit deltas specified */ - deltas[pt_index].x += x_deltas[i] * scalar; - deltas[pt_index].y += y_deltas[i] * scalar; + if (unlikely (pt_index >= deltas.length)) continue; + deltas.arrayZ[pt_index].flag = 1; /* this point is referenced, i.e., explicit deltas specified */ + deltas.arrayZ[pt_index].x += x_deltas.arrayZ[i] * scalar; + deltas.arrayZ[pt_index].y += y_deltas.arrayZ[i] * scalar; } /* infer deltas for unreferenced points */ @@ -645,20 +655,20 @@ struct gvar { i = next_index (i, start_point, end_point); if (i == next) break; - deltas[i].x = infer_delta<x_getter> (orig_points.as_array (), deltas.as_array (), i, prev, next); - deltas[i].y = infer_delta<y_getter> (orig_points.as_array (), deltas.as_array (), i, prev, next); + deltas[i].x = infer_delta (orig_points.as_array (), deltas.as_array (), i, prev, next, &contour_point_t::x); + deltas[i].y = infer_delta (orig_points.as_array (), deltas.as_array (), i, prev, next, &contour_point_t::y); if (--unref_count == 0) goto no_more_gaps; } } -no_more_gaps: + no_more_gaps: start_point = end_point + 1; } /* apply specified / inferred deltas to points */ for (unsigned int i = 0; i < points.length; i++) { - points[i].x += deltas[i].x; - points[i].y += deltas[i].y; + points.arrayZ[i].x += deltas.arrayZ[i].x; + points.arrayZ[i].y += deltas.arrayZ[i].y; } } while (iterator.move_to_next ()); @@ -696,7 +706,7 @@ no_more_gaps: offsetZ; /* Offsets from the start of the GlyphVariationData array * to each GlyphVariationData table. */ public: - DEFINE_SIZE_MIN (20); + DEFINE_SIZE_ARRAY (20, offsetZ); }; struct gvar_accelerator_t : gvar::accelerator_t { diff --git a/thirdparty/harfbuzz/src/hb-ot-var-hvar-table.hh b/thirdparty/harfbuzz/src/hb-ot-var-hvar-table.hh index e9d90352f0..56efcdbee9 100644 --- a/thirdparty/harfbuzz/src/hb-ot-var-hvar-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-var-hvar-table.hh @@ -319,10 +319,15 @@ struct HVARVVAR hvar_plan.index_map_plans.as_array ())); } - float get_advance_var (hb_codepoint_t glyph, hb_font_t *font) const + float get_advance_var (hb_codepoint_t glyph, + hb_font_t *font, + VariationStore::cache_t *store_cache = nullptr) const { uint32_t varidx = (this+advMap).map (glyph); - return (this+varStore).get_delta (varidx, font->coords, font->num_coords); + return (this+varStore).get_delta (varidx, + font->coords, + font->num_coords, + store_cache); } float get_side_bearing_var (hb_codepoint_t glyph, @@ -335,7 +340,7 @@ struct HVARVVAR bool has_side_bearing_deltas () const { return lsbMap && rsbMap; } - protected: + public: FixedVersion<>version; /* Version of the metrics variation table * initially set to 0x00010000u */ Offset32To<VariationStore> diff --git a/thirdparty/harfbuzz/src/hb-priority-queue.hh b/thirdparty/harfbuzz/src/hb-priority-queue.hh index 7d799ae906..ffb86e30ae 100644 --- a/thirdparty/harfbuzz/src/hb-priority-queue.hh +++ b/thirdparty/harfbuzz/src/hb-priority-queue.hh @@ -38,18 +38,11 @@ */ struct hb_priority_queue_t { - HB_DELETE_COPY_ASSIGN (hb_priority_queue_t); - hb_priority_queue_t () { init (); } - ~hb_priority_queue_t () { fini (); } - private: typedef hb_pair_t<int64_t, unsigned> item_t; hb_vector_t<item_t> heap; public: - void init () { heap.init (); } - - void fini () { heap.fini (); } void reset () { heap.resize (0); } @@ -58,14 +51,17 @@ struct hb_priority_queue_t void insert (int64_t priority, unsigned value) { heap.push (item_t (priority, value)); + if (unlikely (heap.in_error ())) return; bubble_up (heap.length - 1); } item_t pop_minimum () { - item_t result = heap[0]; + assert (!is_empty ()); + + item_t result = heap.arrayZ[0]; - heap[0] = heap[heap.length - 1]; + heap.arrayZ[0] = heap.arrayZ[heap.length - 1]; heap.shrink (heap.length - 1); bubble_down (0); @@ -104,6 +100,8 @@ struct hb_priority_queue_t void bubble_down (unsigned index) { + assert (index <= heap.length); + unsigned left = left_child (index); unsigned right = right_child (index); @@ -113,11 +111,11 @@ struct hb_priority_queue_t return; bool has_right = right < heap.length; - if (heap[index].first <= heap[left].first - && (!has_right || heap[index].first <= heap[right].first)) + if (heap.arrayZ[index].first <= heap.arrayZ[left].first + && (!has_right || heap[index].first <= heap.arrayZ[right].first)) return; - if (!has_right || heap[left].first < heap[right].first) + if (!has_right || heap.arrayZ[left].first < heap.arrayZ[right].first) { swap (index, left); bubble_down (left); @@ -130,10 +128,12 @@ struct hb_priority_queue_t void bubble_up (unsigned index) { + assert (index <= heap.length); + if (index == 0) return; unsigned parent_index = parent (index); - if (heap[parent_index].first <= heap[index].first) + if (heap.arrayZ[parent_index].first <= heap.arrayZ[index].first) return; swap (index, parent_index); @@ -142,9 +142,9 @@ struct hb_priority_queue_t void swap (unsigned a, unsigned b) { - item_t temp = heap[a]; - heap[a] = heap[b]; - heap[b] = temp; + assert (a <= heap.length); + assert (b <= heap.length); + hb_swap (heap.arrayZ[a], heap.arrayZ[b]); } }; diff --git a/thirdparty/harfbuzz/src/hb-repacker.hh b/thirdparty/harfbuzz/src/hb-repacker.hh index 2a9e75c45b..683a441ec3 100644 --- a/thirdparty/harfbuzz/src/hb-repacker.hh +++ b/thirdparty/harfbuzz/src/hb-repacker.hh @@ -32,1074 +32,18 @@ #include "hb-priority-queue.hh" #include "hb-serialize.hh" #include "hb-vector.hh" +#include "graph/graph.hh" +#include "graph/serialize.hh" + +using graph::graph_t; /* * For a detailed writeup on the overflow resolution algorithm see: * docs/repacker.md */ -struct graph_t -{ - struct vertex_t - { - hb_serialize_context_t::object_t obj; - int64_t distance = 0 ; - int64_t space = 0 ; - hb_vector_t<unsigned> parents; - unsigned start = 0; - unsigned end = 0; - unsigned priority = 0; - - bool is_shared () const - { - return parents.length > 1; - } - - unsigned incoming_edges () const - { - return parents.length; - } - - void remove_parent (unsigned parent_index) - { - for (unsigned i = 0; i < parents.length; i++) - { - if (parents[i] != parent_index) continue; - parents.remove (i); - break; - } - } - - void remap_parents (const hb_vector_t<unsigned>& id_map) - { - for (unsigned i = 0; i < parents.length; i++) - parents[i] = id_map[parents[i]]; - } - - void remap_parent (unsigned old_index, unsigned new_index) - { - for (unsigned i = 0; i < parents.length; i++) - { - if (parents[i] == old_index) - parents[i] = new_index; - } - } - - bool is_leaf () const - { - return !obj.real_links.length && !obj.virtual_links.length; - } - - bool raise_priority () - { - if (has_max_priority ()) return false; - priority++; - return true; - } - - bool has_max_priority () const { - return priority >= 3; - } - - int64_t modified_distance (unsigned order) const - { - // TODO(garretrieger): once priority is high enough, should try - // setting distance = 0 which will force to sort immediately after - // it's parent where possible. - - int64_t modified_distance = - hb_min (hb_max(distance + distance_modifier (), 0), 0x7FFFFFFFFFF); - if (has_max_priority ()) { - modified_distance = 0; - } - return (modified_distance << 18) | (0x003FFFF & order); - } - - int64_t distance_modifier () const - { - if (!priority) return 0; - int64_t table_size = obj.tail - obj.head; - - if (priority == 1) - return -table_size / 2; - - return -table_size; - } - }; - - struct overflow_record_t - { - unsigned parent; - unsigned child; - }; - - /* - * A topological sorting of an object graph. Ordered - * in reverse serialization order (first object in the - * serialization is at the end of the list). This matches - * the 'packed' object stack used internally in the - * serializer - */ - template<typename T> - graph_t (const T& objects) - : parents_invalid (true), - distance_invalid (true), - positions_invalid (true), - successful (true) - { - num_roots_for_space_.push (1); - bool removed_nil = false; - for (unsigned i = 0; i < objects.length; i++) - { - // TODO(grieger): check all links point to valid objects. - - // If this graph came from a serialization buffer object 0 is the - // nil object. We don't need it for our purposes here so drop it. - if (i == 0 && !objects[i]) - { - removed_nil = true; - continue; - } - - vertex_t* v = vertices_.push (); - if (check_success (!vertices_.in_error ())) - v->obj = *objects[i]; - if (!removed_nil) continue; - // Fix indices to account for removed nil object. - for (auto& l : v->obj.all_links_writer ()) { - l.objidx--; - } - } - } - - ~graph_t () - { - vertices_.fini (); - } - - bool in_error () const - { - return !successful || - vertices_.in_error () || - num_roots_for_space_.in_error (); - } - - const vertex_t& root () const - { - return vertices_[root_idx ()]; - } - - unsigned root_idx () const - { - // Object graphs are in reverse order, the first object is at the end - // of the vector. Since the graph is topologically sorted it's safe to - // assume the first object has no incoming edges. - return vertices_.length - 1; - } - - const hb_serialize_context_t::object_t& object(unsigned i) const - { - return vertices_[i].obj; - } - - /* - * serialize graph into the provided serialization buffer. - */ - hb_blob_t* serialize () const - { - hb_vector_t<char> buffer; - size_t size = serialized_length (); - if (!buffer.alloc (size)) { - DEBUG_MSG (SUBSET_REPACK, nullptr, "Unable to allocate output buffer."); - return nullptr; - } - hb_serialize_context_t c((void *) buffer, size); - - c.start_serialize<void> (); - for (unsigned i = 0; i < vertices_.length; i++) { - c.push (); - - size_t size = vertices_[i].obj.tail - vertices_[i].obj.head; - char* start = c.allocate_size <char> (size); - if (!start) { - DEBUG_MSG (SUBSET_REPACK, nullptr, "Buffer out of space."); - return nullptr; - } - - memcpy (start, vertices_[i].obj.head, size); - - // Only real links needs to be serialized. - for (const auto& link : vertices_[i].obj.real_links) - serialize_link (link, start, &c); - - // All duplications are already encoded in the graph, so don't - // enable sharing during packing. - c.pop_pack (false); - } - c.end_serialize (); - - if (c.in_error ()) { - DEBUG_MSG (SUBSET_REPACK, nullptr, "Error during serialization. Err flag: %d", - c.errors); - return nullptr; - } - - return c.copy_blob (); - } - - /* - * Generates a new topological sorting of graph using Kahn's - * algorithm: https://en.wikipedia.org/wiki/Topological_sorting#Algorithms - */ - void sort_kahn () - { - positions_invalid = true; - - if (vertices_.length <= 1) { - // Graph of 1 or less doesn't need sorting. - return; - } - - hb_vector_t<unsigned> queue; - hb_vector_t<vertex_t> sorted_graph; - if (unlikely (!check_success (sorted_graph.resize (vertices_.length)))) return; - hb_vector_t<unsigned> id_map; - if (unlikely (!check_success (id_map.resize (vertices_.length)))) return; - - hb_vector_t<unsigned> removed_edges; - if (unlikely (!check_success (removed_edges.resize (vertices_.length)))) return; - update_parents (); - - queue.push (root_idx ()); - int new_id = vertices_.length - 1; - - while (!queue.in_error () && queue.length) - { - unsigned next_id = queue[0]; - queue.remove (0); - - vertex_t& next = vertices_[next_id]; - sorted_graph[new_id] = next; - id_map[next_id] = new_id--; - - for (const auto& link : next.obj.all_links ()) { - removed_edges[link.objidx]++; - if (!(vertices_[link.objidx].incoming_edges () - removed_edges[link.objidx])) - queue.push (link.objidx); - } - } - - check_success (!queue.in_error ()); - check_success (!sorted_graph.in_error ()); - if (!check_success (new_id == -1)) - print_orphaned_nodes (); - - remap_all_obj_indices (id_map, &sorted_graph); - - hb_swap (vertices_, sorted_graph); - sorted_graph.fini (); - } - - /* - * Generates a new topological sorting of graph ordered by the shortest - * distance to each node. - */ - void sort_shortest_distance () - { - positions_invalid = true; - - if (vertices_.length <= 1) { - // Graph of 1 or less doesn't need sorting. - return; - } - - update_distances (); - - hb_priority_queue_t queue; - hb_vector_t<vertex_t> sorted_graph; - if (unlikely (!check_success (sorted_graph.resize (vertices_.length)))) return; - hb_vector_t<unsigned> id_map; - if (unlikely (!check_success (id_map.resize (vertices_.length)))) return; - - hb_vector_t<unsigned> removed_edges; - if (unlikely (!check_success (removed_edges.resize (vertices_.length)))) return; - update_parents (); - - queue.insert (root ().modified_distance (0), root_idx ()); - int new_id = root_idx (); - unsigned order = 1; - while (!queue.in_error () && !queue.is_empty ()) - { - unsigned next_id = queue.pop_minimum().second; - - vertex_t& next = vertices_[next_id]; - sorted_graph[new_id] = next; - id_map[next_id] = new_id--; - - for (const auto& link : next.obj.all_links ()) { - removed_edges[link.objidx]++; - if (!(vertices_[link.objidx].incoming_edges () - removed_edges[link.objidx])) - // Add the order that the links were encountered to the priority. - // This ensures that ties between priorities objects are broken in a consistent - // way. More specifically this is set up so that if a set of objects have the same - // distance they'll be added to the topological order in the order that they are - // referenced from the parent object. - queue.insert (vertices_[link.objidx].modified_distance (order++), - link.objidx); - } - } - - check_success (!queue.in_error ()); - check_success (!sorted_graph.in_error ()); - if (!check_success (new_id == -1)) - print_orphaned_nodes (); - - remap_all_obj_indices (id_map, &sorted_graph); - - hb_swap (vertices_, sorted_graph); - sorted_graph.fini (); - } - - /* - * Assign unique space numbers to each connected subgraph of 32 bit offset(s). - */ - bool assign_32bit_spaces () - { - unsigned root_index = root_idx (); - hb_set_t visited; - hb_set_t roots; - for (unsigned i = 0; i <= root_index; i++) - { - // Only real links can form 32 bit spaces - for (auto& l : vertices_[i].obj.real_links) - { - if (l.width == 4 && !l.is_signed) - { - roots.add (l.objidx); - find_subgraph (l.objidx, visited); - } - } - } - - // Mark everything not in the subgraphs of 32 bit roots as visited. - // This prevents 32 bit subgraphs from being connected via nodes not in the 32 bit subgraphs. - visited.invert (); - - if (!roots) return false; - - while (roots) - { - unsigned next = HB_SET_VALUE_INVALID; - if (unlikely (!check_success (!roots.in_error ()))) break; - if (!roots.next (&next)) break; - - hb_set_t connected_roots; - find_connected_nodes (next, roots, visited, connected_roots); - if (unlikely (!check_success (!connected_roots.in_error ()))) break; - - isolate_subgraph (connected_roots); - if (unlikely (!check_success (!connected_roots.in_error ()))) break; - - unsigned next_space = this->next_space (); - num_roots_for_space_.push (0); - for (unsigned root : connected_roots) - { - DEBUG_MSG (SUBSET_REPACK, nullptr, "Subgraph %u gets space %u", root, next_space); - vertices_[root].space = next_space; - num_roots_for_space_[next_space] = num_roots_for_space_[next_space] + 1; - distance_invalid = true; - positions_invalid = true; - } - - // TODO(grieger): special case for GSUB/GPOS use extension promotions to move 16 bit space - // into the 32 bit space as needed, instead of using isolation. - } - - - - return true; - } - - /* - * Isolates the subgraph of nodes reachable from root. Any links to nodes in the subgraph - * that originate from outside of the subgraph will be removed by duplicating the linked to - * object. - * - * Indices stored in roots will be updated if any of the roots are duplicated to new indices. - */ - bool isolate_subgraph (hb_set_t& roots) - { - update_parents (); - hb_hashmap_t<unsigned, unsigned> subgraph; - - // incoming edges to root_idx should be all 32 bit in length so we don't need to de-dup these - // set the subgraph incoming edge count to match all of root_idx's incoming edges - hb_set_t parents; - for (unsigned root_idx : roots) - { - subgraph.set (root_idx, wide_parents (root_idx, parents)); - find_subgraph (root_idx, subgraph); - } - - unsigned original_root_idx = root_idx (); - hb_hashmap_t<unsigned, unsigned> index_map; - bool made_changes = false; - for (auto entry : subgraph.iter ()) - { - const auto& node = vertices_[entry.first]; - unsigned subgraph_incoming_edges = entry.second; - - if (subgraph_incoming_edges < node.incoming_edges ()) - { - // Only de-dup objects with incoming links from outside the subgraph. - made_changes = true; - duplicate_subgraph (entry.first, index_map); - } - } - - if (!made_changes) - return false; - - if (original_root_idx != root_idx () - && parents.has (original_root_idx)) - { - // If the root idx has changed since parents was determined, update root idx in parents - parents.add (root_idx ()); - parents.del (original_root_idx); - } - - auto new_subgraph = - + subgraph.keys () - | hb_map([&] (unsigned node_idx) { - if (index_map.has (node_idx)) return index_map[node_idx]; - return node_idx; - }) - ; - - remap_obj_indices (index_map, new_subgraph); - remap_obj_indices (index_map, parents.iter (), true); - - // Update roots set with new indices as needed. - unsigned next = HB_SET_VALUE_INVALID; - while (roots.next (&next)) - { - if (index_map.has (next)) - { - roots.del (next); - roots.add (index_map[next]); - } - } - - return true; - } - - void find_subgraph (unsigned node_idx, hb_hashmap_t<unsigned, unsigned>& subgraph) - { - for (const auto& link : vertices_[node_idx].obj.all_links ()) - { - if (subgraph.has (link.objidx)) - { - subgraph.set (link.objidx, subgraph[link.objidx] + 1); - continue; - } - subgraph.set (link.objidx, 1); - find_subgraph (link.objidx, subgraph); - } - } - - void find_subgraph (unsigned node_idx, hb_set_t& subgraph) - { - if (subgraph.has (node_idx)) return; - subgraph.add (node_idx); - for (const auto& link : vertices_[node_idx].obj.all_links ()) - find_subgraph (link.objidx, subgraph); - } - - /* - * duplicates all nodes in the subgraph reachable from node_idx. Does not re-assign - * links. index_map is updated with mappings from old id to new id. If a duplication has already - * been performed for a given index, then it will be skipped. - */ - void duplicate_subgraph (unsigned node_idx, hb_hashmap_t<unsigned, unsigned>& index_map) - { - if (index_map.has (node_idx)) - return; - - index_map.set (node_idx, duplicate (node_idx)); - for (const auto& l : object (node_idx).all_links ()) { - duplicate_subgraph (l.objidx, index_map); - } - } - - /* - * Creates a copy of node_idx and returns it's new index. - */ - unsigned duplicate (unsigned node_idx) - { - positions_invalid = true; - distance_invalid = true; - - auto* clone = vertices_.push (); - auto& child = vertices_[node_idx]; - if (vertices_.in_error ()) { - return -1; - } - - clone->obj.head = child.obj.head; - clone->obj.tail = child.obj.tail; - clone->distance = child.distance; - clone->space = child.space; - clone->parents.reset (); - - unsigned clone_idx = vertices_.length - 2; - for (const auto& l : child.obj.real_links) - { - clone->obj.real_links.push (l); - vertices_[l.objidx].parents.push (clone_idx); - } - for (const auto& l : child.obj.virtual_links) - { - clone->obj.virtual_links.push (l); - vertices_[l.objidx].parents.push (clone_idx); - } - - check_success (!clone->obj.real_links.in_error ()); - check_success (!clone->obj.virtual_links.in_error ()); - - // The last object is the root of the graph, so swap back the root to the end. - // The root's obj idx does change, however since it's root nothing else refers to it. - // all other obj idx's will be unaffected. - vertex_t root = vertices_[vertices_.length - 2]; - vertices_[clone_idx] = *clone; - vertices_[vertices_.length - 1] = root; - - // Since the root moved, update the parents arrays of all children on the root. - for (const auto& l : root.obj.all_links ()) - vertices_[l.objidx].remap_parent (root_idx () - 1, root_idx ()); - - return clone_idx; - } - - /* - * Creates a copy of child and re-assigns the link from - * parent to the clone. The copy is a shallow copy, objects - * linked from child are not duplicated. - */ - bool duplicate (unsigned parent_idx, unsigned child_idx) - { - update_parents (); - - unsigned links_to_child = 0; - for (const auto& l : vertices_[parent_idx].obj.all_links ()) - { - if (l.objidx == child_idx) links_to_child++; - } - - if (vertices_[child_idx].incoming_edges () <= links_to_child) - { - // Can't duplicate this node, doing so would orphan the original one as all remaining links - // to child are from parent. - DEBUG_MSG (SUBSET_REPACK, nullptr, " Not duplicating %d => %d", - parent_idx, child_idx); - return false; - } - - DEBUG_MSG (SUBSET_REPACK, nullptr, " Duplicating %d => %d", - parent_idx, child_idx); - - unsigned clone_idx = duplicate (child_idx); - if (clone_idx == (unsigned) -1) return false; - // duplicate shifts the root node idx, so if parent_idx was root update it. - if (parent_idx == clone_idx) parent_idx++; - - auto& parent = vertices_[parent_idx]; - for (auto& l : parent.obj.all_links_writer ()) - { - if (l.objidx != child_idx) - continue; - - reassign_link (l, parent_idx, clone_idx); - } - - return true; - } - - /* - * Raises the sorting priority of all children. - */ - bool raise_childrens_priority (unsigned parent_idx) - { - DEBUG_MSG (SUBSET_REPACK, nullptr, " Raising priority of all children of %d", - parent_idx); - // This operation doesn't change ordering until a sort is run, so no need - // to invalidate positions. It does not change graph structure so no need - // to update distances or edge counts. - auto& parent = vertices_[parent_idx].obj; - bool made_change = false; - for (auto& l : parent.all_links_writer ()) - made_change |= vertices_[l.objidx].raise_priority (); - return made_change; - } - - /* - * Will any offsets overflow on graph when it's serialized? - */ - bool will_overflow (hb_vector_t<overflow_record_t>* overflows = nullptr) - { - if (overflows) overflows->resize (0); - update_positions (); - - for (int parent_idx = vertices_.length - 1; parent_idx >= 0; parent_idx--) - { - // Don't need to check virtual links for overflow - for (const auto& link : vertices_[parent_idx].obj.real_links) - { - int64_t offset = compute_offset (parent_idx, link); - if (is_valid_offset (offset, link)) - continue; - - if (!overflows) return true; - - overflow_record_t r; - r.parent = parent_idx; - r.child = link.objidx; - overflows->push (r); - } - } - - if (!overflows) return false; - return overflows->length; - } - - void print_orphaned_nodes () - { - if (!DEBUG_ENABLED(SUBSET_REPACK)) return; - - DEBUG_MSG (SUBSET_REPACK, nullptr, "Graph is not fully connected."); - parents_invalid = true; - update_parents(); - - for (unsigned i = 0; i < root_idx (); i++) - { - const auto& v = vertices_[i]; - if (!v.parents) - DEBUG_MSG (SUBSET_REPACK, nullptr, "Node %u is orphaned.", i); - } - } - - void print_overflows (const hb_vector_t<overflow_record_t>& overflows) - { - if (!DEBUG_ENABLED(SUBSET_REPACK)) return; - - update_parents (); - int limit = 10; - for (const auto& o : overflows) - { - if (!limit--) break; - const auto& parent = vertices_[o.parent]; - const auto& child = vertices_[o.child]; - DEBUG_MSG (SUBSET_REPACK, nullptr, - " overflow from " - "%4d (%4d in, %4d out, space %2d) => " - "%4d (%4d in, %4d out, space %2d)", - o.parent, - parent.incoming_edges (), - parent.obj.real_links.length + parent.obj.virtual_links.length, - space_for (o.parent), - o.child, - child.incoming_edges (), - child.obj.real_links.length + child.obj.virtual_links.length, - space_for (o.child)); - } - if (overflows.length > 10) { - DEBUG_MSG (SUBSET_REPACK, nullptr, " ... plus %d more overflows.", overflows.length - 10); - } - } - - unsigned num_roots_for_space (unsigned space) const - { - return num_roots_for_space_[space]; - } - - unsigned next_space () const - { - return num_roots_for_space_.length; - } - - void move_to_new_space (const hb_set_t& indices) - { - num_roots_for_space_.push (0); - unsigned new_space = num_roots_for_space_.length - 1; - - for (unsigned index : indices) { - auto& node = vertices_[index]; - num_roots_for_space_[node.space] = num_roots_for_space_[node.space] - 1; - num_roots_for_space_[new_space] = num_roots_for_space_[new_space] + 1; - node.space = new_space; - distance_invalid = true; - positions_invalid = true; - } - } - - unsigned space_for (unsigned index, unsigned* root = nullptr) const - { - const auto& node = vertices_[index]; - if (node.space) - { - if (root != nullptr) - *root = index; - return node.space; - } - - if (!node.parents) - { - if (root) - *root = index; - return 0; - } - - return space_for (node.parents[0], root); - } - - void err_other_error () { this->successful = false; } - - private: - - size_t serialized_length () const { - size_t total_size = 0; - for (unsigned i = 0; i < vertices_.length; i++) { - size_t size = vertices_[i].obj.tail - vertices_[i].obj.head; - total_size += size; - } - return total_size; - } - - /* - * Returns the numbers of incoming edges that are 32bits wide. - */ - unsigned wide_parents (unsigned node_idx, hb_set_t& parents) const - { - unsigned count = 0; - hb_set_t visited; - for (unsigned p : vertices_[node_idx].parents) - { - if (visited.has (p)) continue; - visited.add (p); - - // Only real links can be wide - for (const auto& l : vertices_[p].obj.real_links) - { - if (l.objidx == node_idx && l.width == 4 && !l.is_signed) - { - count++; - parents.add (p); - } - } - } - return count; - } - - bool check_success (bool success) - { return this->successful && (success || (err_other_error (), false)); } - - /* - * Creates a map from objid to # of incoming edges. - */ - void update_parents () - { - if (!parents_invalid) return; - - for (unsigned i = 0; i < vertices_.length; i++) - vertices_[i].parents.reset (); - - for (unsigned p = 0; p < vertices_.length; p++) - { - for (auto& l : vertices_[p].obj.all_links ()) - { - vertices_[l.objidx].parents.push (p); - } - } - - parents_invalid = false; - } - - /* - * compute the serialized start and end positions for each vertex. - */ - void update_positions () - { - if (!positions_invalid) return; - - unsigned current_pos = 0; - for (int i = root_idx (); i >= 0; i--) - { - auto& v = vertices_[i]; - v.start = current_pos; - current_pos += v.obj.tail - v.obj.head; - v.end = current_pos; - } - - positions_invalid = false; - } - - /* - * Finds the distance to each object in the graph - * from the initial node. - */ - void update_distances () - { - if (!distance_invalid) return; - - // Uses Dijkstra's algorithm to find all of the shortest distances. - // https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm - // - // Implementation Note: - // Since our priority queue doesn't support fast priority decreases - // we instead just add new entries into the queue when a priority changes. - // Redundant ones are filtered out later on by the visited set. - // According to https://www3.cs.stonybrook.edu/~rezaul/papers/TR-07-54.pdf - // for practical performance this is faster then using a more advanced queue - // (such as a fibonacci queue) with a fast decrease priority. - for (unsigned i = 0; i < vertices_.length; i++) - { - if (i == vertices_.length - 1) - vertices_[i].distance = 0; - else - vertices_[i].distance = hb_int_max (int64_t); - } - - hb_priority_queue_t queue; - queue.insert (0, vertices_.length - 1); - - hb_vector_t<bool> visited; - visited.resize (vertices_.length); - - while (!queue.in_error () && !queue.is_empty ()) - { - unsigned next_idx = queue.pop_minimum ().second; - if (visited[next_idx]) continue; - const auto& next = vertices_[next_idx]; - int64_t next_distance = vertices_[next_idx].distance; - visited[next_idx] = true; - - for (const auto& link : next.obj.all_links ()) - { - if (visited[link.objidx]) continue; - - const auto& child = vertices_[link.objidx].obj; - unsigned link_width = link.width ? link.width : 4; // treat virtual offsets as 32 bits wide - int64_t child_weight = (child.tail - child.head) + - ((int64_t) 1 << (link_width * 8)) * (vertices_[link.objidx].space + 1); - int64_t child_distance = next_distance + child_weight; - - if (child_distance < vertices_[link.objidx].distance) - { - vertices_[link.objidx].distance = child_distance; - queue.insert (child_distance, link.objidx); - } - } - } - - check_success (!queue.in_error ()); - if (!check_success (queue.is_empty ())) - { - print_orphaned_nodes (); - return; - } - - distance_invalid = false; - } - - int64_t compute_offset ( - unsigned parent_idx, - const hb_serialize_context_t::object_t::link_t& link) const - { - const auto& parent = vertices_[parent_idx]; - const auto& child = vertices_[link.objidx]; - int64_t offset = 0; - switch ((hb_serialize_context_t::whence_t) link.whence) { - case hb_serialize_context_t::whence_t::Head: - offset = child.start - parent.start; break; - case hb_serialize_context_t::whence_t::Tail: - offset = child.start - parent.end; break; - case hb_serialize_context_t::whence_t::Absolute: - offset = child.start; break; - } - - assert (offset >= link.bias); - offset -= link.bias; - return offset; - } - - bool is_valid_offset (int64_t offset, - const hb_serialize_context_t::object_t::link_t& link) const - { - if (unlikely (!link.width)) - // Virtual links can't overflow. - return link.is_signed || offset >= 0; - - if (link.is_signed) - { - if (link.width == 4) - return offset >= -((int64_t) 1 << 31) && offset < ((int64_t) 1 << 31); - else - return offset >= -(1 << 15) && offset < (1 << 15); - } - else - { - if (link.width == 4) - return offset >= 0 && offset < ((int64_t) 1 << 32); - else if (link.width == 3) - return offset >= 0 && offset < ((int32_t) 1 << 24); - else - return offset >= 0 && offset < (1 << 16); - } - } - - /* - * Updates a link in the graph to point to a different object. Corrects the - * parents vector on the previous and new child nodes. - */ - void reassign_link (hb_serialize_context_t::object_t::link_t& link, - unsigned parent_idx, - unsigned new_idx) - { - unsigned old_idx = link.objidx; - link.objidx = new_idx; - vertices_[old_idx].remove_parent (parent_idx); - vertices_[new_idx].parents.push (parent_idx); - } - - /* - * Updates all objidx's in all links using the provided mapping. Corrects incoming edge counts. - */ - template<typename Iterator, hb_requires (hb_is_iterator (Iterator))> - void remap_obj_indices (const hb_hashmap_t<unsigned, unsigned>& id_map, - Iterator subgraph, - bool only_wide = false) - { - if (!id_map) return; - for (unsigned i : subgraph) - { - for (auto& link : vertices_[i].obj.all_links_writer ()) - { - if (!id_map.has (link.objidx)) continue; - if (only_wide && !(link.width == 4 && !link.is_signed)) continue; - - reassign_link (link, i, id_map[link.objidx]); - } - } - } - - /* - * Updates all objidx's in all links using the provided mapping. - */ - void remap_all_obj_indices (const hb_vector_t<unsigned>& id_map, - hb_vector_t<vertex_t>* sorted_graph) const - { - for (unsigned i = 0; i < sorted_graph->length; i++) - { - (*sorted_graph)[i].remap_parents (id_map); - for (auto& link : (*sorted_graph)[i].obj.all_links_writer ()) - { - link.objidx = id_map[link.objidx]; - } - } - } - - template <typename O> void - serialize_link_of_type (const hb_serialize_context_t::object_t::link_t& link, - char* head, - hb_serialize_context_t* c) const - { - OT::Offset<O>* offset = reinterpret_cast<OT::Offset<O>*> (head + link.position); - *offset = 0; - c->add_link (*offset, - // serializer has an extra nil object at the start of the - // object array. So all id's are +1 of what our id's are. - link.objidx + 1, - (hb_serialize_context_t::whence_t) link.whence, - link.bias); - } - - void serialize_link (const hb_serialize_context_t::object_t::link_t& link, - char* head, - hb_serialize_context_t* c) const - { - switch (link.width) - { - case 0: - // Virtual links aren't serialized. - return; - case 4: - if (link.is_signed) - { - serialize_link_of_type<OT::HBINT32> (link, head, c); - } else { - serialize_link_of_type<OT::HBUINT32> (link, head, c); - } - return; - case 2: - if (link.is_signed) - { - serialize_link_of_type<OT::HBINT16> (link, head, c); - } else { - serialize_link_of_type<OT::HBUINT16> (link, head, c); - } - return; - case 3: - serialize_link_of_type<OT::HBUINT24> (link, head, c); - return; - default: - // Unexpected link width. - assert (0); - } - } - - /* - * Finds all nodes in targets that are reachable from start_idx, nodes in visited will be skipped. - * For this search the graph is treated as being undirected. - * - * Connected targets will be added to connected and removed from targets. All visited nodes - * will be added to visited. - */ - void find_connected_nodes (unsigned start_idx, - hb_set_t& targets, - hb_set_t& visited, - hb_set_t& connected) - { - if (unlikely (!check_success (!visited.in_error ()))) return; - if (visited.has (start_idx)) return; - visited.add (start_idx); - - if (targets.has (start_idx)) - { - targets.del (start_idx); - connected.add (start_idx); - } - - const auto& v = vertices_[start_idx]; - - // Graph is treated as undirected so search children and parents of start_idx - for (const auto& l : v.obj.all_links ()) - find_connected_nodes (l.objidx, targets, visited, connected); - - for (unsigned p : v.parents) - find_connected_nodes (p, targets, visited, connected); - } - - public: - // TODO(garretrieger): make private, will need to move most of offset overflow code into graph. - hb_vector_t<vertex_t> vertices_; - private: - bool parents_invalid; - bool distance_invalid; - bool positions_invalid; - bool successful; - hb_vector_t<unsigned> num_roots_for_space_; -}; static inline -bool _try_isolating_subgraphs (const hb_vector_t<graph_t::overflow_record_t>& overflows, +bool _try_isolating_subgraphs (const hb_vector_t<graph::overflow_record_t>& overflows, graph_t& sorted_graph) { unsigned space = 0; @@ -1107,7 +51,7 @@ bool _try_isolating_subgraphs (const hb_vector_t<graph_t::overflow_record_t>& ov for (int i = overflows.length - 1; i >= 0; i--) { - const graph_t::overflow_record_t& r = overflows[i]; + const graph::overflow_record_t& r = overflows[i]; unsigned root; unsigned overflow_space = sorted_graph.space_for (r.parent, &root); @@ -1149,7 +93,7 @@ bool _try_isolating_subgraphs (const hb_vector_t<graph_t::overflow_record_t>& ov } static inline -bool _process_overflows (const hb_vector_t<graph_t::overflow_record_t>& overflows, +bool _process_overflows (const hb_vector_t<graph::overflow_record_t>& overflows, hb_set_t& priority_bumped_parents, graph_t& sorted_graph) { @@ -1158,7 +102,7 @@ bool _process_overflows (const hb_vector_t<graph_t::overflow_record_t>& overflow // Try resolving the furthest overflows first. for (int i = overflows.length - 1; i >= 0; i--) { - const graph_t::overflow_record_t& r = overflows[i]; + const graph::overflow_record_t& r = overflows[i]; const auto& child = sorted_graph.vertices_[r.child]; if (child.is_shared ()) { @@ -1214,20 +158,18 @@ inline hb_blob_t* hb_resolve_overflows (const T& packed, hb_tag_t table_tag, unsigned max_rounds = 20) { - // Kahn sort is ~twice as fast as shortest distance sort and works for many fonts - // so try it first to save time. graph_t sorted_graph (packed); - sorted_graph.sort_kahn (); - if (!sorted_graph.will_overflow ()) + sorted_graph.sort_shortest_distance (); + + bool will_overflow = graph::will_overflow (sorted_graph); + if (!will_overflow) { - return sorted_graph.serialize (); + return graph::serialize (sorted_graph); } - sorted_graph.sort_shortest_distance (); - if ((table_tag == HB_OT_TAG_GPOS || table_tag == HB_OT_TAG_GSUB) - && sorted_graph.will_overflow ()) + && will_overflow) { DEBUG_MSG (SUBSET_REPACK, nullptr, "Assigning spaces to 32 bit subgraphs."); if (sorted_graph.assign_32bit_spaces ()) @@ -1235,13 +177,13 @@ hb_resolve_overflows (const T& packed, } unsigned round = 0; - hb_vector_t<graph_t::overflow_record_t> overflows; + hb_vector_t<graph::overflow_record_t> overflows; // TODO(garretrieger): select a good limit for max rounds. while (!sorted_graph.in_error () - && sorted_graph.will_overflow (&overflows) + && graph::will_overflow (sorted_graph, &overflows) && round++ < max_rounds) { DEBUG_MSG (SUBSET_REPACK, nullptr, "=== Overflow resolution round %d ===", round); - sorted_graph.print_overflows (overflows); + print_overflows (sorted_graph, overflows); hb_set_t priority_bumped_parents; @@ -1263,13 +205,13 @@ hb_resolve_overflows (const T& packed, return nullptr; } - if (sorted_graph.will_overflow ()) + if (graph::will_overflow (sorted_graph)) { DEBUG_MSG (SUBSET_REPACK, nullptr, "Offset overflow resolution failed."); return nullptr; } - return sorted_graph.serialize (); + return graph::serialize (sorted_graph); } #endif /* HB_REPACKER_HH */ diff --git a/thirdparty/harfbuzz/src/hb-serialize.hh b/thirdparty/harfbuzz/src/hb-serialize.hh index 40895a4548..cecdcdeb74 100644 --- a/thirdparty/harfbuzz/src/hb-serialize.hh +++ b/thirdparty/harfbuzz/src/hb-serialize.hh @@ -74,7 +74,7 @@ struct hb_serialize_context_t } object_t () = default; - + #ifdef HB_EXPERIMENTAL_API object_t (const hb_object_t &o) { @@ -91,6 +91,15 @@ struct hb_serialize_context_t } #endif + friend void swap (object_t& a, object_t& b) + { + hb_swap (a.head, b.head); + hb_swap (a.tail, b.tail); + hb_swap (a.next, b.next); + hb_swap (a.real_links, b.real_links); + hb_swap (a.virtual_links, b.virtual_links); + } + bool operator == (const object_t &o) const { // Virtual links aren't considered for equality since they don't affect the functionality @@ -111,10 +120,10 @@ struct hb_serialize_context_t struct link_t { unsigned width: 3; - bool is_signed: 1; + unsigned is_signed: 1; unsigned whence: 2; - unsigned position: 28; - unsigned bias; + unsigned bias : 26; + unsigned position; objidx_t objidx; link_t () = default; @@ -686,7 +695,7 @@ struct hb_serialize_context_t check_assign (off, offset, HB_SERIALIZE_ERROR_OFFSET_OVERFLOW); } - public: /* TODO Make private. */ + public: char *start, *head, *tail, *end; unsigned int debug_depth; hb_serialize_error_t errors; @@ -710,9 +719,7 @@ struct hb_serialize_context_t hb_vector_t<object_t *> packed; /* Map view of packed objects. */ - hb_hashmap_t<const object_t *, objidx_t, - const object_t *, objidx_t, - nullptr, 0> packed_map; + hb_hashmap_t<const object_t *, objidx_t> packed_map; }; #endif /* HB_SERIALIZE_HH */ diff --git a/thirdparty/harfbuzz/src/hb-set-digest.hh b/thirdparty/harfbuzz/src/hb-set-digest.hh index 7d4979b73b..fab36216e4 100644 --- a/thirdparty/harfbuzz/src/hb-set-digest.hh +++ b/thirdparty/harfbuzz/src/hb-set-digest.hh @@ -30,7 +30,7 @@ #include "hb.hh" /* - * The set digests here implement various "filters" that support + * The set-digests here implement various "filters" that support * "approximate member query". Conceptually these are like Bloom * Filter and Quotient Filter, however, much smaller, faster, and * designed to fit the requirements of our uses for glyph coverage @@ -40,13 +40,25 @@ * set of glyphs, but fully flooded and ineffective if coverage is * all over the place. * - * The frozen-set can be used instead of a digest, to trade more - * memory for 100% accuracy, but in practice, that doesn't look like - * an attractive trade-off. + * The way these are used is that the filter is first populated by + * a lookup's or subtable's Coverage table(s), and then when we + * want to apply the lookup or subtable to a glyph, before trying + * to apply, we ask the filter if the glyph may be covered. If it's + * not, we return early. + * + * We use these filters both at the lookup-level, and then again, + * at the subtable-level. Both have performance win. + * + * The main filter we use is a combination of three bits-pattern + * filters. A bits-pattern filter checks a number of bits (5 or 6) + * of the input number (glyph-id in this case) and checks whether + * its pattern is amongst the patterns of any of the accepted values. + * The accepted patterns are represented as a "long" integer. The + * check is done using four bitwise operations only. */ template <typename mask_t, unsigned int shift> -struct hb_set_digest_lowest_bits_t +struct hb_set_digest_bits_pattern_t { static constexpr unsigned mask_bytes = sizeof (mask_t); static constexpr unsigned mask_bits = sizeof (mask_t) * 8; @@ -102,7 +114,7 @@ struct hb_set_digest_lowest_bits_t bool add_sorted_array (const hb_sorted_array_t<const T>& arr) { return add_sorted_array (&arr, arr.len ()); } bool may_have (hb_codepoint_t g) const - { return !!(mask & mask_for (g)); } + { return mask & mask_for (g); } private: @@ -171,11 +183,11 @@ struct hb_set_digest_combiner_t using hb_set_digest_t = hb_set_digest_combiner_t < - hb_set_digest_lowest_bits_t<unsigned long, 4>, + hb_set_digest_bits_pattern_t<unsigned long, 4>, hb_set_digest_combiner_t < - hb_set_digest_lowest_bits_t<unsigned long, 0>, - hb_set_digest_lowest_bits_t<unsigned long, 9> + hb_set_digest_bits_pattern_t<unsigned long, 0>, + hb_set_digest_bits_pattern_t<unsigned long, 9> > > ; diff --git a/thirdparty/harfbuzz/src/hb-set.cc b/thirdparty/harfbuzz/src/hb-set.cc index 0e2c1f77ef..2d458294f8 100644 --- a/thirdparty/harfbuzz/src/hb-set.cc +++ b/thirdparty/harfbuzz/src/hb-set.cc @@ -40,7 +40,7 @@ /** - * hb_set_create: (Xconstructor) + * hb_set_create: * * Creates a new, initially empty set. * @@ -186,6 +186,7 @@ hb_set_t * hb_set_copy (const hb_set_t *set) { hb_set_t *copy = hb_set_create (); + if (unlikely (!copy)) return nullptr; copy->set (*set); return copy; } @@ -359,6 +360,23 @@ hb_set_is_equal (const hb_set_t *set, } /** + * hb_set_hash: + * @set: A set + * + * Creates a hash representing @set. + * + * Return value: + * A hash of @set. + * + * Since: 4.4.0 + **/ +HB_EXTERN unsigned int +hb_set_hash (const hb_set_t *set) +{ + return set->hash (); +} + +/** * hb_set_is_subset: * @set: A set * @larger_set: Another set diff --git a/thirdparty/harfbuzz/src/hb-set.h b/thirdparty/harfbuzz/src/hb-set.h index 10ce7c10d4..56902c267e 100644 --- a/thirdparty/harfbuzz/src/hb-set.h +++ b/thirdparty/harfbuzz/src/hb-set.h @@ -128,6 +128,9 @@ HB_EXTERN hb_bool_t hb_set_is_equal (const hb_set_t *set, const hb_set_t *other); +HB_EXTERN unsigned int +hb_set_hash (const hb_set_t *set); + HB_EXTERN hb_bool_t hb_set_is_subset (const hb_set_t *set, const hb_set_t *larger_set); diff --git a/thirdparty/harfbuzz/src/hb-set.hh b/thirdparty/harfbuzz/src/hb-set.hh index 1f05407869..7eb5e19a2a 100644 --- a/thirdparty/harfbuzz/src/hb-set.hh +++ b/thirdparty/harfbuzz/src/hb-set.hh @@ -43,8 +43,8 @@ struct hb_sparseset_t hb_sparseset_t (const hb_sparseset_t& other) : hb_sparseset_t () { set (other); } hb_sparseset_t (hb_sparseset_t&& other) : hb_sparseset_t () { s = std::move (other.s); } - hb_sparseset_t& operator= (const hb_sparseset_t& other) { set (other); return *this; } - hb_sparseset_t& operator= (hb_sparseset_t&& other) { hb_swap (*this, other); return *this; } + hb_sparseset_t& operator = (const hb_sparseset_t& other) { set (other); return *this; } + hb_sparseset_t& operator = (hb_sparseset_t&& other) { s = std::move (other.s); return *this; } friend void swap (hb_sparseset_t& a, hb_sparseset_t& b) { hb_swap (a.s, b.s); } hb_sparseset_t (std::initializer_list<hb_codepoint_t> lst) : hb_sparseset_t () @@ -53,7 +53,7 @@ struct hb_sparseset_t add (item); } template <typename Iterable, - hb_requires (hb_is_iterable (Iterable))> + hb_requires (hb_is_iterable (Iterable))> hb_sparseset_t (const Iterable &o) : hb_sparseset_t () { hb_copy (o, *this); @@ -77,10 +77,12 @@ struct hb_sparseset_t void err () { s.err (); } bool in_error () const { return s.in_error (); } + void alloc (unsigned sz) { s.alloc (sz); } void reset () { s.reset (); } void clear () { s.clear (); } void invert () { s.invert (); } bool is_empty () const { return s.is_empty (); } + uint32_t hash () const { return s.hash (); } void add (hb_codepoint_t g) { s.add (g); } bool add_range (hb_codepoint_t a, hb_codepoint_t b) { return s.add_range (a, b); } @@ -125,6 +127,8 @@ struct hb_sparseset_t void set (const hb_sparseset_t &other) { s.set (other.s); } bool is_equal (const hb_sparseset_t &other) const { return s.is_equal (other.s); } + bool operator == (const hb_set_t &other) const { return is_equal (other); } + bool operator != (const hb_set_t &other) const { return !is_equal (other); } bool is_subset (const hb_sparseset_t &larger_set) const { return s.is_subset (larger_set.s); } @@ -158,15 +162,18 @@ struct hb_sparseset_t struct hb_set_t : hb_sparseset_t<hb_bit_set_invertible_t> { - hb_set_t () = default; + using sparseset = hb_sparseset_t<hb_bit_set_invertible_t>; + ~hb_set_t () = default; - hb_set_t (hb_set_t&) = default; - hb_set_t& operator= (const hb_set_t&) = default; - hb_set_t& operator= (hb_set_t&&) = default; - hb_set_t (std::initializer_list<hb_codepoint_t> lst) : hb_sparseset_t<hb_bit_set_invertible_t> (lst) {} + hb_set_t () : sparseset () {}; + hb_set_t (const hb_set_t &o) : sparseset ((sparseset &) o) {}; + hb_set_t (hb_set_t&& o) : sparseset (std::move ((sparseset &) o)) {} + hb_set_t& operator = (const hb_set_t&) = default; + hb_set_t& operator = (hb_set_t&&) = default; + hb_set_t (std::initializer_list<hb_codepoint_t> lst) : sparseset (lst) {} template <typename Iterable, hb_requires (hb_is_iterable (Iterable))> - hb_set_t (const Iterable &o) : hb_sparseset_t<hb_bit_set_invertible_t> (o) {} + hb_set_t (const Iterable &o) : sparseset (o) {} }; static_assert (hb_set_t::INVALID == HB_SET_VALUE_INVALID, ""); diff --git a/thirdparty/harfbuzz/src/hb-shape-plan.cc b/thirdparty/harfbuzz/src/hb-shape-plan.cc index 66332165c3..0af07825fc 100644 --- a/thirdparty/harfbuzz/src/hb-shape-plan.cc +++ b/thirdparty/harfbuzz/src/hb-shape-plan.cc @@ -170,7 +170,7 @@ hb_shape_plan_key_t::equal (const hb_shape_plan_key_t *other) /** - * hb_shape_plan_create: (Xconstructor) + * hb_shape_plan_create: * @face: #hb_face_t to use * @props: The #hb_segment_properties_t of the segment * @user_features: (array length=num_user_features): The list of user-selected features @@ -198,7 +198,7 @@ hb_shape_plan_create (hb_face_t *face, } /** - * hb_shape_plan_create2: (Xconstructor) + * hb_shape_plan_create2: * @face: #hb_face_t to use * @props: The #hb_segment_properties_t of the segment * @user_features: (array length=num_user_features): The list of user-selected features @@ -231,7 +231,8 @@ hb_shape_plan_create2 (hb_face_t *face, num_coords, shaper_list); - assert (props->direction != HB_DIRECTION_INVALID); + if (unlikely (props->direction == HB_DIRECTION_INVALID)) + return hb_shape_plan_get_empty (); hb_shape_plan_t *shape_plan; diff --git a/thirdparty/harfbuzz/src/hb-shape.cc b/thirdparty/harfbuzz/src/hb-shape.cc index 3407e1af42..14ec92828f 100644 --- a/thirdparty/harfbuzz/src/hb-shape.cc +++ b/thirdparty/harfbuzz/src/hb-shape.cc @@ -50,7 +50,7 @@ static inline void free_static_shaper_list (); -static const char *nil_shaper_list[] = {nullptr}; +static const char * const nil_shaper_list[] = {nullptr}; static struct hb_shaper_list_lazy_loader_t : hb_lazy_loader_t<const char *, hb_shaper_list_lazy_loader_t> @@ -73,7 +73,7 @@ static struct hb_shaper_list_lazy_loader_t : hb_lazy_loader_t<const char *, } static void destroy (const char **l) { hb_free (l); } - static const char ** get_null () + static const char * const * get_null () { return nil_shaper_list; } } static_shaper_list; @@ -126,6 +126,11 @@ hb_shape_full (hb_font_t *font, unsigned int num_features, const char * const *shaper_list) { + if (unlikely (!buffer->len)) + return true; + + buffer->enter (); + hb_buffer_t *text_buffer = nullptr; if (buffer->flags & HB_BUFFER_FLAG_VERIFY) { @@ -137,12 +142,19 @@ hb_shape_full (hb_font_t *font, features, num_features, font->coords, font->num_coords, shaper_list); + hb_bool_t res = hb_shape_plan_execute (shape_plan, font, buffer, features, num_features); + + if (buffer->max_ops <= 0) + buffer->shaping_failed = true; + hb_shape_plan_destroy (shape_plan); if (text_buffer) { - if (res && !buffer->verify (text_buffer, + if (res && buffer->successful && !buffer->shaping_failed + && text_buffer->successful + && !buffer->verify (text_buffer, font, features, num_features, @@ -151,6 +163,8 @@ hb_shape_full (hb_font_t *font, hb_buffer_destroy (text_buffer); } + buffer->leave (); + return res; } diff --git a/thirdparty/harfbuzz/src/hb-shaper.cc b/thirdparty/harfbuzz/src/hb-shaper.cc index a11ed83afd..da4253ed64 100644 --- a/thirdparty/harfbuzz/src/hb-shaper.cc +++ b/thirdparty/harfbuzz/src/hb-shaper.cc @@ -29,18 +29,18 @@ #include "hb-machinery.hh" -static const hb_shaper_entry_t all_shapers[] = { +static const hb_shaper_entry_t _hb_all_shapers[] = { #define HB_SHAPER_IMPLEMENT(name) {#name, _hb_##name##_shape}, #include "hb-shaper-list.hh" #undef HB_SHAPER_IMPLEMENT }; #ifndef HB_NO_SHAPER -static_assert (0 != ARRAY_LENGTH_CONST (all_shapers), "No shaper enabled."); +static_assert (0 != ARRAY_LENGTH_CONST (_hb_all_shapers), "No shaper enabled."); #endif static inline void free_static_shapers (); -static struct hb_shapers_lazy_loader_t : hb_lazy_loader_t<const hb_shaper_entry_t, +static struct hb_shapers_lazy_loader_t : hb_lazy_loader_t<hb_shaper_entry_t, hb_shapers_lazy_loader_t> { static hb_shaper_entry_t *create () @@ -49,11 +49,11 @@ static struct hb_shapers_lazy_loader_t : hb_lazy_loader_t<const hb_shaper_entry_ if (!env || !*env) return nullptr; - hb_shaper_entry_t *shapers = (hb_shaper_entry_t *) hb_calloc (1, sizeof (all_shapers)); + hb_shaper_entry_t *shapers = (hb_shaper_entry_t *) hb_calloc (1, sizeof (_hb_all_shapers)); if (unlikely (!shapers)) return nullptr; - memcpy (shapers, all_shapers, sizeof (all_shapers)); + memcpy (shapers, _hb_all_shapers, sizeof (_hb_all_shapers)); /* Reorder shaper list to prefer requested shapers. */ unsigned int i = 0; @@ -64,7 +64,7 @@ static struct hb_shapers_lazy_loader_t : hb_lazy_loader_t<const hb_shaper_entry_ if (!end) end = p + strlen (p); - for (unsigned int j = i; j < ARRAY_LENGTH (all_shapers); j++) + for (unsigned int j = i; j < ARRAY_LENGTH (_hb_all_shapers); j++) if (end - p == (int) strlen (shapers[j].name) && 0 == strncmp (shapers[j].name, p, end - p)) { @@ -85,8 +85,8 @@ static struct hb_shapers_lazy_loader_t : hb_lazy_loader_t<const hb_shaper_entry_ return shapers; } - static void destroy (const hb_shaper_entry_t *p) { hb_free ((void *) p); } - static const hb_shaper_entry_t *get_null () { return all_shapers; } + static void destroy (hb_shaper_entry_t *p) { hb_free (p); } + static const hb_shaper_entry_t *get_null () { return _hb_all_shapers; } } static_shapers; static inline diff --git a/thirdparty/harfbuzz/src/hb-static.cc b/thirdparty/harfbuzz/src/hb-static.cc index 7cc51be611..5c5ecce880 100644 --- a/thirdparty/harfbuzz/src/hb-static.cc +++ b/thirdparty/harfbuzz/src/hb-static.cc @@ -53,6 +53,9 @@ DEFINE_NULL_NAMESPACE_BYTES (AAT, SettingName) = {0xFF,0xFF, 0xFF,0xFF}; const unsigned char _hb_Null_AAT_Lookup[2] = {0xFF, 0xFF}; +/* hb_map_t */ + +const hb_codepoint_t minus_1 = -1; /* hb_face_t */ diff --git a/thirdparty/harfbuzz/src/hb-subset-cff-common.hh b/thirdparty/harfbuzz/src/hb-subset-cff-common.hh index 18657705fa..bb9f27eec1 100644 --- a/thirdparty/harfbuzz/src/hb-subset-cff-common.hh +++ b/thirdparty/harfbuzz/src/hb-subset-cff-common.hh @@ -40,11 +40,12 @@ struct str_encoder_t str_encoder_t (str_buff_t &buff_) : buff (buff_), error (false) {} - void reset () { buff.resize (0); } + void reset () { buff.reset (); } void encode_byte (unsigned char b) { - if (unlikely (buff.push (b) == &Crap (unsigned char))) + buff.push (b); + if (unlikely (buff.in_error ())) set_error (); } @@ -107,20 +108,18 @@ struct str_encoder_t encode_byte (op); } - void copy_str (const byte_str_t &str) + void copy_str (const hb_ubytes_t &str) { unsigned int offset = buff.length; - if (unlikely (!buff.resize (offset + str.length))) + /* Manually resize buffer since faster. */ + if ((signed) (buff.length + str.length) <= buff.allocated) + buff.length += str.length; + else if (unlikely (!buff.resize (offset + str.length))) { set_error (); return; } - if (unlikely (buff.length < offset + str.length)) - { - set_error (); - return; - } - memcpy (&buff[offset], &str[0], str.length); + memcpy (buff.arrayZ + offset, &str[0], str.length); } bool is_error () const { return error; } @@ -253,12 +252,12 @@ struct subr_flattener_t if (endchar_op != OpCode_Invalid) flat_charstrings[i].push (endchar_op); continue; } - const byte_str_t str = (*acc.charStrings)[glyph]; + const hb_ubytes_t str = (*acc.charStrings)[glyph]; unsigned int fd = acc.fdSelect->get_fd (glyph); if (unlikely (fd >= acc.fdCount)) return false; - cs_interpreter_t<ENV, OPSET, flatten_param_t> interp; - interp.env.init (str, acc, fd); + ENV env (str, acc, fd); + cs_interpreter_t<ENV, OPSET, flatten_param_t> interp (env); flatten_param_t param = { flat_charstrings[i], (bool) (plan->flags & HB_SUBSET_FLAGS_NO_HINTING) @@ -317,9 +316,9 @@ struct parsed_cs_op_t : op_str_t unsigned int subr_num; protected: - bool drop_flag : 1; - bool keep_flag : 1; - bool skip_flag : 1; + bool drop_flag; + bool keep_flag; + bool skip_flag; }; struct parsed_cs_str_t : parsed_values_t<parsed_cs_op_t> @@ -398,19 +397,19 @@ struct parsed_cs_str_vec_t : hb_vector_t<parsed_cs_str_t> struct subr_subset_param_t { - void init (parsed_cs_str_t *parsed_charstring_, - parsed_cs_str_vec_t *parsed_global_subrs_, parsed_cs_str_vec_t *parsed_local_subrs_, - hb_set_t *global_closure_, hb_set_t *local_closure_, - bool drop_hints_) - { - parsed_charstring = parsed_charstring_; - current_parsed_str = parsed_charstring; - parsed_global_subrs = parsed_global_subrs_; - parsed_local_subrs = parsed_local_subrs_; - global_closure = global_closure_; - local_closure = local_closure_; - drop_hints = drop_hints_; - } + subr_subset_param_t (parsed_cs_str_t *parsed_charstring_, + parsed_cs_str_vec_t *parsed_global_subrs_, + parsed_cs_str_vec_t *parsed_local_subrs_, + hb_set_t *global_closure_, + hb_set_t *local_closure_, + bool drop_hints_) : + current_parsed_str (parsed_charstring_), + parsed_charstring (parsed_charstring_), + parsed_global_subrs (parsed_global_subrs_), + parsed_local_subrs (parsed_local_subrs_), + global_closure (global_closure_), + local_closure (local_closure_), + drop_hints (drop_hints_) {} parsed_cs_str_t *get_parsed_str_for_context (call_context_t &context) { @@ -468,6 +467,7 @@ struct subr_remap_t : hb_inc_bimap_t * no optimization based on usage counts. fonttools doesn't appear doing that either. */ + resize (closure->get_population ()); hb_codepoint_t old_num = HB_SET_VALUE_INVALID; while (hb_set_next (closure, &old_num)) add (old_num); @@ -561,19 +561,21 @@ struct subr_subsetter_t hb_codepoint_t glyph; if (!plan->old_gid_for_new_gid (i, &glyph)) continue; - const byte_str_t str = (*acc.charStrings)[glyph]; + const hb_ubytes_t str = (*acc.charStrings)[glyph]; unsigned int fd = acc.fdSelect->get_fd (glyph); if (unlikely (fd >= acc.fdCount)) return false; - cs_interpreter_t<ENV, OPSET, subr_subset_param_t> interp; - interp.env.init (str, acc, fd); + ENV env (str, acc, fd); + cs_interpreter_t<ENV, OPSET, subr_subset_param_t> interp (env); - subr_subset_param_t param; - param.init (&parsed_charstrings[i], - &parsed_global_subrs, &parsed_local_subrs[fd], - &closures.global_closure, &closures.local_closures[fd], - plan->flags & HB_SUBSET_FLAGS_NO_HINTING); + parsed_charstrings[i].alloc (str.length); + subr_subset_param_t param (&parsed_charstrings[i], + &parsed_global_subrs, + &parsed_local_subrs[fd], + &closures.global_closure, + &closures.local_closures[fd], + plan->flags & HB_SUBSET_FLAGS_NO_HINTING); if (unlikely (!interp.interpret (param))) return false; @@ -593,11 +595,12 @@ struct subr_subsetter_t unsigned int fd = acc.fdSelect->get_fd (glyph); if (unlikely (fd >= acc.fdCount)) return false; - subr_subset_param_t param; - param.init (&parsed_charstrings[i], - &parsed_global_subrs, &parsed_local_subrs[fd], - &closures.global_closure, &closures.local_closures[fd], - plan->flags & HB_SUBSET_FLAGS_NO_HINTING); + subr_subset_param_t param (&parsed_charstrings[i], + &parsed_global_subrs, + &parsed_local_subrs[fd], + &closures.global_closure, + &closures.local_closures[fd], + plan->flags & HB_SUBSET_FLAGS_NO_HINTING); drop_hints_param_t drop; if (drop_hints_in_str (parsed_charstrings[i], param, drop)) @@ -618,11 +621,12 @@ struct subr_subsetter_t unsigned int fd = acc.fdSelect->get_fd (glyph); if (unlikely (fd >= acc.fdCount)) return false; - subr_subset_param_t param; - param.init (&parsed_charstrings[i], - &parsed_global_subrs, &parsed_local_subrs[fd], - &closures.global_closure, &closures.local_closures[fd], - plan->flags & HB_SUBSET_FLAGS_NO_HINTING); + subr_subset_param_t param (&parsed_charstrings[i], + &parsed_global_subrs, + &parsed_local_subrs[fd], + &closures.global_closure, + &closures.local_closures[fd], + plan->flags & HB_SUBSET_FLAGS_NO_HINTING); collect_subr_refs_in_str (parsed_charstrings[i], param); } } @@ -849,9 +853,10 @@ struct subr_subsetter_t bool encode_str (const parsed_cs_str_t &str, const unsigned int fd, str_buff_t &buff) const { - buff.init (); + unsigned count = str.get_count (); str_encoder_t encoder (buff); encoder.reset (); + buff.alloc (count * 3); /* if a prefix (CFF1 width or CFF2 vsindex) has been removed along with hints, * re-insert it at the beginning of charstreing */ if (str.has_prefix () && str.is_hint_dropped ()) @@ -860,7 +865,7 @@ struct subr_subsetter_t if (str.prefix_op () != OpCode_Invalid) encoder.encode_op (str.prefix_op ()); } - for (unsigned int i = 0; i < str.get_count(); i++) + for (unsigned int i = 0; i < count; i++) { const parsed_cs_op_t &opstr = str.values[i]; if (!opstr.for_drop () && !opstr.for_skip ()) diff --git a/thirdparty/harfbuzz/src/hb-subset-cff1.cc b/thirdparty/harfbuzz/src/hb-subset-cff1.cc index 35fecd67bc..52bb13d320 100644 --- a/thirdparty/harfbuzz/src/hb-subset-cff1.cc +++ b/thirdparty/harfbuzz/src/hb-subset-cff1.cc @@ -169,7 +169,7 @@ struct cff1_top_dict_op_serializer_t : cff_top_dict_op_serializer_t<cff1_top_dic supp_op.op = op; if ( unlikely (!(opstr.str.length >= opstr.last_arg_offset + 3))) return_trace (false); - supp_op.str = byte_str_t (&opstr.str + opstr.last_arg_offset, opstr.str.length - opstr.last_arg_offset); + supp_op.str = hb_ubytes_t (&opstr.str + opstr.last_arg_offset, opstr.str.length - opstr.last_arg_offset); return_trace (UnsizedByteStr::serialize_int2 (c, mod.nameSIDs[name_dict_values_t::registry]) && UnsizedByteStr::serialize_int2 (c, mod.nameSIDs[name_dict_values_t::ordering]) && copy_opstr (c, supp_op)); @@ -270,13 +270,13 @@ struct range_list_t : hb_vector_t<code_pair_t> /* replace the first glyph ID in the "glyph" field each range with a nLeft value */ bool complete (unsigned int last_glyph) { - bool two_byte = false; - for (unsigned int i = (*this).length; i > 0; i--) + bool two_byte = false; + unsigned count = this->length; + for (unsigned int i = count; i; i--) { - code_pair_t &pair = (*this)[i - 1]; - unsigned int nLeft = last_glyph - pair.glyph - 1; - if (nLeft >= 0x100) - two_byte = true; + code_pair_t &pair = arrayZ[i - 1]; + unsigned int nLeft = last_glyph - pair.glyph - 1; + two_byte |= nLeft >= 0x100; last_glyph = pair.glyph; pair.glyph = nLeft; } @@ -442,6 +442,9 @@ struct cff_subset_plan { return; } + bool use_glyph_to_sid_map = plan->num_output_glyphs () > plan->source->get_num_glyphs () / 8.; + hb_map_t *glyph_to_sid_map = use_glyph_to_sid_map ? acc.create_glyph_to_sid_map () : nullptr; + unsigned int glyph; for (glyph = 1; glyph < plan->num_output_glyphs (); glyph++) { @@ -451,7 +454,7 @@ struct cff_subset_plan { /* Retain the SID for the old missing glyph ID */ old_glyph = glyph; } - sid = acc.glyph_to_sid (old_glyph); + sid = glyph_to_sid_map ? glyph_to_sid_map->get (old_glyph) : acc.glyph_to_sid (old_glyph); if (!acc.is_CID ()) sid = sidmap.add (sid); @@ -464,6 +467,9 @@ struct cff_subset_plan { last_sid = sid; } + if (glyph_to_sid_map) + hb_map_destroy (glyph_to_sid_map); + bool two_byte = subset_charset_ranges.complete (glyph); size0 = Charset0::min_size + HBUINT16::static_size * (plan->num_output_glyphs () - 1); diff --git a/thirdparty/harfbuzz/src/hb-subset-cff2.cc b/thirdparty/harfbuzz/src/hb-subset-cff2.cc index 92dd6b1d2c..08e820efcf 100644 --- a/thirdparty/harfbuzz/src/hb-subset-cff2.cc +++ b/thirdparty/harfbuzz/src/hb-subset-cff2.cc @@ -67,9 +67,9 @@ struct cff2_top_dict_op_serializer_t : cff_top_dict_op_serializer_t<> } }; -struct cff2_cs_opset_flatten_t : cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatten_param_t> +struct cff2_cs_opset_flatten_t : cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatten_param_t, blend_arg_t> { - static void flush_args_and_op (op_code_t op, cff2_cs_interp_env_t &env, flatten_param_t& param) + static void flush_args_and_op (op_code_t op, cff2_cs_interp_env_t<blend_arg_t> &env, flatten_param_t& param) { switch (op) { @@ -97,7 +97,7 @@ struct cff2_cs_opset_flatten_t : cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatte } } - static void flush_args (cff2_cs_interp_env_t &env, flatten_param_t& param) + static void flush_args (cff2_cs_interp_env_t<blend_arg_t> &env, flatten_param_t& param) { for (unsigned int i = 0; i < env.argStack.get_count ();) { @@ -122,7 +122,7 @@ struct cff2_cs_opset_flatten_t : cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatte SUPER::flush_args (env, param); } - static void flatten_blends (const blend_arg_t &arg, unsigned int i, cff2_cs_interp_env_t &env, flatten_param_t& param) + static void flatten_blends (const blend_arg_t &arg, unsigned int i, cff2_cs_interp_env_t<blend_arg_t> &env, flatten_param_t& param) { /* flatten the default values */ str_encoder_t encoder (param.flatStr); @@ -149,7 +149,7 @@ struct cff2_cs_opset_flatten_t : cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatte encoder.encode_op (OpCode_blendcs); } - static void flush_op (op_code_t op, cff2_cs_interp_env_t &env, flatten_param_t& param) + static void flush_op (op_code_t op, cff2_cs_interp_env_t<blend_arg_t> &env, flatten_param_t& param) { switch (op) { @@ -163,13 +163,13 @@ struct cff2_cs_opset_flatten_t : cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatte } private: - typedef cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatten_param_t> SUPER; - typedef cs_opset_t<blend_arg_t, cff2_cs_opset_flatten_t, cff2_cs_opset_flatten_t, cff2_cs_interp_env_t, flatten_param_t> CSOPSET; + typedef cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatten_param_t, blend_arg_t> SUPER; + typedef cs_opset_t<blend_arg_t, cff2_cs_opset_flatten_t, cff2_cs_opset_flatten_t, cff2_cs_interp_env_t<blend_arg_t>, flatten_param_t> CSOPSET; }; -struct cff2_cs_opset_subr_subset_t : cff2_cs_opset_t<cff2_cs_opset_subr_subset_t, subr_subset_param_t> +struct cff2_cs_opset_subr_subset_t : cff2_cs_opset_t<cff2_cs_opset_subr_subset_t, subr_subset_param_t, blend_arg_t> { - static void process_op (op_code_t op, cff2_cs_interp_env_t &env, subr_subset_param_t& param) + static void process_op (op_code_t op, cff2_cs_interp_env_t<blend_arg_t> &env, subr_subset_param_t& param) { switch (op) { @@ -201,7 +201,7 @@ struct cff2_cs_opset_subr_subset_t : cff2_cs_opset_t<cff2_cs_opset_subr_subset_t protected: static void process_call_subr (op_code_t op, cs_type_t type, - cff2_cs_interp_env_t &env, subr_subset_param_t& param, + cff2_cs_interp_env_t<blend_arg_t> &env, subr_subset_param_t& param, cff2_biased_subrs_t& subrs, hb_set_t *closure) { byte_str_ref_t str_ref = env.str_ref; @@ -212,15 +212,15 @@ struct cff2_cs_opset_subr_subset_t : cff2_cs_opset_t<cff2_cs_opset_subr_subset_t } private: - typedef cff2_cs_opset_t<cff2_cs_opset_subr_subset_t, subr_subset_param_t> SUPER; + typedef cff2_cs_opset_t<cff2_cs_opset_subr_subset_t, subr_subset_param_t, blend_arg_t> SUPER; }; -struct cff2_subr_subsetter_t : subr_subsetter_t<cff2_subr_subsetter_t, CFF2Subrs, const OT::cff2::accelerator_subset_t, cff2_cs_interp_env_t, cff2_cs_opset_subr_subset_t> +struct cff2_subr_subsetter_t : subr_subsetter_t<cff2_subr_subsetter_t, CFF2Subrs, const OT::cff2::accelerator_subset_t, cff2_cs_interp_env_t<blend_arg_t>, cff2_cs_opset_subr_subset_t> { cff2_subr_subsetter_t (const OT::cff2::accelerator_subset_t &acc_, const hb_subset_plan_t *plan_) : subr_subsetter_t (acc_, plan_) {} - static void complete_parsed_str (cff2_cs_interp_env_t &env, subr_subset_param_t& param, parsed_cs_str_t &charstring) + static void complete_parsed_str (cff2_cs_interp_env_t<blend_arg_t> &env, subr_subset_param_t& param, parsed_cs_str_t &charstring) { /* vsindex is inserted at the beginning of the charstring as necessary */ if (env.seen_vsindex ()) @@ -245,7 +245,7 @@ struct cff2_subset_plan { if (desubroutinize) { /* Flatten global & local subrs */ - subr_flattener_t<const OT::cff2::accelerator_subset_t, cff2_cs_interp_env_t, cff2_cs_opset_flatten_t> + subr_flattener_t<const OT::cff2::accelerator_subset_t, cff2_cs_interp_env_t<blend_arg_t>, cff2_cs_opset_flatten_t> flattener(acc, plan); if (!flattener.flatten (subset_charstrings)) return false; diff --git a/thirdparty/harfbuzz/src/hb-subset-input.cc b/thirdparty/harfbuzz/src/hb-subset-input.cc index 4885280996..028ddf9035 100644 --- a/thirdparty/harfbuzz/src/hb-subset-input.cc +++ b/thirdparty/harfbuzz/src/hb-subset-input.cc @@ -140,7 +140,20 @@ hb_subset_input_create_or_fail (void) HB_TAG ('r', 't', 'l', 'a'), HB_TAG ('r', 't', 'l', 'm'), - //Complex shapers + //random + HB_TAG ('r', 'a', 'n', 'd'), + + //justify + HB_TAG ('j', 'a', 'l', 't'), // HarfBuzz doesn't use; others might + + //private + HB_TAG ('H', 'a', 'r', 'f'), + HB_TAG ('H', 'A', 'R', 'F'), + HB_TAG ('B', 'u', 'z', 'z'), + HB_TAG ('B', 'U', 'Z', 'Z'), + + //shapers + //arabic HB_TAG ('i', 'n', 'i', 't'), HB_TAG ('m', 'e', 'd', 'i'), diff --git a/thirdparty/harfbuzz/src/hb-subset-plan.cc b/thirdparty/harfbuzz/src/hb-subset-plan.cc index 74b7e3977c..4e3bb1d477 100644 --- a/thirdparty/harfbuzz/src/hb-subset-plan.cc +++ b/thirdparty/harfbuzz/src/hb-subset-plan.cc @@ -41,9 +41,9 @@ #include "hb-ot-math-table.hh" using OT::Layout::GSUB::GSUB; +using OT::Layout::GPOS; - -typedef hb_hashmap_t<unsigned, hb_set_t *> script_langsys_map; +typedef hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> script_langsys_map; #ifndef HB_NO_SUBSET_CFF static inline void _add_cff_seac_components (const OT::cff1::accelerator_t &cff, @@ -204,7 +204,7 @@ static inline void hb_map_t *layout_variation_idx_map) { hb_blob_ptr_t<OT::GDEF> gdef = hb_sanitize_context_t ().reference_table<OT::GDEF> (face); - hb_blob_ptr_t<OT::GPOS> gpos = hb_sanitize_context_t ().reference_table<OT::GPOS> (face); + hb_blob_ptr_t<GPOS> gpos = hb_sanitize_context_t ().reference_table<GPOS> (face); if (!gdef->has_data ()) { @@ -279,12 +279,7 @@ static inline void _remove_invalid_gids (hb_set_t *glyphs, unsigned int num_glyphs) { - hb_codepoint_t gid = HB_SET_VALUE_INVALID; - while (glyphs->next (&gid)) - { - if (gid >= num_glyphs) - glyphs->del (gid); - } + glyphs->del_range (num_glyphs, HB_SET_VALUE_INVALID); } static void @@ -294,12 +289,13 @@ _populate_unicodes_to_retain (const hb_set_t *unicodes, { OT::cmap::accelerator_t cmap (plan->source); - constexpr static const int size_threshold = 4096; - + unsigned size_threshold = plan->source->get_num_glyphs (); if (glyphs->is_empty () && unicodes->get_population () < size_threshold) { - /* This is the fast path if it's anticipated that size of unicodes - * is << than the number of codepoints in the font. */ + // This is approach to collection is faster, but can only be used if glyphs + // are not being explicitly added to the subset and the input unicodes set is + // not excessively large (eg. an inverted set). + plan->unicode_to_new_gid_list.alloc (unicodes->get_population ()); for (hb_codepoint_t cp : *unicodes) { hb_codepoint_t gid; @@ -310,27 +306,32 @@ _populate_unicodes_to_retain (const hb_set_t *unicodes, } plan->codepoint_to_glyph->set (cp, gid); + plan->unicode_to_new_gid_list.push (hb_pair (cp, gid)); } } else { + // This approach is slower, but can handle adding in glyphs to the subset and will match + // them with cmap entries. hb_map_t unicode_glyphid_map; - cmap.collect_mapping (hb_set_get_empty (), &unicode_glyphid_map); + hb_set_t cmap_unicodes; + cmap.collect_mapping (&cmap_unicodes, &unicode_glyphid_map); + plan->unicode_to_new_gid_list.alloc (hb_min(unicodes->get_population () + + glyphs->get_population (), + cmap_unicodes.get_population ())); - for (hb_pair_t<hb_codepoint_t, hb_codepoint_t> cp_gid : - + unicode_glyphid_map.iter ()) + for (hb_codepoint_t cp : cmap_unicodes) { - if (!unicodes->has (cp_gid.first) && !glyphs->has (cp_gid.second)) - continue; + hb_codepoint_t gid = unicode_glyphid_map[cp]; + if (!unicodes->has (cp) && !glyphs->has (gid)) + continue; - plan->codepoint_to_glyph->set (cp_gid.first, cp_gid.second); + plan->codepoint_to_glyph->set (cp, gid); + plan->unicode_to_new_gid_list.push (hb_pair (cp, gid)); } /* Add gids which where requested, but not mapped in cmap */ - // TODO(garretrieger): - // Once https://github.com/harfbuzz/harfbuzz/issues/3169 - // is implemented, this can be done with union and del_range - for (hb_codepoint_t gid : glyphs->iter ()) + for (hb_codepoint_t gid : *glyphs) { if (gid >= plan->source->get_num_glyphs ()) break; @@ -338,8 +339,41 @@ _populate_unicodes_to_retain (const hb_set_t *unicodes, } } - + plan->codepoint_to_glyph->keys () | hb_sink (plan->unicodes); - + plan->codepoint_to_glyph->values () | hb_sink (plan->_glyphset_gsub); + auto &arr = plan->unicode_to_new_gid_list; + if (arr.length) + { + plan->unicodes->add_sorted_array (&arr.arrayZ->first, arr.length, sizeof (*arr.arrayZ)); + plan->_glyphset_gsub->add_array (&arr.arrayZ->second, arr.length, sizeof (*arr.arrayZ)); + } +} + +#ifndef HB_COMPOSITE_OPERATIONS_PER_GLYPH +#define HB_COMPOSITE_OPERATIONS_PER_GLYPH 64 +#endif + +static unsigned +_glyf_add_gid_and_children (const OT::glyf_accelerator_t &glyf, + hb_codepoint_t gid, + hb_set_t *gids_to_retain, + int operation_count, + unsigned depth = 0) +{ + if (unlikely (depth++ > HB_MAX_NESTING_LEVEL)) return operation_count; + if (unlikely (--operation_count < 0)) return operation_count; + /* Check if is already visited */ + if (gids_to_retain->has (gid)) return operation_count; + + gids_to_retain->add (gid); + + for (auto item : glyf.glyph_for_gid (gid).get_composite_iterator ()) + operation_count = + _glyf_add_gid_and_children (glyf, + item.glyphIndex, + gids_to_retain, + operation_count, + depth); + + return operation_count; } static void @@ -348,7 +382,7 @@ _populate_gids_to_retain (hb_subset_plan_t* plan, bool close_over_gpos, bool close_over_gdef) { - OT::glyf::accelerator_t glyf (plan->source); + OT::glyf_accelerator_t glyf (plan->source); #ifndef HB_NO_SUBSET_CFF OT::cff1::accelerator_t cff (plan->source); #endif @@ -369,7 +403,7 @@ _populate_gids_to_retain (hb_subset_plan_t* plan, plan->gsub_langsys); if (close_over_gpos) - _closure_glyphs_lookups_features<OT::GPOS> ( + _closure_glyphs_lookups_features<GPOS> ( plan->source, plan->_glyphset_gsub, plan->layout_features, @@ -388,16 +422,20 @@ _populate_gids_to_retain (hb_subset_plan_t* plan, _remove_invalid_gids (&cur_glyphset, plan->source->get_num_glyphs ()); hb_set_set (plan->_glyphset_colred, &cur_glyphset); - // Populate a full set of glyphs to retain by adding all referenced - // composite glyphs. - for (hb_codepoint_t gid : cur_glyphset.iter ()) - { - glyf.add_gid_and_children (gid, plan->_glyphset); + + /* Populate a full set of glyphs to retain by adding all referenced + * composite glyphs. */ + if (glyf.has_data ()) + for (hb_codepoint_t gid : cur_glyphset) + _glyf_add_gid_and_children (glyf, gid, plan->_glyphset, + cur_glyphset.get_population () * HB_COMPOSITE_OPERATIONS_PER_GLYPH); + else + plan->_glyphset->union_ (cur_glyphset); #ifndef HB_NO_SUBSET_CFF - if (cff.is_valid ()) + if (cff.is_valid ()) + for (hb_codepoint_t gid : cur_glyphset) _add_cff_seac_components (cff, gid, plan->_glyphset); #endif - } _remove_invalid_gids (plan->_glyphset, plan->source->get_num_glyphs ()); @@ -413,6 +451,20 @@ _populate_gids_to_retain (hb_subset_plan_t* plan, } static void +_create_glyph_map_gsub (const hb_set_t* glyph_set_gsub, + const hb_map_t* glyph_map, + hb_map_t* out) +{ + + hb_iter (glyph_set_gsub) + | hb_map ([&] (hb_codepoint_t gid) { + return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (gid, + glyph_map->get (gid)); + }) + | hb_sink (out) + ; +} + +static void _create_old_gid_to_new_gid_map (const hb_face_t *face, bool retain_gids, const hb_set_t *all_gids_to_retain, @@ -420,13 +472,19 @@ _create_old_gid_to_new_gid_map (const hb_face_t *face, hb_map_t *reverse_glyph_map, /* OUT */ unsigned int *num_glyphs /* OUT */) { + unsigned pop = all_gids_to_retain->get_population (); + reverse_glyph_map->resize (pop); + glyph_map->resize (pop); + if (!retain_gids) { + hb_enumerate (hb_iter (all_gids_to_retain), (hb_codepoint_t) 0) | hb_sink (reverse_glyph_map) ; *num_glyphs = reverse_glyph_map->get_population (); - } else { + } + else + { + hb_iter (all_gids_to_retain) | hb_map ([] (hb_codepoint_t _) { return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (_, _); @@ -434,10 +492,9 @@ _create_old_gid_to_new_gid_map (const hb_face_t *face, | hb_sink (reverse_glyph_map) ; - unsigned max_glyph = - + hb_iter (all_gids_to_retain) - | hb_reduce (hb_max, 0u) - ; + hb_codepoint_t max_glyph = HB_SET_VALUE_INVALID; + hb_set_previous (all_gids_to_retain, &max_glyph); + *num_glyphs = max_glyph + 1; } @@ -485,6 +542,9 @@ hb_subset_plan_create_or_fail (hb_face_t *face, plan->successful = true; plan->flags = input->flags; plan->unicodes = hb_set_create (); + + plan->unicode_to_new_gid_list.init (); + plan->name_ids = hb_set_copy (input->sets.name_ids); _nameid_closure (face, plan->name_ids); plan->name_languages = hb_set_copy (input->sets.name_languages); @@ -502,6 +562,7 @@ hb_subset_plan_create_or_fail (hb_face_t *face, plan->codepoint_to_glyph = hb_map_create (); plan->glyph_map = hb_map_create (); plan->reverse_glyph_map = hb_map_create (); + plan->glyph_map_gsub = hb_map_create (); plan->gsub_lookups = hb_map_create (); plan->gpos_lookups = hb_map_create (); @@ -536,6 +597,19 @@ hb_subset_plan_create_or_fail (hb_face_t *face, plan->reverse_glyph_map, &plan->_num_output_glyphs); + _create_glyph_map_gsub ( + plan->_glyphset_gsub, + plan->glyph_map, + plan->glyph_map_gsub); + + // Now that we have old to new gid map update the unicode to new gid list. + for (unsigned i = 0; i < plan->unicode_to_new_gid_list.length; i++) + { + // Use raw array access for performance. + plan->unicode_to_new_gid_list.arrayZ[i].second = + plan->glyph_map->get(plan->unicode_to_new_gid_list.arrayZ[i].second); + } + if (unlikely (plan->in_error ())) { hb_subset_plan_destroy (plan); return nullptr; @@ -558,6 +632,7 @@ hb_subset_plan_destroy (hb_subset_plan_t *plan) if (!hb_object_destroy (plan)) return; hb_set_destroy (plan->unicodes); + plan->unicode_to_new_gid_list.fini (); hb_set_destroy (plan->name_ids); hb_set_destroy (plan->name_languages); hb_set_destroy (plan->layout_features); @@ -569,6 +644,7 @@ hb_subset_plan_destroy (hb_subset_plan_t *plan) hb_map_destroy (plan->codepoint_to_glyph); hb_map_destroy (plan->glyph_map); hb_map_destroy (plan->reverse_glyph_map); + hb_map_destroy (plan->glyph_map_gsub); hb_set_destroy (plan->_glyphset); hb_set_destroy (plan->_glyphset_gsub); hb_set_destroy (plan->_glyphset_mathed); @@ -584,9 +660,6 @@ hb_subset_plan_destroy (hb_subset_plan_t *plan) if (plan->gsub_langsys) { - for (auto _ : plan->gsub_langsys->iter ()) - hb_set_destroy (_.second); - hb_object_destroy (plan->gsub_langsys); plan->gsub_langsys->fini_shallow (); hb_free (plan->gsub_langsys); @@ -594,9 +667,6 @@ hb_subset_plan_destroy (hb_subset_plan_t *plan) if (plan->gpos_langsys) { - for (auto _ : plan->gpos_langsys->iter ()) - hb_set_destroy (_.second); - hb_object_destroy (plan->gpos_langsys); plan->gpos_langsys->fini_shallow (); hb_free (plan->gpos_langsys); diff --git a/thirdparty/harfbuzz/src/hb-subset-plan.hh b/thirdparty/harfbuzz/src/hb-subset-plan.hh index ab2c4c302c..2aaf19c61d 100644 --- a/thirdparty/harfbuzz/src/hb-subset-plan.hh +++ b/thirdparty/harfbuzz/src/hb-subset-plan.hh @@ -44,6 +44,7 @@ struct hb_subset_plan_t // For each cp that we'd like to retain maps to the corresponding gid. hb_set_t *unicodes; + hb_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> unicode_to_new_gid_list; // name_ids we would like to retain hb_set_t *name_ids; @@ -69,6 +70,7 @@ struct hb_subset_plan_t // Old -> New glyph id mapping hb_map_t *glyph_map; hb_map_t *reverse_glyph_map; + hb_map_t *glyph_map_gsub; // Plan is only good for a specific source/dest so keep them with it hb_face_t *source; @@ -85,8 +87,8 @@ struct hb_subset_plan_t hb_map_t *gpos_lookups; //active langsys we'd like to retain - hb_hashmap_t<unsigned, hb_set_t *> *gsub_langsys; - hb_hashmap_t<unsigned, hb_set_t *> *gpos_langsys; + hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *gsub_langsys; + hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *gpos_langsys; //active features after removing redundant langsys and prune_features hb_map_t *gsub_features; diff --git a/thirdparty/harfbuzz/src/hb-subset.cc b/thirdparty/harfbuzz/src/hb-subset.cc index 4588268b76..10c572c2f7 100644 --- a/thirdparty/harfbuzz/src/hb-subset.cc +++ b/thirdparty/harfbuzz/src/hb-subset.cc @@ -56,6 +56,7 @@ #include "hb-repacker.hh" using OT::Layout::GSUB::GSUB; +using OT::Layout::GPOS; /** * SECTION:hb-subset @@ -78,13 +79,117 @@ using OT::Layout::GSUB::GSUB; * retain glyph ids option and configure the subset to pass through the layout tables untouched. */ +/* + * The list of tables in the open type spec. Used to check for tables that may need handling + * if we are unable to list the tables in a face. + */ +static hb_tag_t known_tables[] { + HB_TAG ('a', 'v', 'a', 'r'), + HB_OT_TAG_BASE, + HB_OT_TAG_CBDT, + HB_OT_TAG_CBLC, + HB_OT_TAG_cff1, + HB_OT_TAG_cff2, + HB_OT_TAG_cmap, + HB_OT_TAG_COLR, + HB_OT_TAG_CPAL, + HB_TAG ('c', 'v', 'a', 'r'), + HB_TAG ('c', 'v', 't', ' '), + HB_TAG ('D', 'S', 'I', 'G'), + HB_TAG ('E', 'B', 'D', 'T'), + HB_TAG ('E', 'B', 'L', 'C'), + HB_TAG ('E', 'B', 'S', 'C'), + HB_TAG ('f', 'p', 'g', 'm'), + HB_TAG ('f', 'v', 'a', 'r'), + HB_TAG ('g', 'a', 's', 'p'), + HB_OT_TAG_GDEF, + HB_OT_TAG_glyf, + HB_OT_TAG_GPOS, + HB_OT_TAG_GSUB, + HB_OT_TAG_gvar, + HB_OT_TAG_hdmx, + HB_OT_TAG_head, + HB_OT_TAG_hhea, + HB_OT_TAG_hmtx, + HB_OT_TAG_HVAR, + HB_OT_TAG_JSTF, + HB_TAG ('k', 'e', 'r', 'n'), + HB_OT_TAG_loca, + HB_TAG ('L', 'T', 'S', 'H'), + HB_OT_TAG_MATH, + HB_OT_TAG_maxp, + HB_TAG ('M', 'E', 'R', 'G'), + HB_TAG ('m', 'e', 't', 'a'), + HB_TAG ('M', 'V', 'A', 'R'), + HB_TAG ('P', 'C', 'L', 'T'), + HB_OT_TAG_post, + HB_TAG ('p', 'r', 'e', 'p'), + HB_OT_TAG_sbix, + HB_TAG ('S', 'T', 'A', 'T'), + HB_TAG ('S', 'V', 'G', ' '), + HB_TAG ('V', 'D', 'M', 'X'), + HB_OT_TAG_vhea, + HB_OT_TAG_vmtx, + HB_OT_TAG_VORG, + HB_OT_TAG_VVAR, + HB_OT_TAG_name, + HB_OT_TAG_OS2 +}; + +static bool _table_is_empty (const hb_face_t *face, hb_tag_t tag) +{ + hb_blob_t* blob = hb_face_reference_table (face, tag); + bool result = (blob == hb_blob_get_empty ()); + hb_blob_destroy (blob); + return result; +} + +static unsigned int +_get_table_tags (const hb_subset_plan_t* plan, + unsigned int start_offset, + unsigned int *table_count, /* IN/OUT */ + hb_tag_t *table_tags /* OUT */) +{ + unsigned num_tables = hb_face_get_table_tags (plan->source, 0, nullptr, nullptr); + if (num_tables) + return hb_face_get_table_tags (plan->source, start_offset, table_count, table_tags); + + // If face has 0 tables associated with it, assume that it was built from + // hb_face_create_tables and thus is unable to list its tables. Fallback to + // checking each table type we can handle for existence instead. + auto it = + hb_concat ( + + hb_array (known_tables) + | hb_filter ([&] (hb_tag_t tag) { + return !_table_is_empty (plan->source, tag) && !plan->no_subset_tables->has (tag); + }) + | hb_map ([] (hb_tag_t tag) -> hb_tag_t { return tag; }), + + plan->no_subset_tables->iter () + | hb_filter([&] (hb_tag_t tag) { + return !_table_is_empty (plan->source, tag); + })); + + it += start_offset; + + unsigned num_written = 0; + while (bool (it) && num_written < *table_count) + table_tags[num_written++] = *it++; + + *table_count = num_written; + return num_written; +} + + static unsigned -_plan_estimate_subset_table_size (hb_subset_plan_t *plan, unsigned table_len) +_plan_estimate_subset_table_size (hb_subset_plan_t *plan, + unsigned table_len, + bool same_size) { unsigned src_glyphs = plan->source->get_num_glyphs (); unsigned dst_glyphs = plan->glyphset ()->get_population (); - if (unlikely (!src_glyphs)) + if (unlikely (!src_glyphs) || same_size) return 512 + table_len; return 512 + (unsigned) (table_len * sqrt ((double) dst_glyphs / src_glyphs)); @@ -123,7 +228,6 @@ static bool _try_subset (const TableType *table, hb_vector_t<char>* buf, - unsigned buf_size, hb_subset_context_t* c /* OUT */) { c->serializer->start_serialize<TableType> (); @@ -136,7 +240,8 @@ _try_subset (const TableType *table, return needed; } - buf_size += (buf_size >> 1) + 32; + unsigned buf_size = buf->allocated; + buf_size = buf_size * 2 + 16; DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c ran out of room; reallocating to %u bytes.", HB_UNTAG (c->table_tag), buf_size); @@ -147,13 +252,13 @@ _try_subset (const TableType *table, return needed; } - c->serializer->reset (buf->arrayZ, buf_size); - return _try_subset (table, buf, buf_size, c); + c->serializer->reset (buf->arrayZ, buf->allocated); + return _try_subset (table, buf, c); } template<typename TableType> static bool -_subset (hb_subset_plan_t *plan) +_subset (hb_subset_plan_t *plan, hb_vector_t<char> &buf) { hb_blob_t *source_blob = hb_sanitize_context_t ().reference_table<TableType> (plan->source); const TableType *table = source_blob->as<TableType> (); @@ -167,10 +272,13 @@ _subset (hb_subset_plan_t *plan) return false; } - hb_vector_t<char> buf; - /* TODO Not all tables are glyph-related. 'name' table size for example should not be - * affected by number of glyphs. Accommodate that. */ - unsigned buf_size = _plan_estimate_subset_table_size (plan, source_blob->length); + /* Tables that we want to allocate same space as the source table. For GSUB/GPOS it's + * because those are expensive to subset, so giving them more room is fine. */ + bool same_size_table = TableType::tableTag == HB_OT_TAG_GSUB || + TableType::tableTag == HB_OT_TAG_GPOS || + TableType::tableTag == HB_OT_TAG_name; + + unsigned buf_size = _plan_estimate_subset_table_size (plan, source_blob->length, same_size_table); DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c initial estimated table size: %u bytes.", HB_UNTAG (tag), buf_size); if (unlikely (!buf.alloc (buf_size))) @@ -181,10 +289,10 @@ _subset (hb_subset_plan_t *plan) } bool needed = false; - hb_serialize_context_t serializer (buf.arrayZ, buf_size); + hb_serialize_context_t serializer (buf.arrayZ, buf.allocated); { hb_subset_context_t c (source_blob, plan, &serializer, tag); - needed = _try_subset (table, &buf, buf_size, &c); + needed = _try_subset (table, &buf, &c); } hb_blob_destroy (source_blob); @@ -219,9 +327,17 @@ _subset (hb_subset_plan_t *plan) static bool _is_table_present (hb_face_t *source, hb_tag_t tag) { + + if (!hb_face_get_table_tags (source, 0, nullptr, nullptr)) { + // If face has 0 tables associated with it, assume that it was built from + // hb_face_create_tables and thus is unable to list its tables. Fallback to + // checking if the blob associated with tag is empty. + return !_table_is_empty (source, tag); + } + hb_tag_t table_tags[32]; unsigned offset = 0, num_tables = ARRAY_LENGTH (table_tags); - while ((hb_face_get_table_tags (source, offset, &num_tables, table_tags), num_tables)) + while (((void) hb_face_get_table_tags (source, offset, &num_tables, table_tags), num_tables)) { for (unsigned i = 0; i < num_tables; ++i) if (table_tags[i] == tag) @@ -274,7 +390,9 @@ _passthrough (hb_subset_plan_t *plan, hb_tag_t tag) } static bool -_subset_table (hb_subset_plan_t *plan, hb_tag_t tag) +_subset_table (hb_subset_plan_t *plan, + hb_vector_t<char> &buf, + hb_tag_t tag) { if (plan->no_subset_tables->has (tag)) { return _passthrough (plan, tag); @@ -283,42 +401,42 @@ _subset_table (hb_subset_plan_t *plan, hb_tag_t tag) DEBUG_MSG (SUBSET, nullptr, "subset %c%c%c%c", HB_UNTAG (tag)); switch (tag) { - case HB_OT_TAG_glyf: return _subset<const OT::glyf> (plan); - case HB_OT_TAG_hdmx: return _subset<const OT::hdmx> (plan); - case HB_OT_TAG_name: return _subset<const OT::name> (plan); + case HB_OT_TAG_glyf: return _subset<const OT::glyf> (plan, buf); + case HB_OT_TAG_hdmx: return _subset<const OT::hdmx> (plan, buf); + case HB_OT_TAG_name: return _subset<const OT::name> (plan, buf); case HB_OT_TAG_head: if (_is_table_present (plan->source, HB_OT_TAG_glyf) && !_should_drop_table (plan, HB_OT_TAG_glyf)) return true; /* skip head, handled by glyf */ - return _subset<const OT::head> (plan); + return _subset<const OT::head> (plan, buf); case HB_OT_TAG_hhea: return true; /* skip hhea, handled by hmtx */ - case HB_OT_TAG_hmtx: return _subset<const OT::hmtx> (plan); + case HB_OT_TAG_hmtx: return _subset<const OT::hmtx> (plan, buf); case HB_OT_TAG_vhea: return true; /* skip vhea, handled by vmtx */ - case HB_OT_TAG_vmtx: return _subset<const OT::vmtx> (plan); - case HB_OT_TAG_maxp: return _subset<const OT::maxp> (plan); - case HB_OT_TAG_sbix: return _subset<const OT::sbix> (plan); + case HB_OT_TAG_vmtx: return _subset<const OT::vmtx> (plan, buf); + case HB_OT_TAG_maxp: return _subset<const OT::maxp> (plan, buf); + case HB_OT_TAG_sbix: return _subset<const OT::sbix> (plan, buf); case HB_OT_TAG_loca: return true; /* skip loca, handled by glyf */ - case HB_OT_TAG_cmap: return _subset<const OT::cmap> (plan); - case HB_OT_TAG_OS2 : return _subset<const OT::OS2 > (plan); - case HB_OT_TAG_post: return _subset<const OT::post> (plan); - case HB_OT_TAG_COLR: return _subset<const OT::COLR> (plan); - case HB_OT_TAG_CPAL: return _subset<const OT::CPAL> (plan); - case HB_OT_TAG_CBLC: return _subset<const OT::CBLC> (plan); + case HB_OT_TAG_cmap: return _subset<const OT::cmap> (plan, buf); + case HB_OT_TAG_OS2 : return _subset<const OT::OS2 > (plan, buf); + case HB_OT_TAG_post: return _subset<const OT::post> (plan, buf); + case HB_OT_TAG_COLR: return _subset<const OT::COLR> (plan, buf); + case HB_OT_TAG_CPAL: return _subset<const OT::CPAL> (plan, buf); + case HB_OT_TAG_CBLC: return _subset<const OT::CBLC> (plan, buf); case HB_OT_TAG_CBDT: return true; /* skip CBDT, handled by CBLC */ - case HB_OT_TAG_MATH: return _subset<const OT::MATH> (plan); + case HB_OT_TAG_MATH: return _subset<const OT::MATH> (plan, buf); #ifndef HB_NO_SUBSET_CFF - case HB_OT_TAG_cff1: return _subset<const OT::cff1> (plan); - case HB_OT_TAG_cff2: return _subset<const OT::cff2> (plan); - case HB_OT_TAG_VORG: return _subset<const OT::VORG> (plan); + case HB_OT_TAG_cff1: return _subset<const OT::cff1> (plan, buf); + case HB_OT_TAG_cff2: return _subset<const OT::cff2> (plan, buf); + case HB_OT_TAG_VORG: return _subset<const OT::VORG> (plan, buf); #endif #ifndef HB_NO_SUBSET_LAYOUT - case HB_OT_TAG_GDEF: return _subset<const OT::GDEF> (plan); - case HB_OT_TAG_GSUB: return _subset<const GSUB> (plan); - case HB_OT_TAG_GPOS: return _subset<const OT::GPOS> (plan); - case HB_OT_TAG_gvar: return _subset<const OT::gvar> (plan); - case HB_OT_TAG_HVAR: return _subset<const OT::HVAR> (plan); - case HB_OT_TAG_VVAR: return _subset<const OT::VVAR> (plan); + case HB_OT_TAG_GDEF: return _subset<const OT::GDEF> (plan, buf); + case HB_OT_TAG_GSUB: return _subset<const GSUB> (plan, buf); + case HB_OT_TAG_GPOS: return _subset<const GPOS> (plan, buf); + case HB_OT_TAG_gvar: return _subset<const OT::gvar> (plan, buf); + case HB_OT_TAG_HVAR: return _subset<const OT::HVAR> (plan, buf); + case HB_OT_TAG_VVAR: return _subset<const OT::VVAR> (plan, buf); #endif default: @@ -379,19 +497,22 @@ hb_subset_plan_execute_or_fail (hb_subset_plan_t *plan) bool success = true; hb_tag_t table_tags[32]; unsigned offset = 0, num_tables = ARRAY_LENGTH (table_tags); - while ((hb_face_get_table_tags (plan->source, offset, &num_tables, table_tags), num_tables)) + hb_vector_t<char> buf; + buf.alloc (4096 - 16); + + while (((void) _get_table_tags (plan, offset, &num_tables, table_tags), num_tables)) { for (unsigned i = 0; i < num_tables; ++i) { hb_tag_t tag = table_tags[i]; if (_should_drop_table (plan, tag) && !tags_set.has (tag)) continue; tags_set.add (tag); - success = _subset_table (plan, tag); + success = _subset_table (plan, buf, tag); if (unlikely (!success)) goto end; } offset += num_tables; } -end: +end: return success ? hb_face_reference (plan->dest) : nullptr; } diff --git a/thirdparty/harfbuzz/src/hb-ucd-table.hh b/thirdparty/harfbuzz/src/hb-ucd-table.hh index 1a4c89c17f..9e76ca460b 100644 --- a/thirdparty/harfbuzz/src/hb-ucd-table.hh +++ b/thirdparty/harfbuzz/src/hb-ucd-table.hh @@ -13,7 +13,7 @@ #include "hb.hh" static const hb_script_t -_hb_ucd_sc_map[162] = +_hb_ucd_sc_map[163] = { HB_SCRIPT_COMMON, HB_SCRIPT_INHERITED, HB_SCRIPT_UNKNOWN, HB_SCRIPT_ARABIC, @@ -96,6 +96,7 @@ _hb_ucd_sc_map[162] = HB_SCRIPT_YEZIDI, HB_SCRIPT_CYPRO_MINOAN, HB_SCRIPT_OLD_UYGHUR, HB_SCRIPT_TANGSA, HB_SCRIPT_TOTO, HB_SCRIPT_VITHKUQI, + HB_SCRIPT_MATH, }; static const uint16_t _hb_ucd_dm1_p0_map[825] = diff --git a/thirdparty/harfbuzz/src/hb-unicode.cc b/thirdparty/harfbuzz/src/hb-unicode.cc index 83ead6398b..05f74b9237 100644 --- a/thirdparty/harfbuzz/src/hb-unicode.cc +++ b/thirdparty/harfbuzz/src/hb-unicode.cc @@ -169,7 +169,7 @@ hb_unicode_funcs_get_default () #endif /** - * hb_unicode_funcs_create: (Xconstructor) + * hb_unicode_funcs_create: * @parent: (nullable): Parent Unicode-functions structure * * Creates a new #hb_unicode_funcs_t structure of Unicode functions. diff --git a/thirdparty/harfbuzz/src/hb-unicode.hh b/thirdparty/harfbuzz/src/hb-unicode.hh index 4c28bb0cdf..39aaee5baa 100644 --- a/thirdparty/harfbuzz/src/hb-unicode.hh +++ b/thirdparty/harfbuzz/src/hb-unicode.hh @@ -105,12 +105,9 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE unsigned int modified_combining_class (hb_codepoint_t u) { - /* XXX This hack belongs to the USE shaper (for Tai Tham): - * Reorder SAKOT to ensure it comes after any tone marks. */ + /* Reorder SAKOT to ensure it comes after any tone marks. */ if (unlikely (u == 0x1A60u)) return 254; - - /* XXX This hack belongs to the Tibetan shaper: - * Reorder PADMA to ensure it comes after any vowel marks. */ + /* Reorder PADMA to ensure it comes after any vowel marks. */ if (unlikely (u == 0x0FC6u)) return 254; /* Reorder TSA -PHRU to reorder before U+0F74 */ if (unlikely (u == 0x0F39u)) return 127; diff --git a/thirdparty/harfbuzz/src/hb-vector.hh b/thirdparty/harfbuzz/src/hb-vector.hh index 6c7d32e49d..7b08e3b4d2 100644 --- a/thirdparty/harfbuzz/src/hb-vector.hh +++ b/thirdparty/harfbuzz/src/hb-vector.hh @@ -29,6 +29,7 @@ #include "hb.hh" #include "hb-array.hh" +#include "hb-meta.hh" #include "hb-null.hh" @@ -42,6 +43,7 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty using c_array_t = typename std::conditional<sorted, hb_sorted_array_t<const Type>, hb_array_t<const Type>>::type; hb_vector_t () = default; + hb_vector_t (std::nullptr_t) : hb_vector_t () {} hb_vector_t (std::initializer_list<Type> lst) : hb_vector_t () { alloc (lst.size ()); @@ -59,7 +61,8 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty hb_vector_t (const hb_vector_t &o) : hb_vector_t () { alloc (o.length); - hb_copy (o, *this); + if (unlikely (in_error ())) return; + copy_vector (o); } hb_vector_t (hb_vector_t &&o) { @@ -70,9 +73,8 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty } ~hb_vector_t () { fini (); } - private: - int allocated = 0; /* == -1 means allocation failed. */ public: + int allocated = 0; /* == -1 means allocation failed. */ unsigned int length = 0; public: Type *arrayZ = nullptr; @@ -108,7 +110,10 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty { reset (); alloc (o.length); - hb_copy (o, *this); + if (unlikely (in_error ())) return *this; + + copy_vector (o); + return *this; } hb_vector_t& operator = (hb_vector_t &&o) @@ -184,12 +189,14 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty { if (unlikely (!resize (length + 1))) return &Crap (Type); - return &arrayZ[length - 1]; + return std::addressof (arrayZ[length - 1]); } - template <typename T> + template <typename T, + typename T2 = Type, + hb_enable_if (!std::is_copy_constructible<T2>::value && + std::is_copy_assignable<T>::value)> Type *push (T&& v) { - /* TODO Emplace? */ Type *p = push (); if (p == &Crap (Type)) // If push failed to allocate then don't copy v, since this may cause @@ -199,18 +206,34 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty *p = std::forward<T> (v); return p; } + template <typename T, + typename T2 = Type, + hb_enable_if (std::is_copy_constructible<T2>::value)> + Type *push (T&& v) + { + if (unlikely (!alloc (length + 1))) + // If push failed to allocate then don't copy v, since this may cause + // the created copy to leak memory since we won't have stored a + // reference to it. + return &Crap (Type); + + /* Emplace. */ + length++; + Type *p = std::addressof (arrayZ[length - 1]); + return new (p) Type (std::forward<T> (v)); + } bool in_error () const { return allocated < 0; } template <typename T = Type, - hb_enable_if (std::is_trivially_copy_assignable<T>::value)> + hb_enable_if (hb_is_trivially_copy_assignable(T))> Type * realloc_vector (unsigned new_allocated) { return (Type *) hb_realloc (arrayZ, new_allocated * sizeof (Type)); } template <typename T = Type, - hb_enable_if (!std::is_trivially_copy_assignable<T>::value)> + hb_enable_if (!hb_is_trivially_copy_assignable(T))> Type * realloc_vector (unsigned new_allocated) { @@ -230,8 +253,7 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty } template <typename T = Type, - hb_enable_if (std::is_trivially_constructible<T>::value || - !std::is_default_constructible<T>::value)> + hb_enable_if (hb_is_trivially_constructible(T))> void grow_vector (unsigned size) { @@ -239,8 +261,7 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty length = size; } template <typename T = Type, - hb_enable_if (!std::is_trivially_constructible<T>::value && - std::is_default_constructible<T>::value)> + hb_enable_if (!hb_is_trivially_constructible(T))> void grow_vector (unsigned size) { @@ -252,14 +273,52 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty } template <typename T = Type, - hb_enable_if (std::is_trivially_destructible<T>::value)> + hb_enable_if (hb_is_trivially_copyable (T))> + void + copy_vector (const hb_vector_t &other) + { + length = other.length; + hb_memcpy ((void *) arrayZ, (const void *) other.arrayZ, length * item_size); + } + template <typename T = Type, + hb_enable_if (!hb_is_trivially_copyable (T) && + std::is_copy_constructible<T>::value)> + void + copy_vector (const hb_vector_t &other) + { + length = 0; + while (length < other.length) + { + length++; + new (std::addressof (arrayZ[length - 1])) Type (other.arrayZ[length - 1]); + } + } + template <typename T = Type, + hb_enable_if (!hb_is_trivially_copyable (T) && + !std::is_copy_constructible<T>::value && + std::is_default_constructible<T>::value && + std::is_copy_assignable<T>::value)> + void + copy_vector (const hb_vector_t &other) + { + length = 0; + while (length < other.length) + { + length++; + new (std::addressof (arrayZ[length - 1])) Type (); + arrayZ[length - 1] = other.arrayZ[length - 1]; + } + } + + template <typename T = Type, + hb_enable_if (hb_is_trivially_destructible(T))> void shrink_vector (unsigned size) { length = size; } template <typename T = Type, - hb_enable_if (!std::is_trivially_destructible<T>::value)> + hb_enable_if (!hb_is_trivially_destructible(T))> void shrink_vector (unsigned size) { @@ -271,7 +330,7 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty } template <typename T = Type, - hb_enable_if (std::is_trivially_copy_assignable<T>::value)> + hb_enable_if (hb_is_trivially_copy_assignable(T))> void shift_down_vector (unsigned i) { @@ -280,7 +339,7 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty (length - i) * sizeof (Type)); } template <typename T = Type, - hb_enable_if (!std::is_trivially_copy_assignable<T>::value)> + hb_enable_if (!hb_is_trivially_copy_assignable(T))> void shift_down_vector (unsigned i) { @@ -341,7 +400,7 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty Type pop () { if (!length) return Null (Type); - Type v = std::move (arrayZ[length - 1]); + Type v = arrayZ[length - 1]; arrayZ[length - 1].~Type (); length--; return v; @@ -351,8 +410,8 @@ struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty { if (unlikely (i >= length)) return; - arrayZ[i].~Type (); shift_down_vector (i + 1); + arrayZ[length - 1].~Type (); length--; } diff --git a/thirdparty/harfbuzz/src/hb-version.h b/thirdparty/harfbuzz/src/hb-version.h index 39fbde45c1..f036a12226 100644 --- a/thirdparty/harfbuzz/src/hb-version.h +++ b/thirdparty/harfbuzz/src/hb-version.h @@ -47,20 +47,20 @@ HB_BEGIN_DECLS * * The minor component of the library version available at compile-time. */ -#define HB_VERSION_MINOR 2 +#define HB_VERSION_MINOR 4 /** * HB_VERSION_MICRO: * * The micro component of the library version available at compile-time. */ -#define HB_VERSION_MICRO 0 +#define HB_VERSION_MICRO 1 /** * HB_VERSION_STRING: * * A string literal containing the library version available at compile-time. */ -#define HB_VERSION_STRING "4.2.0" +#define HB_VERSION_STRING "4.4.1" /** * HB_VERSION_ATLEAST: diff --git a/thirdparty/harfbuzz/src/hb.hh b/thirdparty/harfbuzz/src/hb.hh index b9f5f71415..8ec638a2b4 100644 --- a/thirdparty/harfbuzz/src/hb.hh +++ b/thirdparty/harfbuzz/src/hb.hh @@ -29,7 +29,6 @@ #ifndef HB_HH #define HB_HH - #ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC #ifdef _MSC_VER #pragma warning( disable: 4068 ) /* Unknown pragma */ @@ -65,6 +64,7 @@ #pragma GCC diagnostic error "-Wbitwise-instead-of-logical" #pragma GCC diagnostic error "-Wcast-align" #pragma GCC diagnostic error "-Wcast-function-type" +#pragma GCC diagnostic error "-Wcomma" #pragma GCC diagnostic error "-Wdelete-non-virtual-dtor" #pragma GCC diagnostic error "-Wembedded-directive" #pragma GCC diagnostic error "-Wextra-semi-stmt" @@ -183,7 +183,7 @@ #include <cassert> #include <cfloat> #include <climits> -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(_USE_MATH_DEFINES) # define _USE_MATH_DEFINES #endif #include <cmath> @@ -470,6 +470,7 @@ static_assert ((sizeof (hb_var_int_t) == 4), ""); /* Headers we include for everyone. Keep topologically sorted by dependency. * They express dependency amongst themselves, but no other file should include * them directly.*/ +#include "hb-cplusplus.hh" #include "hb-meta.hh" #include "hb-mutex.hh" #include "hb-number.hh" |